blob: 6b64c3fb21782d4ba0e89a6dd72ce2b42f301bc0 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005#include <sstream>
6
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009#include "src/accessors.h"
10#include "src/allocation-site-scopes.h"
11#include "src/api.h"
12#include "src/arguments.h"
13#include "src/base/bits.h"
14#include "src/bootstrapper.h"
15#include "src/code-stubs.h"
16#include "src/codegen.h"
17#include "src/cpu-profiler.h"
18#include "src/date.h"
19#include "src/debug.h"
20#include "src/deoptimizer.h"
21#include "src/elements.h"
22#include "src/execution.h"
23#include "src/field-index-inl.h"
24#include "src/field-index.h"
25#include "src/full-codegen.h"
26#include "src/heap/mark-compact.h"
27#include "src/heap/objects-visiting-inl.h"
28#include "src/hydrogen.h"
29#include "src/ic/ic.h"
30#include "src/isolate-inl.h"
31#include "src/log.h"
32#include "src/lookup.h"
33#include "src/macro-assembler.h"
34#include "src/objects-inl.h"
35#include "src/prototype.h"
36#include "src/safepoint-table.h"
37#include "src/string-search.h"
38#include "src/string-stream.h"
39#include "src/utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040
41#ifdef ENABLE_DISASSEMBLER
Ben Murdochb8a8cc12014-11-26 15:28:44 +000042#include "src/disasm.h"
43#include "src/disassembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#endif
45
Steve Blocka7e24c12009-10-30 11:49:00 +000046namespace v8 {
47namespace internal {
48
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049Handle<HeapType> Object::OptimalType(Isolate* isolate,
50 Representation representation) {
51 if (representation.IsNone()) return HeapType::None(isolate);
52 if (FLAG_track_field_types) {
53 if (representation.IsHeapObject() && IsHeapObject()) {
54 // We can track only JavaScript objects with stable maps.
55 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
56 if (map->is_stable() &&
57 map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
58 map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
59 return HeapType::Class(map, isolate);
60 }
61 }
62 }
63 return HeapType::Any(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010064}
65
Steve Blocka7e24c12009-10-30 11:49:00 +000066
Ben Murdochb8a8cc12014-11-26 15:28:44 +000067MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
68 Handle<Object> object,
69 Handle<Context> native_context) {
70 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
71 Handle<JSFunction> constructor;
72 if (object->IsNumber()) {
73 constructor = handle(native_context->number_function(), isolate);
74 } else if (object->IsBoolean()) {
75 constructor = handle(native_context->boolean_function(), isolate);
76 } else if (object->IsString()) {
77 constructor = handle(native_context->string_function(), isolate);
78 } else if (object->IsSymbol()) {
79 constructor = handle(native_context->symbol_function(), isolate);
80 } else {
81 return MaybeHandle<JSReceiver>();
John Reck59135872010-11-02 12:39:01 -070082 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000083 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
84 Handle<JSValue>::cast(result)->set_value(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +000085 return result;
86}
87
88
Ben Murdochb8a8cc12014-11-26 15:28:44 +000089bool Object::BooleanValue() {
90 if (IsBoolean()) return IsTrue();
91 if (IsSmi()) return Smi::cast(this)->value() != 0;
92 if (IsUndefined() || IsNull()) return false;
93 if (IsUndetectableObject()) return false; // Undetectable object is false.
94 if (IsString()) return String::cast(this)->length() != 0;
95 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
96 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000097}
98
99
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100bool Object::IsCallable() const {
101 const Object* fun = this;
102 while (fun->IsJSFunctionProxy()) {
103 fun = JSFunctionProxy::cast(fun)->call_trap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000104 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000105 return fun->IsJSFunction() ||
106 (fun->IsHeapObject() &&
107 HeapObject::cast(fun)->map()->has_instance_call_handler());
Steve Blocka7e24c12009-10-30 11:49:00 +0000108}
109
110
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000111MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
112 for (; it->IsFound(); it->Next()) {
113 switch (it->state()) {
114 case LookupIterator::NOT_FOUND:
115 case LookupIterator::TRANSITION:
116 UNREACHABLE();
117 case LookupIterator::JSPROXY:
118 return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
119 it->GetReceiver(), it->name());
120 case LookupIterator::INTERCEPTOR: {
121 MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithInterceptor(
122 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
123 if (!maybe_result.is_null()) return maybe_result;
124 if (it->isolate()->has_pending_exception()) return maybe_result;
125 break;
126 }
127 case LookupIterator::ACCESS_CHECK:
128 if (it->HasAccess(v8::ACCESS_GET)) break;
129 return JSObject::GetPropertyWithFailedAccessCheck(it);
130 case LookupIterator::ACCESSOR:
131 return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
132 it->GetHolder<JSObject>(),
133 it->GetAccessors());
134 case LookupIterator::DATA:
135 return it->GetDataValue();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100136 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000138 return it->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000139}
140
141
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000142Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object,
143 Handle<Name> key) {
144 LookupIterator it(object, key,
145 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
146 return GetDataProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +0000147}
148
149
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000150Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
151 for (; it->IsFound(); it->Next()) {
152 switch (it->state()) {
153 case LookupIterator::INTERCEPTOR:
154 case LookupIterator::NOT_FOUND:
155 case LookupIterator::TRANSITION:
156 UNREACHABLE();
157 case LookupIterator::ACCESS_CHECK:
158 if (it->HasAccess(v8::ACCESS_GET)) continue;
159 // Fall through.
160 case LookupIterator::JSPROXY:
161 it->NotFound();
162 return it->isolate()->factory()->undefined_value();
163 case LookupIterator::ACCESSOR:
164 // TODO(verwaest): For now this doesn't call into
165 // ExecutableAccessorInfo, since clients don't need it. Update once
166 // relevant.
167 it->NotFound();
168 return it->isolate()->factory()->undefined_value();
169 case LookupIterator::DATA:
170 return it->GetDataValue();
171 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000172 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000173 return it->isolate()->factory()->undefined_value();
174}
Steve Blocka7e24c12009-10-30 11:49:00 +0000175
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000176
177bool Object::ToInt32(int32_t* value) {
178 if (IsSmi()) {
179 *value = Smi::cast(this)->value();
180 return true;
181 }
182 if (IsHeapNumber()) {
183 double num = HeapNumber::cast(this)->value();
184 if (FastI2D(FastD2I(num)) == num) {
185 *value = FastD2I(num);
186 return true;
187 }
188 }
189 return false;
190}
191
192
193bool Object::ToUint32(uint32_t* value) {
194 if (IsSmi()) {
195 int num = Smi::cast(this)->value();
196 if (num >= 0) {
197 *value = static_cast<uint32_t>(num);
198 return true;
199 }
200 }
201 if (IsHeapNumber()) {
202 double num = HeapNumber::cast(this)->value();
203 if (num >= 0 && FastUI2D(FastD2UI(num)) == num) {
204 *value = FastD2UI(num);
205 return true;
206 }
207 }
208 return false;
209}
210
211
212bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
213 if (!object->IsHeapObject()) return false;
214 return IsTemplateFor(HeapObject::cast(object)->map());
215}
216
217
218bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
219 // There is a constraint on the object; check.
220 if (!map->IsJSObjectMap()) return false;
221 // Fetch the constructor function of the object.
222 Object* cons_obj = map->constructor();
223 if (!cons_obj->IsJSFunction()) return false;
224 JSFunction* fun = JSFunction::cast(cons_obj);
225 // Iterate through the chain of inheriting function templates to
226 // see if the required one occurs.
227 for (Object* type = fun->shared()->function_data();
228 type->IsFunctionTemplateInfo();
229 type = FunctionTemplateInfo::cast(type)->parent_template()) {
230 if (type == this) return true;
231 }
232 // Didn't find the required type in the inheritance chain.
233 return false;
234}
235
236
237template<typename To>
238static inline To* CheckedCast(void *from) {
239 uintptr_t temp = reinterpret_cast<uintptr_t>(from);
240 DCHECK(temp % sizeof(To) == 0);
241 return reinterpret_cast<To*>(temp);
242}
243
244
245static Handle<Object> PerformCompare(const BitmaskCompareDescriptor& descriptor,
246 char* ptr,
247 Isolate* isolate) {
248 uint32_t bitmask = descriptor.bitmask;
249 uint32_t compare_value = descriptor.compare_value;
250 uint32_t value;
251 switch (descriptor.size) {
252 case 1:
253 value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
254 compare_value &= 0xff;
255 bitmask &= 0xff;
256 break;
257 case 2:
258 value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
259 compare_value &= 0xffff;
260 bitmask &= 0xffff;
261 break;
262 case 4:
263 value = *CheckedCast<uint32_t>(ptr);
264 break;
265 default:
266 UNREACHABLE();
267 return isolate->factory()->undefined_value();
268 }
269 return isolate->factory()->ToBoolean(
270 (bitmask & value) == (bitmask & compare_value));
271}
272
273
274static Handle<Object> PerformCompare(const PointerCompareDescriptor& descriptor,
275 char* ptr,
276 Isolate* isolate) {
277 uintptr_t compare_value =
278 reinterpret_cast<uintptr_t>(descriptor.compare_value);
279 uintptr_t value = *CheckedCast<uintptr_t>(ptr);
280 return isolate->factory()->ToBoolean(compare_value == value);
281}
282
283
284static Handle<Object> GetPrimitiveValue(
285 const PrimitiveValueDescriptor& descriptor,
286 char* ptr,
287 Isolate* isolate) {
288 int32_t int32_value = 0;
289 switch (descriptor.data_type) {
290 case kDescriptorInt8Type:
291 int32_value = *CheckedCast<int8_t>(ptr);
292 break;
293 case kDescriptorUint8Type:
294 int32_value = *CheckedCast<uint8_t>(ptr);
295 break;
296 case kDescriptorInt16Type:
297 int32_value = *CheckedCast<int16_t>(ptr);
298 break;
299 case kDescriptorUint16Type:
300 int32_value = *CheckedCast<uint16_t>(ptr);
301 break;
302 case kDescriptorInt32Type:
303 int32_value = *CheckedCast<int32_t>(ptr);
304 break;
305 case kDescriptorUint32Type: {
306 uint32_t value = *CheckedCast<uint32_t>(ptr);
307 AllowHeapAllocation allow_gc;
308 return isolate->factory()->NewNumberFromUint(value);
309 }
310 case kDescriptorBoolType: {
311 uint8_t byte = *CheckedCast<uint8_t>(ptr);
312 return isolate->factory()->ToBoolean(
313 byte & (0x1 << descriptor.bool_offset));
314 }
315 case kDescriptorFloatType: {
316 float value = *CheckedCast<float>(ptr);
317 AllowHeapAllocation allow_gc;
318 return isolate->factory()->NewNumber(value);
319 }
320 case kDescriptorDoubleType: {
321 double value = *CheckedCast<double>(ptr);
322 AllowHeapAllocation allow_gc;
323 return isolate->factory()->NewNumber(value);
324 }
325 }
326 AllowHeapAllocation allow_gc;
327 return isolate->factory()->NewNumberFromInt(int32_value);
328}
329
330
331static Handle<Object> GetDeclaredAccessorProperty(
332 Handle<Object> receiver,
333 Handle<DeclaredAccessorInfo> info,
334 Isolate* isolate) {
335 DisallowHeapAllocation no_gc;
336 char* current = reinterpret_cast<char*>(*receiver);
337 DeclaredAccessorDescriptorIterator iterator(info->descriptor());
338 while (true) {
339 const DeclaredAccessorDescriptorData* data = iterator.Next();
340 switch (data->type) {
341 case kDescriptorReturnObject: {
342 DCHECK(iterator.Complete());
343 current = *CheckedCast<char*>(current);
344 return handle(*CheckedCast<Object*>(current), isolate);
345 }
346 case kDescriptorPointerDereference:
347 DCHECK(!iterator.Complete());
348 current = *reinterpret_cast<char**>(current);
349 break;
350 case kDescriptorPointerShift:
351 DCHECK(!iterator.Complete());
352 current += data->pointer_shift_descriptor.byte_offset;
353 break;
354 case kDescriptorObjectDereference: {
355 DCHECK(!iterator.Complete());
356 Object* object = CheckedCast<Object>(current);
357 int field = data->object_dereference_descriptor.internal_field;
358 Object* smi = JSObject::cast(object)->GetInternalField(field);
359 DCHECK(smi->IsSmi());
360 current = reinterpret_cast<char*>(smi);
361 break;
362 }
363 case kDescriptorBitmaskCompare:
364 DCHECK(iterator.Complete());
365 return PerformCompare(data->bitmask_compare_descriptor,
366 current,
367 isolate);
368 case kDescriptorPointerCompare:
369 DCHECK(iterator.Complete());
370 return PerformCompare(data->pointer_compare_descriptor,
371 current,
372 isolate);
373 case kDescriptorPrimitiveValue:
374 DCHECK(iterator.Complete());
375 return GetPrimitiveValue(data->primitive_value_descriptor,
376 current,
377 isolate);
378 }
379 }
380 UNREACHABLE();
381 return isolate->factory()->undefined_value();
382}
383
384
385Handle<FixedArray> JSObject::EnsureWritableFastElements(
386 Handle<JSObject> object) {
387 DCHECK(object->HasFastSmiOrObjectElements());
388 Isolate* isolate = object->GetIsolate();
389 Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
390 if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
391 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
392 elems, isolate->factory()->fixed_array_map());
393 object->set_elements(*writable_elems);
394 isolate->counters()->cow_arrays_converted()->Increment();
395 return writable_elems;
396}
397
398
399MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy,
400 Handle<Object> receiver,
401 Handle<Name> name) {
402 Isolate* isolate = proxy->GetIsolate();
403
404 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
405 if (name->IsSymbol()) return isolate->factory()->undefined_value();
406
407 Handle<Object> args[] = { receiver, name };
408 return CallTrap(
409 proxy, "get", isolate->derived_get_trap(), arraysize(args), args);
410}
411
412
413MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
414 Handle<Name> name,
415 Handle<JSObject> holder,
416 Handle<Object> structure) {
417 Isolate* isolate = name->GetIsolate();
418 DCHECK(!structure->IsForeign());
Steve Blocka7e24c12009-10-30 11:49:00 +0000419 // api style callbacks.
420 if (structure->IsAccessorInfo()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000421 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
422 if (!info->IsCompatibleReceiver(*receiver)) {
423 Handle<Object> args[2] = { name, receiver };
424 THROW_NEW_ERROR(isolate,
425 NewTypeError("incompatible_method_receiver",
426 HandleVector(args, arraysize(args))),
427 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000428 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000429 if (structure->IsDeclaredAccessorInfo()) {
430 return GetDeclaredAccessorProperty(
431 receiver,
432 Handle<DeclaredAccessorInfo>::cast(structure),
433 isolate);
434 }
435
436 Handle<ExecutableAccessorInfo> data =
437 Handle<ExecutableAccessorInfo>::cast(structure);
438 v8::AccessorNameGetterCallback call_fun =
439 v8::ToCData<v8::AccessorNameGetterCallback>(data->getter());
440 if (call_fun == NULL) return isolate->factory()->undefined_value();
441
442 LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
443 PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder);
444 v8::Handle<v8::Value> result =
445 args.Call(call_fun, v8::Utils::ToLocal(name));
446 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
Steve Block44f0eee2011-05-26 01:26:41 +0100447 if (result.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 return isolate->factory()->undefined_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100449 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000450 Handle<Object> return_value = v8::Utils::OpenHandle(*result);
451 return_value->VerifyApiCallResultType();
452 // Rebox handle before return.
453 return handle(*return_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000454 }
455
456 // __defineGetter__ callback
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000457 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
458 isolate);
459 if (getter->IsSpecFunction()) {
460 // TODO(rossberg): nicer would be to cast to some JSCallable here...
461 return Object::GetPropertyWithDefinedGetter(
462 receiver, Handle<JSReceiver>::cast(getter));
463 }
464 // Getter is not a function.
465 return isolate->factory()->undefined_value();
466}
467
468
469bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
470 Handle<AccessorInfo> info,
471 Handle<HeapType> type) {
472 if (!info->HasExpectedReceiverType()) return true;
473 Handle<Map> map = IC::TypeToMap(*type, isolate);
474 if (!map->IsJSObjectMap()) return false;
475 return FunctionTemplateInfo::cast(info->expected_receiver_type())
476 ->IsTemplateFor(*map);
477}
478
479
480MaybeHandle<Object> Object::SetPropertyWithAccessor(
481 Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
482 Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) {
483 Isolate* isolate = name->GetIsolate();
484
485 // We should never get here to initialize a const with the hole
486 // value since a const declaration would conflict with the setter.
487 DCHECK(!structure->IsForeign());
488 if (structure->IsExecutableAccessorInfo()) {
489 // Don't call executable accessor setters with non-JSObject receivers.
490 if (!receiver->IsJSObject()) return value;
491 // api style callbacks
492 ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure);
493 if (!info->IsCompatibleReceiver(*receiver)) {
494 Handle<Object> args[2] = { name, receiver };
495 THROW_NEW_ERROR(isolate,
496 NewTypeError("incompatible_method_receiver",
497 HandleVector(args, arraysize(args))),
498 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000499 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000500 Object* call_obj = info->setter();
501 v8::AccessorNameSetterCallback call_fun =
502 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj);
503 if (call_fun == NULL) return value;
504 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
505 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
506 args.Call(call_fun,
507 v8::Utils::ToLocal(name),
508 v8::Utils::ToLocal(value));
509 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
510 return value;
511 }
512
513 if (structure->IsAccessorPair()) {
514 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
515 if (setter->IsSpecFunction()) {
516 // TODO(rossberg): nicer would be to cast to some JSCallable here...
517 return SetPropertyWithDefinedSetter(
518 receiver, Handle<JSReceiver>::cast(setter), value);
519 } else {
520 if (strict_mode == SLOPPY) return value;
521 Handle<Object> args[2] = { name, holder };
522 THROW_NEW_ERROR(
523 isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
524 Object);
525 }
526 }
527
528 // TODO(dcarney): Handle correctly.
529 if (structure->IsDeclaredAccessorInfo()) {
530 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000531 }
532
533 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 return MaybeHandle<Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +0000535}
536
537
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
539 Handle<Object> receiver,
540 Handle<JSReceiver> getter) {
541 Isolate* isolate = getter->GetIsolate();
542 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000543 // Handle stepping into a getter if step into is active.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100544 // TODO(rossberg): should this apply to getters that are function proxies?
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400545 if (debug->is_active()) {
546 debug->HandleStepIn(getter, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100548
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549 return Execution::Call(isolate, getter, receiver, 0, NULL, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000550}
551
552
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
554 Handle<Object> receiver,
555 Handle<JSReceiver> setter,
556 Handle<Object> value) {
557 Isolate* isolate = setter->GetIsolate();
558
559 Debug* debug = isolate->debug();
560 // Handle stepping into a setter if step into is active.
561 // TODO(rossberg): should this apply to getters that are function proxies?
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400562 if (debug->is_active()) {
563 debug->HandleStepIn(setter, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000564 }
565
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566 Handle<Object> argv[] = { value };
567 RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver,
568 arraysize(argv), argv, true),
569 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 return value;
571}
572
573
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000574static bool FindAllCanReadHolder(LookupIterator* it) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400575 // Skip current iteration, it's in state ACCESS_CHECK or INTERCEPTOR, both of
576 // which have already been checked.
577 DCHECK(it->state() == LookupIterator::ACCESS_CHECK ||
578 it->state() == LookupIterator::INTERCEPTOR);
579 for (it->Next(); it->IsFound(); it->Next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000580 if (it->state() == LookupIterator::ACCESSOR) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400581 auto accessors = it->GetAccessors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582 if (accessors->IsAccessorInfo()) {
583 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
584 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400585 } else if (it->state() == LookupIterator::INTERCEPTOR) {
586 auto holder = it->GetHolder<JSObject>();
587 if (holder->GetNamedInterceptor()->all_can_read()) return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000588 }
589 }
590 return false;
591}
592
593
594MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
595 LookupIterator* it) {
596 Handle<JSObject> checked = it->GetHolder<JSObject>();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400597 while (FindAllCanReadHolder(it)) {
598 if (it->state() == LookupIterator::ACCESSOR) {
599 return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
600 it->GetHolder<JSObject>(),
601 it->GetAccessors());
602 }
603 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
604 auto receiver = Handle<JSObject>::cast(it->GetReceiver());
605 auto result = GetPropertyWithInterceptor(it->GetHolder<JSObject>(),
606 receiver, it->name());
607 if (it->isolate()->has_scheduled_exception()) break;
608 if (!result.is_null()) return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000609 }
610 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
611 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
612 return it->factory()->undefined_value();
613}
614
615
616Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
617 LookupIterator* it) {
618 Handle<JSObject> checked = it->GetHolder<JSObject>();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400619 while (FindAllCanReadHolder(it)) {
620 if (it->state() == LookupIterator::ACCESSOR) {
621 return maybe(it->property_details().attributes());
622 }
623 DCHECK_EQ(LookupIterator::INTERCEPTOR, it->state());
624 auto result = GetPropertyAttributesWithInterceptor(
625 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
626 if (it->isolate()->has_scheduled_exception()) break;
627 if (result.has_value && result.value != ABSENT) return result;
628 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000629 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
630 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
631 Maybe<PropertyAttributes>());
632 return maybe(ABSENT);
633}
634
635
636static bool FindAllCanWriteHolder(LookupIterator* it) {
637 for (; it->IsFound(); it->Next()) {
638 if (it->state() == LookupIterator::ACCESSOR) {
639 Handle<Object> accessors = it->GetAccessors();
640 if (accessors->IsAccessorInfo()) {
641 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
642 }
643 }
644 }
645 return false;
646}
647
648
649MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
650 LookupIterator* it, Handle<Object> value, StrictMode strict_mode) {
651 Handle<JSObject> checked = it->GetHolder<JSObject>();
652 if (FindAllCanWriteHolder(it)) {
653 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
654 it->GetHolder<JSObject>(),
655 it->GetAccessors(), strict_mode);
656 }
657
658 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET);
659 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
660 return value;
661}
662
663
664void JSObject::SetNormalizedProperty(Handle<JSObject> object,
665 Handle<Name> name,
666 Handle<Object> value,
667 PropertyDetails details) {
668 DCHECK(!object->HasFastProperties());
669 Handle<NameDictionary> property_dictionary(object->property_dictionary());
670
671 if (!name->IsUniqueName()) {
672 name = object->GetIsolate()->factory()->InternalizeString(
673 Handle<String>::cast(name));
674 }
675
676 int entry = property_dictionary->FindEntry(name);
677 if (entry == NameDictionary::kNotFound) {
678 Handle<Object> store_value = value;
679 if (object->IsGlobalObject()) {
680 store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
681 }
682
683 property_dictionary = NameDictionary::Add(
684 property_dictionary, name, store_value, details);
685 object->set_properties(*property_dictionary);
686 return;
687 }
688
689 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
690 int enumeration_index;
691 // Preserve the enumeration index unless the property was deleted.
692 if (original_details.IsDeleted()) {
693 enumeration_index = property_dictionary->NextEnumerationIndex();
694 property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000695 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000696 enumeration_index = original_details.dictionary_index();
697 DCHECK(enumeration_index > 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000698 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000699
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000700 details = PropertyDetails(
701 details.attributes(), details.type(), enumeration_index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000702
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000703 if (object->IsGlobalObject()) {
704 Handle<PropertyCell> cell(
705 PropertyCell::cast(property_dictionary->ValueAt(entry)));
706 PropertyCell::SetValueInferType(cell, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000707 // Please note we have to update the property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000708 property_dictionary->DetailsAtPut(entry, details);
Steve Blocka7e24c12009-10-30 11:49:00 +0000709 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000710 property_dictionary->SetEntry(entry, name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +0000711 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000712}
713
714
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000715Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
716 Handle<Name> name,
717 DeleteMode mode) {
718 DCHECK(!object->HasFastProperties());
719 Isolate* isolate = object->GetIsolate();
720 Handle<NameDictionary> dictionary(object->property_dictionary());
Steve Blocka7e24c12009-10-30 11:49:00 +0000721 int entry = dictionary->FindEntry(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000722 if (entry != NameDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 // If we have a global object set the cell to the hole.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 if (object->IsGlobalObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000725 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000726 if (!details.IsConfigurable()) {
727 if (mode != FORCE_DELETION) return isolate->factory()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 // When forced to delete global properties, we have to make a
729 // map change to invalidate any ICs that think they can load
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000730 // from the non-configurable cell without checking if it contains
Steve Blocka7e24c12009-10-30 11:49:00 +0000731 // the hole value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
733 DCHECK(new_map->is_dictionary_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400734#if TRACE_MAPS
735 if (FLAG_trace_maps) {
736 PrintF("[TraceMaps: GlobalDeleteNormalized from= %p to= %p ]\n",
737 reinterpret_cast<void*>(object->map()),
738 reinterpret_cast<void*>(*new_map));
739 }
740#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000741 JSObject::MigrateToMap(object, new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
744 Handle<Object> value = isolate->factory()->the_hole_value();
745 PropertyCell::SetValueInferType(cell, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000746 dictionary->DetailsAtPut(entry, details.AsDeleted());
747 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000748 Handle<Object> deleted(
749 NameDictionary::DeleteProperty(dictionary, entry, mode));
750 if (*deleted == isolate->heap()->true_value()) {
751 Handle<NameDictionary> new_properties =
752 NameDictionary::Shrink(dictionary, name);
753 object->set_properties(*new_properties);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000754 }
755 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000756 }
757 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000758 return isolate->factory()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000759}
760
761
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400762static MaybeHandle<JSObject> FindIndexedAllCanReadHolder(
763 Isolate* isolate, Handle<JSObject> js_object,
764 PrototypeIterator::WhereToStart where_to_start) {
765 for (PrototypeIterator iter(isolate, js_object, where_to_start);
766 !iter.IsAtEnd(); iter.Advance()) {
767 auto curr = PrototypeIterator::GetCurrent(iter);
768 if (!curr->IsJSObject()) break;
769 auto obj = Handle<JSObject>::cast(curr);
770 if (!obj->HasIndexedInterceptor()) continue;
771 if (obj->GetIndexedInterceptor()->all_can_read()) return obj;
772 }
773 return MaybeHandle<JSObject>();
774}
775
776
777MaybeHandle<Object> JSObject::GetElementWithFailedAccessCheck(
778 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
779 uint32_t index) {
780 Handle<JSObject> holder = object;
781 PrototypeIterator::WhereToStart where_to_start =
782 PrototypeIterator::START_AT_RECEIVER;
783 while (true) {
784 auto all_can_read_holder =
785 FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
786 if (!all_can_read_holder.ToHandle(&holder)) break;
787 auto result =
788 JSObject::GetElementWithInterceptor(holder, receiver, index, false);
789 if (isolate->has_scheduled_exception()) break;
790 if (!result.is_null()) return result;
791 where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
792 }
793 isolate->ReportFailedAccessCheck(object, v8::ACCESS_GET);
794 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
795 return isolate->factory()->undefined_value();
796}
797
798
799Maybe<PropertyAttributes> JSObject::GetElementAttributesWithFailedAccessCheck(
800 Isolate* isolate, Handle<JSObject> object, Handle<Object> receiver,
801 uint32_t index) {
802 Handle<JSObject> holder = object;
803 PrototypeIterator::WhereToStart where_to_start =
804 PrototypeIterator::START_AT_RECEIVER;
805 while (true) {
806 auto all_can_read_holder =
807 FindIndexedAllCanReadHolder(isolate, holder, where_to_start);
808 if (!all_can_read_holder.ToHandle(&holder)) break;
809 auto result =
810 JSObject::GetElementAttributeFromInterceptor(object, receiver, index);
811 if (isolate->has_scheduled_exception()) break;
812 if (result.has_value && result.value != ABSENT) return result;
813 where_to_start = PrototypeIterator::START_AT_PROTOTYPE;
814 }
815 isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
816 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
817 return maybe(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +0000818}
819
820
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000821MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
822 Handle<Object> object,
823 Handle<Object> receiver,
824 uint32_t index) {
825 if (object->IsUndefined()) {
826 // TODO(verwaest): Why is this check here?
827 UNREACHABLE();
828 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 }
830
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000831 // Iterate up the prototype chain until an element is found or the null
832 // prototype is encountered.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000833 for (PrototypeIterator iter(isolate, object,
834 object->IsJSProxy() || object->IsJSObject()
835 ? PrototypeIterator::START_AT_RECEIVER
836 : PrototypeIterator::START_AT_PROTOTYPE);
837 !iter.IsAtEnd(); iter.Advance()) {
838 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
839 return JSProxy::GetElementWithHandler(
840 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
841 index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000842 }
843
844 // Inline the case for JSObjects. Doing so significantly improves the
845 // performance of fetching elements where checking the prototype chain is
846 // necessary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000847 Handle<JSObject> js_object =
848 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000849
850 // Check access rights if needed.
851 if (js_object->IsAccessCheckNeeded()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000852 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400853 return JSObject::GetElementWithFailedAccessCheck(isolate, js_object,
854 receiver, index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000855 }
856 }
857
858 if (js_object->HasIndexedInterceptor()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400859 return JSObject::GetElementWithInterceptor(js_object, receiver, index,
860 true);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000861 }
862
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000863 if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
864 Handle<Object> result;
865 ASSIGN_RETURN_ON_EXCEPTION(
866 isolate, result,
867 js_object->GetElementsAccessor()->Get(receiver, js_object, index),
868 Object);
869 if (!result->IsTheHole()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100870 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100871 }
872
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000873 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000874}
875
876
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400877MaybeHandle<Object> Object::SetElementWithReceiver(
878 Isolate* isolate, Handle<Object> object, Handle<Object> receiver,
879 uint32_t index, Handle<Object> value, StrictMode strict_mode) {
880 // Iterate up the prototype chain until an element is found or the null
881 // prototype is encountered.
882 bool done = false;
883 for (PrototypeIterator iter(isolate, object,
884 object->IsJSProxy() || object->IsJSObject()
885 ? PrototypeIterator::START_AT_RECEIVER
886 : PrototypeIterator::START_AT_PROTOTYPE);
887 !iter.IsAtEnd() && !done; iter.Advance()) {
888 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
889 // TODO(dslomov): implement.
890 isolate->ThrowIllegalOperation();
891 return MaybeHandle<Object>();
892 }
893
894 Handle<JSObject> js_object =
895 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
896
897 // Check access rights if needed.
898 if (js_object->IsAccessCheckNeeded()) {
899 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_SET)) {
900 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_SET);
901 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
902 return isolate->factory()->undefined_value();
903 }
904 }
905
906 if (js_object->HasIndexedInterceptor()) {
907 Maybe<PropertyAttributes> from_interceptor =
908 JSObject::GetElementAttributeFromInterceptor(js_object, receiver,
909 index);
910 if (!from_interceptor.has_value) return MaybeHandle<Object>();
911 if ((from_interceptor.value & READ_ONLY) != 0) {
912 return WriteToReadOnlyElement(isolate, receiver, index, value,
913 strict_mode);
914 }
915 done = from_interceptor.value != ABSENT;
916 }
917
918 if (!done &&
919 js_object->elements() != isolate->heap()->empty_fixed_array()) {
920 ElementsAccessor* accessor = js_object->GetElementsAccessor();
921 PropertyAttributes attrs =
922 accessor->GetAttributes(receiver, js_object, index);
923 if ((attrs & READ_ONLY) != 0) {
924 return WriteToReadOnlyElement(isolate, receiver, index, value,
925 strict_mode);
926 }
927 Handle<AccessorPair> accessor_pair;
928 if (accessor->GetAccessorPair(receiver, js_object, index)
929 .ToHandle(&accessor_pair)) {
930 return JSObject::SetElementWithCallback(receiver, accessor_pair, index,
931 value, js_object, strict_mode);
932 } else {
933 done = attrs != ABSENT;
934 }
935 }
936 }
937
938 if (!receiver->IsJSObject()) {
939 return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
940 }
941 Handle<JSObject> target = Handle<JSObject>::cast(receiver);
942 ElementsAccessor* accessor = target->GetElementsAccessor();
943 PropertyAttributes attrs = accessor->GetAttributes(receiver, target, index);
944 if ((attrs & READ_ONLY) != 0) {
945 return WriteToReadOnlyElement(isolate, receiver, index, value, strict_mode);
946 }
947 PropertyAttributes new_attrs = attrs != ABSENT ? attrs : NONE;
948 return JSObject::SetElement(target, index, value, new_attrs, strict_mode,
949 false);
950}
951
952
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000953Map* Object::GetRootMap(Isolate* isolate) {
954 DisallowHeapAllocation no_alloc;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100955 if (IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956 Context* context = isolate->context()->native_context();
957 return context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100958 }
959
960 HeapObject* heap_object = HeapObject::cast(this);
961
Ben Murdoch257744e2011-11-30 15:57:28 +0000962 // The object is either a number, a string, a boolean,
963 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000964 if (heap_object->IsJSReceiver()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000965 return heap_object->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100966 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000967 Context* context = isolate->context()->native_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000968
Ben Murdoch8b112d22011-06-08 16:22:53 +0100969 if (heap_object->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000970 return context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100971 }
972 if (heap_object->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000973 return context->string_function()->initial_map();
974 }
975 if (heap_object->IsSymbol()) {
976 return context->symbol_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100977 }
978 if (heap_object->IsBoolean()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000979 return context->boolean_function()->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000981 return isolate->heap()->null_value()->map();
Steve Blocka7e24c12009-10-30 11:49:00 +0000982}
983
984
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000985Object* Object::GetHash() {
986 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100987 // a real JS object, or a Harmony proxy.
988 if (IsNumber()) {
989 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
990 return Smi::FromInt(hash & Smi::kMaxValue);
991 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 if (IsName()) {
993 uint32_t hash = Name::cast(this)->Hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100994 return Smi::FromInt(hash);
995 }
996 if (IsOddball()) {
997 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
998 return Smi::FromInt(hash);
999 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001000
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001001 DCHECK(IsJSReceiver());
1002 return JSReceiver::cast(this)->GetIdentityHash();
1003}
1004
1005
1006Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
1007 Handle<Object> hash(object->GetHash(), isolate);
1008 if (hash->IsSmi()) return Handle<Smi>::cast(hash);
1009
1010 DCHECK(object->IsJSReceiver());
1011 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001012}
1013
1014
1015bool Object::SameValue(Object* other) {
1016 if (other == this) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001017
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001018 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001019 // a real JS object, or a Harmony proxy.
1020 if (IsNumber() && other->IsNumber()) {
1021 double this_value = Number();
1022 double other_value = other->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001023 bool equal = this_value == other_value;
1024 // SameValue(NaN, NaN) is true.
1025 if (!equal) return std::isnan(this_value) && std::isnan(other_value);
1026 // SameValue(0.0, -0.0) is false.
1027 return (this_value != 0) || ((1 / this_value) == (1 / other_value));
1028 }
1029 if (IsString() && other->IsString()) {
1030 return String::cast(this)->Equals(String::cast(other));
1031 }
1032 return false;
1033}
1034
1035
1036bool Object::SameValueZero(Object* other) {
1037 if (other == this) return true;
1038
1039 // The object is either a number, a name, an odd-ball,
1040 // a real JS object, or a Harmony proxy.
1041 if (IsNumber() && other->IsNumber()) {
1042 double this_value = Number();
1043 double other_value = other->Number();
1044 // +0 == -0 is true
1045 return this_value == other_value
1046 || (std::isnan(this_value) && std::isnan(other_value));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001047 }
1048 if (IsString() && other->IsString()) {
1049 return String::cast(this)->Equals(String::cast(other));
1050 }
1051 return false;
1052}
1053
1054
Ben Murdochb0fe1622011-05-05 13:52:32 +01001055void Object::ShortPrint(FILE* out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001056 OFStream os(out);
1057 os << Brief(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001058}
1059
1060
1061void Object::ShortPrint(StringStream* accumulator) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001062 std::ostringstream os;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001063 os << Brief(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001064 accumulator->Add(os.str().c_str());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001065}
1066
1067
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001068void Object::ShortPrint(std::ostream& os) { os << Brief(this); }
1069
1070
1071std::ostream& operator<<(std::ostream& os, const Brief& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 if (v.value->IsSmi()) {
1073 Smi::cast(v.value)->SmiPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001074 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
1076 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
1077 obj->HeapObjectShortPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00001078 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001079 return os;
Steve Blocka7e24c12009-10-30 11:49:00 +00001080}
1081
1082
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001083void Smi::SmiPrint(std::ostream& os) const { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001084 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001085}
1086
1087
Steve Blocka7e24c12009-10-30 11:49:00 +00001088// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1089// English? Returns false for non-ASCII or words that don't start with
1090// a capital letter. The a/an rule follows pronunciation in English.
1091// We don't use the BBC's overcorrect "an historic occasion" though if
1092// you speak a dialect you may well say "an 'istoric occasion".
1093static bool AnWord(String* str) {
1094 if (str->length() == 0) return false; // A nothing.
1095 int c0 = str->Get(0);
1096 int c1 = str->length() > 1 ? str->Get(1) : 0;
1097 if (c0 == 'U') {
1098 if (c1 > 'Z') {
1099 return true; // An Umpire, but a UTF8String, a U.
1100 }
1101 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
1102 return true; // An Ape, an ABCBook.
1103 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1104 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1105 c0 == 'S' || c0 == 'X')) {
1106 return true; // An MP3File, an M.
1107 }
1108 return false;
1109}
1110
1111
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001112Handle<String> String::SlowFlatten(Handle<ConsString> cons,
1113 PretenureFlag pretenure) {
1114 DCHECK(AllowHeapAllocation::IsAllowed());
1115 DCHECK(cons->second()->length() != 0);
1116 Isolate* isolate = cons->GetIsolate();
1117 int length = cons->length();
1118 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
1119 : TENURED;
1120 Handle<SeqString> result;
1121 if (cons->IsOneByteRepresentation()) {
1122 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
1123 length, tenure).ToHandleChecked();
1124 DisallowHeapAllocation no_gc;
1125 WriteToFlat(*cons, flat->GetChars(), 0, length);
1126 result = flat;
1127 } else {
1128 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
1129 length, tenure).ToHandleChecked();
1130 DisallowHeapAllocation no_gc;
1131 WriteToFlat(*cons, flat->GetChars(), 0, length);
1132 result = flat;
Steve Blocka7e24c12009-10-30 11:49:00 +00001133 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001134 cons->set_first(*result);
1135 cons->set_second(isolate->heap()->empty_string());
1136 DCHECK(result->IsFlat());
1137 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001138}
1139
1140
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001141
Steve Blocka7e24c12009-10-30 11:49:00 +00001142bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +01001143 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001144 // prohibited by the API.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001145 DCHECK(!this->IsExternalString());
1146#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001147 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001148 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001149 DCHECK(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +01001150 ScopedVector<uc16> smart_chars(this->length());
1151 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001152 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001154 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001155 }
1156#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 // Abort if size does not allow in-place conversion.
1159 if (size < ExternalString::kShortSize) return false;
1160 Heap* heap = GetHeap();
1161 bool is_one_byte = this->IsOneByteRepresentation();
1162 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001163
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001164 // Morph the string to an external string by replacing the map and
1165 // reinitializing the fields. This won't work if the space the existing
1166 // string occupies is too small for a regular external string.
1167 // Instead, we resort to a short external string instead, omitting
1168 // the field caching the address of the backing store. When we encounter
1169 // short external strings in generated code, we need to bailout to runtime.
1170 Map* new_map;
1171 if (size < ExternalString::kSize) {
1172 new_map = is_internalized
1173 ? (is_one_byte
1174 ? heap->short_external_internalized_string_with_one_byte_data_map()
1175 : heap->short_external_internalized_string_map())
1176 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
1177 : heap->short_external_string_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001178 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001179 new_map = is_internalized
1180 ? (is_one_byte
1181 ? heap->external_internalized_string_with_one_byte_data_map()
1182 : heap->external_internalized_string_map())
1183 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
1184 : heap->external_string_map());
Ben Murdoch85b71792012-04-11 18:30:58 +01001185 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001186
1187 // Byte size of the external String object.
1188 int new_size = this->SizeFromMap(new_map);
1189 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1190
1191 // We are storing the new map using release store after creating a filler for
1192 // the left-over space to avoid races with the sweeper thread.
1193 this->synchronized_set_map(new_map);
1194
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001195 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1196 self->set_resource(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001197 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001198
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 return true;
1201}
1202
1203
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001204bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
1205 // Externalizing twice leaks the external resource, so it's
1206 // prohibited by the API.
1207 DCHECK(!this->IsExternalString());
1208#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001209 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001210 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001211 DCHECK(static_cast<size_t>(this->length()) == resource->length());
1212 if (this->IsTwoByteRepresentation()) {
1213 ScopedVector<uint16_t> smart_chars(this->length());
1214 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1215 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
1216 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001217 ScopedVector<char> smart_chars(this->length());
1218 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001220 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001221 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001222 }
1223#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001224 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001225 // Abort if size does not allow in-place conversion.
1226 if (size < ExternalString::kShortSize) return false;
1227 Heap* heap = GetHeap();
1228 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001229
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230 // Morph the string to an external string by replacing the map and
1231 // reinitializing the fields. This won't work if the space the existing
1232 // string occupies is too small for a regular external string.
1233 // Instead, we resort to a short external string instead, omitting
1234 // the field caching the address of the backing store. When we encounter
1235 // short external strings in generated code, we need to bailout to runtime.
1236 Map* new_map;
1237 if (size < ExternalString::kSize) {
1238 new_map = is_internalized
1239 ? heap->short_external_one_byte_internalized_string_map()
1240 : heap->short_external_one_byte_string_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001241 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001242 new_map = is_internalized
1243 ? heap->external_one_byte_internalized_string_map()
1244 : heap->external_one_byte_string_map();
Ben Murdoch85b71792012-04-11 18:30:58 +01001245 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001246
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247 // Byte size of the external String object.
1248 int new_size = this->SizeFromMap(new_map);
Steve Block44f0eee2011-05-26 01:26:41 +01001249 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001250
1251 // We are storing the new map using release store after creating a filler for
1252 // the left-over space to avoid races with the sweeper thread.
1253 this->synchronized_set_map(new_map);
1254
1255 ExternalOneByteString* self = ExternalOneByteString::cast(this);
1256 self->set_resource(resource);
1257 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
1258
1259 heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 return true;
1261}
1262
1263
1264void String::StringShortPrint(StringStream* accumulator) {
1265 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001266 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001267 accumulator->Add("<Very long string[%u]>", len);
1268 return;
1269 }
1270
1271 if (!LooksValid()) {
1272 accumulator->Add("<Invalid String>");
1273 return;
1274 }
1275
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001276 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001277
1278 bool truncated = false;
1279 if (len > kMaxShortPrintLength) {
1280 len = kMaxShortPrintLength;
1281 truncated = true;
1282 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283 bool one_byte = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001284 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001285 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001286
1287 if (c < 32 || c >= 127) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 one_byte = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 }
1290 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001291 stream.Reset(this);
1292 if (one_byte) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001293 accumulator->Add("<String[%u]: ", length());
1294 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001295 accumulator->Put(static_cast<char>(stream.GetNext()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001296 }
1297 accumulator->Put('>');
1298 } else {
1299 // Backslash indicates that the string contains control
1300 // characters and that backslashes are therefore escaped.
1301 accumulator->Add("<String[%u]\\: ", length());
1302 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001303 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 if (c == '\n') {
1305 accumulator->Add("\\n");
1306 } else if (c == '\r') {
1307 accumulator->Add("\\r");
1308 } else if (c == '\\') {
1309 accumulator->Add("\\\\");
1310 } else if (c < 32 || c > 126) {
1311 accumulator->Add("\\x%02x", c);
1312 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001313 accumulator->Put(static_cast<char>(c));
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 }
1315 }
1316 if (truncated) {
1317 accumulator->Put('.');
1318 accumulator->Put('.');
1319 accumulator->Put('.');
1320 }
1321 accumulator->Put('>');
1322 }
1323 return;
1324}
1325
1326
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001327void String::PrintUC16(std::ostream& os, int start, int end) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 if (end < 0) end = length();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001329 StringCharacterStream stream(this, start);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001330 for (int i = start; i < end && stream.HasMore(); i++) {
1331 os << AsUC16(stream.GetNext());
1332 }
1333}
1334
1335
Steve Blocka7e24c12009-10-30 11:49:00 +00001336void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1337 switch (map()->instance_type()) {
1338 case JS_ARRAY_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339 double length = JSArray::cast(this)->length()->IsUndefined()
1340 ? 0
1341 : JSArray::cast(this)->length()->Number();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001342 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +00001343 break;
1344 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001345 case JS_WEAK_MAP_TYPE: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001346 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001347 break;
1348 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 case JS_WEAK_SET_TYPE: {
1350 accumulator->Add("<JS WeakSet>");
1351 break;
1352 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001353 case JS_REGEXP_TYPE: {
1354 accumulator->Add("<JS RegExp>");
1355 break;
1356 }
1357 case JS_FUNCTION_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001358 JSFunction* function = JSFunction::cast(this);
1359 Object* fun_name = function->shared()->DebugName();
Steve Blocka7e24c12009-10-30 11:49:00 +00001360 bool printed = false;
1361 if (fun_name->IsString()) {
1362 String* str = String::cast(fun_name);
1363 if (str->length() > 0) {
1364 accumulator->Add("<JS Function ");
1365 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001366 printed = true;
1367 }
1368 }
1369 if (!printed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001370 accumulator->Add("<JS Function");
Steve Blocka7e24c12009-10-30 11:49:00 +00001371 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001372 accumulator->Add(" (SharedFunctionInfo %p)",
1373 reinterpret_cast<void*>(function->shared()));
1374 accumulator->Put('>');
1375 break;
1376 }
1377 case JS_GENERATOR_OBJECT_TYPE: {
1378 accumulator->Add("<JS Generator>");
1379 break;
1380 }
1381 case JS_MODULE_TYPE: {
1382 accumulator->Add("<JS Module>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001383 break;
1384 }
1385 // All other JSObjects are rather similar to each other (JSObject,
1386 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1387 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001388 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001389 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001390 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 bool printed = false;
1392 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001393 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001394 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1395 } else {
1396 bool global_object = IsJSGlobalProxy();
1397 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001398 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1400 } else {
1401 Object* constructor_name =
1402 JSFunction::cast(constructor)->shared()->name();
1403 if (constructor_name->IsString()) {
1404 String* str = String::cast(constructor_name);
1405 if (str->length() > 0) {
1406 bool vowel = AnWord(str);
1407 accumulator->Add("<%sa%s ",
1408 global_object ? "Global Object: " : "",
1409 vowel ? "n" : "");
1410 accumulator->Put(str);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001411 accumulator->Add(" with %smap %p",
1412 map_of_this->is_deprecated() ? "deprecated " : "",
1413 map_of_this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001414 printed = true;
1415 }
1416 }
1417 }
1418 }
1419 if (!printed) {
1420 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1421 }
1422 }
1423 if (IsJSValue()) {
1424 accumulator->Add(" value = ");
1425 JSValue::cast(this)->value()->ShortPrint(accumulator);
1426 }
1427 accumulator->Put('>');
1428 break;
1429 }
1430 }
1431}
1432
1433
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001434void JSObject::PrintElementsTransition(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 FILE* file, Handle<JSObject> object,
1436 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
1437 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001438 if (from_kind != to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001439 OFStream os(file);
1440 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
1441 << ElementsKindToString(to_kind) << "] in ";
1442 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001443 PrintF(file, " for ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001444 object->ShortPrint(file);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001445 PrintF(file, " from ");
1446 from_elements->ShortPrint(file);
1447 PrintF(file, " to ");
1448 to_elements->ShortPrint(file);
1449 PrintF(file, "\n");
1450 }
1451}
1452
1453
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001454void Map::PrintGeneralization(FILE* file,
1455 const char* reason,
1456 int modify_index,
1457 int split,
1458 int descriptors,
1459 bool constant_to_field,
1460 Representation old_representation,
1461 Representation new_representation,
1462 HeapType* old_field_type,
1463 HeapType* new_field_type) {
1464 OFStream os(file);
1465 os << "[generalizing ";
1466 constructor_name()->PrintOn(file);
1467 os << "] ";
1468 Name* name = instance_descriptors()->GetKey(modify_index);
1469 if (name->IsString()) {
1470 String::cast(name)->PrintOn(file);
1471 } else {
1472 os << "{symbol " << static_cast<void*>(name) << "}";
1473 }
1474 os << ":";
1475 if (constant_to_field) {
1476 os << "c";
1477 } else {
1478 os << old_representation.Mnemonic() << "{";
1479 old_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
1480 os << "}";
1481 }
1482 os << "->" << new_representation.Mnemonic() << "{";
1483 new_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
1484 os << "} (";
1485 if (strlen(reason) > 0) {
1486 os << reason;
1487 } else {
1488 os << "+" << (descriptors - split) << " maps";
1489 }
1490 os << ") [";
1491 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
1492 os << "]\n";
1493}
1494
1495
1496void JSObject::PrintInstanceMigration(FILE* file,
1497 Map* original_map,
1498 Map* new_map) {
1499 PrintF(file, "[migrating ");
1500 map()->constructor_name()->PrintOn(file);
1501 PrintF(file, "] ");
1502 DescriptorArray* o = original_map->instance_descriptors();
1503 DescriptorArray* n = new_map->instance_descriptors();
1504 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
1505 Representation o_r = o->GetDetails(i).representation();
1506 Representation n_r = n->GetDetails(i).representation();
1507 if (!o_r.Equals(n_r)) {
1508 String::cast(o->GetKey(i))->PrintOn(file);
1509 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
1510 } else if (o->GetDetails(i).type() == CONSTANT &&
1511 n->GetDetails(i).type() == FIELD) {
1512 Name* name = o->GetKey(i);
1513 if (name->IsString()) {
1514 String::cast(name)->PrintOn(file);
1515 } else {
1516 PrintF(file, "{symbol %p}", static_cast<void*>(name));
1517 }
1518 PrintF(file, " ");
1519 }
1520 }
1521 PrintF(file, "\n");
1522}
1523
1524
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001525void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +01001526 Heap* heap = GetHeap();
1527 if (!heap->Contains(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001528 os << "!!!INVALID POINTER!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00001529 return;
1530 }
Steve Block44f0eee2011-05-26 01:26:41 +01001531 if (!heap->Contains(map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001532 os << "!!!INVALID MAP!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00001533 return;
1534 }
1535
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 os << this << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +00001537
1538 if (IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001539 HeapStringAllocator allocator;
1540 StringStream accumulator(&allocator);
1541 String::cast(this)->StringShortPrint(&accumulator);
1542 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00001543 return;
1544 }
1545 if (IsJSObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001546 HeapStringAllocator allocator;
1547 StringStream accumulator(&allocator);
1548 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
1549 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00001550 return;
1551 }
1552 switch (map()->instance_type()) {
1553 case MAP_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001554 os << "<Map(elements=" << Map::cast(this)->elements_kind() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 break;
1556 case FIXED_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001557 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001559 case FIXED_DOUBLE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001560 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
1561 << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001562 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 case BYTE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001564 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001565 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001566 case FREE_SPACE_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001567 os << "<FreeSpace[" << FreeSpace::cast(this)->Size() << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001568 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001569#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
1570 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
1571 os << "<External" #Type "Array[" \
1572 << External##Type##Array::cast(this)->length() << "]>"; \
1573 break; \
1574 case FIXED_##TYPE##_ARRAY_TYPE: \
1575 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
1576 << "]>"; \
1577 break;
1578
1579 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
1580#undef TYPED_ARRAY_SHORT_PRINT
1581
1582 case SHARED_FUNCTION_INFO_TYPE: {
1583 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
1584 SmartArrayPointer<char> debug_name =
1585 shared->DebugName()->ToCString();
1586 if (debug_name[0] != 0) {
1587 os << "<SharedFunctionInfo " << debug_name.get() << ">";
1588 } else {
1589 os << "<SharedFunctionInfo>";
1590 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001592 }
Steve Block1e0659c2011-05-24 12:43:12 +01001593 case JS_MESSAGE_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001594 os << "<JSMessageObject>";
Steve Block1e0659c2011-05-24 12:43:12 +01001595 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001596#define MAKE_STRUCT_CASE(NAME, Name, name) \
1597 case NAME##_TYPE: \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001598 os << "<" #Name ">"; \
Steve Blocka7e24c12009-10-30 11:49:00 +00001599 break;
1600 STRUCT_LIST(MAKE_STRUCT_CASE)
1601#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001602 case CODE_TYPE: {
1603 Code* code = Code::cast(this);
1604 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
Steve Blocka7e24c12009-10-30 11:49:00 +00001605 break;
1606 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 case ODDBALL_TYPE: {
1608 if (IsUndefined()) {
1609 os << "<undefined>";
1610 } else if (IsTheHole()) {
1611 os << "<the hole>";
1612 } else if (IsNull()) {
1613 os << "<null>";
1614 } else if (IsTrue()) {
1615 os << "<true>";
1616 } else if (IsFalse()) {
1617 os << "<false>";
1618 } else {
1619 os << "<Odd Oddball>";
1620 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001622 }
1623 case SYMBOL_TYPE: {
1624 Symbol* symbol = Symbol::cast(this);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001625 symbol->SymbolShortPrint(os);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001626 break;
1627 }
1628 case HEAP_NUMBER_TYPE: {
1629 os << "<Number: ";
1630 HeapNumber::cast(this)->HeapNumberPrint(os);
1631 os << ">";
1632 break;
1633 }
1634 case MUTABLE_HEAP_NUMBER_TYPE: {
1635 os << "<MutableNumber: ";
1636 HeapNumber::cast(this)->HeapNumberPrint(os);
1637 os << '>';
1638 break;
1639 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001640 case JS_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001641 os << "<JSProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00001642 break;
1643 case JS_FUNCTION_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001644 os << "<JSFunctionProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00001645 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001646 case FOREIGN_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001647 os << "<Foreign>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001648 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001649 case CELL_TYPE: {
1650 os << "Cell for ";
1651 HeapStringAllocator allocator;
1652 StringStream accumulator(&allocator);
1653 Cell::cast(this)->value()->ShortPrint(&accumulator);
1654 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00001655 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001656 }
1657 case PROPERTY_CELL_TYPE: {
1658 os << "PropertyCell for ";
1659 HeapStringAllocator allocator;
1660 StringStream accumulator(&allocator);
1661 PropertyCell::cast(this)->value()->ShortPrint(&accumulator);
1662 os << accumulator.ToCString().get();
1663 break;
1664 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001665 case WEAK_CELL_TYPE: {
1666 os << "WeakCell for ";
1667 HeapStringAllocator allocator;
1668 StringStream accumulator(&allocator);
1669 WeakCell::cast(this)->value()->ShortPrint(&accumulator);
1670 os << accumulator.ToCString().get();
1671 break;
1672 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001674 os << "<Other heap object (" << map()->instance_type() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001675 break;
1676 }
1677}
1678
1679
Steve Blocka7e24c12009-10-30 11:49:00 +00001680void HeapObject::Iterate(ObjectVisitor* v) {
1681 // Handle header
1682 IteratePointer(v, kMapOffset);
1683 // Handle object body
1684 Map* m = map();
1685 IterateBody(m->instance_type(), SizeFromMap(m), v);
1686}
1687
1688
1689void HeapObject::IterateBody(InstanceType type, int object_size,
1690 ObjectVisitor* v) {
1691 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1692 // During GC, the map pointer field is encoded.
1693 if (type < FIRST_NONSTRING_TYPE) {
1694 switch (type & kStringRepresentationMask) {
1695 case kSeqStringTag:
1696 break;
1697 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001698 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001700 case kSlicedStringTag:
1701 SlicedString::BodyDescriptor::IterateBody(this, v);
1702 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001703 case kExternalStringTag:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001704 if ((type & kStringEncodingMask) == kOneByteStringTag) {
1705 reinterpret_cast<ExternalOneByteString*>(this)
1706 ->ExternalOneByteStringIterateBody(v);
Steve Blockd0582a62009-12-15 09:54:21 +00001707 } else {
1708 reinterpret_cast<ExternalTwoByteString*>(this)->
1709 ExternalTwoByteStringIterateBody(v);
1710 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001711 break;
1712 }
1713 return;
1714 }
1715
1716 switch (type) {
1717 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001718 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001719 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 case CONSTANT_POOL_ARRAY_TYPE:
1721 reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
1722 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001723 case FIXED_DOUBLE_ARRAY_TYPE:
1724 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001725 case JS_OBJECT_TYPE:
1726 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001727 case JS_GENERATOR_OBJECT_TYPE:
1728 case JS_MODULE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 case JS_VALUE_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001730 case JS_DATE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001731 case JS_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001732 case JS_ARRAY_BUFFER_TYPE:
1733 case JS_TYPED_ARRAY_TYPE:
1734 case JS_DATA_VIEW_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001735 case JS_SET_TYPE:
1736 case JS_MAP_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001737 case JS_SET_ITERATOR_TYPE:
1738 case JS_MAP_ITERATOR_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001739 case JS_WEAK_MAP_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001740 case JS_WEAK_SET_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001741 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 case JS_GLOBAL_PROXY_TYPE:
1743 case JS_GLOBAL_OBJECT_TYPE:
1744 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001745 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001746 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001747 break;
Steve Block791712a2010-08-27 10:21:07 +01001748 case JS_FUNCTION_TYPE:
1749 reinterpret_cast<JSFunction*>(this)
1750 ->JSFunctionIterateBody(object_size, v);
1751 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001752 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001753 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001755 case JS_PROXY_TYPE:
1756 JSProxy::BodyDescriptor::IterateBody(this, v);
1757 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001758 case JS_FUNCTION_PROXY_TYPE:
1759 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1760 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001761 case FOREIGN_TYPE:
1762 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001763 break;
1764 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001765 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001766 break;
1767 case CODE_TYPE:
1768 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1769 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001770 case CELL_TYPE:
1771 Cell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001772 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001773 case PROPERTY_CELL_TYPE:
1774 PropertyCell::BodyDescriptor::IterateBody(this, v);
1775 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001776 case WEAK_CELL_TYPE:
1777 WeakCell::BodyDescriptor::IterateBody(this, v);
1778 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001779 case SYMBOL_TYPE:
1780 Symbol::BodyDescriptor::IterateBody(this, v);
1781 break;
1782
Steve Blocka7e24c12009-10-30 11:49:00 +00001783 case HEAP_NUMBER_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001784 case MUTABLE_HEAP_NUMBER_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001785 case FILLER_TYPE:
1786 case BYTE_ARRAY_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001787 case FREE_SPACE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001788 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001789
1790#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
1791 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
1792 case FIXED_##TYPE##_ARRAY_TYPE: \
1793 break;
1794
1795 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1796#undef TYPED_ARRAY_CASE
1797
Ben Murdoch8f9999f2012-04-23 10:39:17 +01001798 case SHARED_FUNCTION_INFO_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001799 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 break;
Ben Murdoch8f9999f2012-04-23 10:39:17 +01001801 }
Iain Merrick75681382010-08-19 15:07:18 +01001802
Steve Blocka7e24c12009-10-30 11:49:00 +00001803#define MAKE_STRUCT_CASE(NAME, Name, name) \
1804 case NAME##_TYPE:
1805 STRUCT_LIST(MAKE_STRUCT_CASE)
1806#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001807 if (type == ALLOCATION_SITE_TYPE) {
1808 AllocationSite::BodyDescriptor::IterateBody(this, v);
1809 } else {
1810 StructBodyDescriptor::IterateBody(this, object_size, v);
1811 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001812 break;
1813 default:
1814 PrintF("Unknown type: %d\n", type);
1815 UNREACHABLE();
1816 }
1817}
1818
1819
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001820bool HeapNumber::HeapNumberBooleanValue() {
1821 return DoubleToBoolean(value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001822}
1823
1824
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001825void HeapNumber::HeapNumberPrint(std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001826 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001827}
1828
1829
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001830String* JSReceiver::class_name() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001831 if (IsJSFunction() || IsJSFunctionProxy()) {
1832 return GetHeap()->Function_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001833 }
1834 if (map()->constructor()->IsJSFunction()) {
1835 JSFunction* constructor = JSFunction::cast(map()->constructor());
1836 return String::cast(constructor->shared()->instance_class_name());
1837 }
1838 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001839 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001840}
1841
1842
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001843String* Map::constructor_name() {
1844 if (constructor()->IsJSFunction()) {
1845 JSFunction* constructor = JSFunction::cast(this->constructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00001846 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001847 if (name->length() > 0) return name;
1848 String* inferred_name = constructor->shared()->inferred_name();
1849 if (inferred_name->length() > 0) return inferred_name;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001850 Object* proto = prototype();
Ben Murdochf87a2032010-10-22 12:50:53 +01001851 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001852 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001853 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001854 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001855 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001856}
1857
1858
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001859String* JSReceiver::constructor_name() {
1860 return map()->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001861}
1862
1863
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001864MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
1865 Handle<Name> name,
1866 Handle<HeapType> type,
1867 PropertyAttributes attributes,
1868 Representation representation,
1869 TransitionFlag flag) {
1870 DCHECK(DescriptorArray::kNotFound ==
1871 map->instance_descriptors()->Search(
1872 *name, map->NumberOfOwnDescriptors()));
Ben Murdoch8b112d22011-06-08 16:22:53 +01001873
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001874 // Ensure the descriptor array does not get too big.
1875 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1876 return MaybeHandle<Map>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 }
1878
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 Isolate* isolate = map->GetIsolate();
1880
Steve Blocka7e24c12009-10-30 11:49:00 +00001881 // Compute the new index for new field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001882 int index = map->NextFreePropertyIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00001883
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
1885 representation = Representation::Tagged();
1886 type = HeapType::Any(isolate);
John Reck59135872010-11-02 12:39:01 -07001887 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001888
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889 FieldDescriptor new_field_desc(name, index, type, attributes, representation);
1890 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
1891 int unused_property_fields = new_map->unused_property_fields() - 1;
1892 if (unused_property_fields < 0) {
1893 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07001894 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895 new_map->set_unused_property_fields(unused_property_fields);
1896 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00001897}
1898
1899
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001900MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
1901 Handle<Name> name,
1902 Handle<Object> constant,
1903 PropertyAttributes attributes,
1904 TransitionFlag flag) {
1905 // Ensure the descriptor array does not get too big.
1906 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1907 return MaybeHandle<Map>();
John Reck59135872010-11-02 12:39:01 -07001908 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001909
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001910 // Allocate new instance descriptors with (name, constant) added.
1911 ConstantDescriptor new_constant_desc(name, constant, attributes);
1912 return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00001913}
1914
1915
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916void JSObject::AddSlowProperty(Handle<JSObject> object,
1917 Handle<Name> name,
1918 Handle<Object> value,
1919 PropertyAttributes attributes) {
1920 DCHECK(!object->HasFastProperties());
1921 Isolate* isolate = object->GetIsolate();
1922 Handle<NameDictionary> dict(object->property_dictionary());
1923 if (object->IsGlobalObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001924 // In case name is an orphaned property reuse the cell.
1925 int entry = dict->FindEntry(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001926 if (entry != NameDictionary::kNotFound) {
1927 Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
1928 PropertyCell::SetValueInferType(cell, value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001929 // Assign an enumeration index to the property and update
1930 // SetNextEnumerationIndex.
1931 int index = dict->NextEnumerationIndex();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001932 PropertyDetails details(attributes, FIELD, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00001933 dict->SetNextEnumerationIndex(index + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001934 dict->SetEntry(entry, name, cell, details);
1935 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001937 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
1938 PropertyCell::SetValueInferType(cell, value);
1939 value = cell;
Steve Blocka7e24c12009-10-30 11:49:00 +00001940 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001941 PropertyDetails details(attributes, FIELD, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001942 Handle<NameDictionary> result =
1943 NameDictionary::Add(dict, name, value, details);
1944 if (*dict != *result) object->set_properties(*result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001945}
1946
1947
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001948Context* JSObject::GetCreationContext() {
1949 Object* constructor = this->map()->constructor();
1950 JSFunction* function;
1951 if (!constructor->IsJSFunction()) {
1952 // Functions have null as a constructor,
1953 // but any JSFunction knows its context immediately.
1954 function = JSFunction::cast(this);
1955 } else {
1956 function = JSFunction::cast(constructor);
1957 }
1958
1959 return function->context()->native_context();
1960}
1961
1962
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001963MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
1964 const char* type_str,
1965 Handle<Name> name,
1966 Handle<Object> old_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001967 DCHECK(!object->IsJSGlobalProxy());
1968 DCHECK(!object->IsJSGlobalObject());
1969 Isolate* isolate = object->GetIsolate();
1970 HandleScope scope(isolate);
1971 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
1972 Handle<Object> args[] = { type, object, name, old_value };
1973 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
1974
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001975 return Execution::Call(isolate,
1976 Handle<JSFunction>(isolate->observers_notify_change()),
1977 isolate->factory()->undefined_value(), argc, args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001978}
1979
1980
1981const char* Representation::Mnemonic() const {
1982 switch (kind_) {
1983 case kNone: return "v";
1984 case kTagged: return "t";
1985 case kSmi: return "s";
1986 case kDouble: return "d";
1987 case kInteger32: return "i";
1988 case kHeapObject: return "h";
1989 case kExternal: return "x";
1990 default:
1991 UNREACHABLE();
1992 return NULL;
1993 }
1994}
1995
1996
1997bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
1998 int target_inobject, int target_unused,
1999 int* old_number_of_fields) {
2000 // If fields were added (or removed), rewrite the instance.
2001 *old_number_of_fields = NumberOfFields();
2002 DCHECK(target_number_of_fields >= *old_number_of_fields);
2003 if (target_number_of_fields != *old_number_of_fields) return true;
2004
2005 // If smi descriptors were replaced by double descriptors, rewrite.
2006 DescriptorArray* old_desc = instance_descriptors();
2007 DescriptorArray* new_desc = target->instance_descriptors();
2008 int limit = NumberOfOwnDescriptors();
2009 for (int i = 0; i < limit; i++) {
2010 if (new_desc->GetDetails(i).representation().IsDouble() !=
2011 old_desc->GetDetails(i).representation().IsDouble()) {
2012 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01002013 }
Steve Block8defd9f2010-07-08 12:39:36 +01002014 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002015
2016 // If no fields were added, and no inobject properties were removed, setting
2017 // the map is sufficient.
2018 if (target_inobject == inobject_properties()) return false;
2019 // In-object slack tracking may have reduced the object size of the new map.
2020 // In that case, succeed if all existing fields were inobject, and they still
2021 // fit within the new inobject size.
2022 DCHECK(target_inobject < inobject_properties());
2023 if (target_number_of_fields <= target_inobject) {
2024 DCHECK(target_number_of_fields + target_unused == target_inobject);
2025 return false;
2026 }
2027 // Otherwise, properties will need to be moved to the backing store.
2028 return true;
2029}
2030
2031
2032void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) {
2033 Isolate* isolate = parent->GetIsolate();
2034 Handle<Name> name = isolate->factory()->elements_transition_symbol();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002035 ConnectTransition(parent, child, name, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002036}
2037
2038
2039void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
2040 if (object->map() == *new_map) return;
2041 if (object->HasFastProperties()) {
2042 if (!new_map->is_dictionary_map()) {
2043 Handle<Map> old_map(object->map());
2044 MigrateFastToFast(object, new_map);
2045 if (old_map->is_prototype_map()) {
2046 // Clear out the old descriptor array to avoid problems to sharing
2047 // the descriptor array without using an explicit.
2048 old_map->InitializeDescriptors(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002049 old_map->GetHeap()->empty_descriptor_array(),
2050 LayoutDescriptor::FastPointerLayout());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002051 // Ensure that no transition was inserted for prototype migrations.
2052 DCHECK(!old_map->HasTransitionArray());
2053 DCHECK(new_map->GetBackPointer()->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00002054 }
2055 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002056 MigrateFastToSlow(object, new_map, 0);
2057 }
2058 } else {
2059 // For slow-to-fast migrations JSObject::TransformToFastProperties()
2060 // must be used instead.
2061 CHECK(new_map->is_dictionary_map());
2062
2063 // Slow-to-slow migration is trivial.
2064 object->set_map(*new_map);
2065 }
2066}
2067
2068
2069// To migrate a fast instance to a fast map:
2070// - First check whether the instance needs to be rewritten. If not, simply
2071// change the map.
2072// - Otherwise, allocate a fixed array large enough to hold all fields, in
2073// addition to unused space.
2074// - Copy all existing properties in, in the following order: backing store
2075// properties, unused fields, inobject properties.
2076// - If all allocation succeeded, commit the state atomically:
2077// * Copy inobject properties from the backing store back into the object.
2078// * Trim the difference in instance size of the object. This also cleanly
2079// frees inobject properties that moved to the backing store.
2080// * If there are properties left in the backing store, trim of the space used
2081// to temporarily store the inobject properties.
2082// * If there are properties left in the backing store, install the backing
2083// store.
2084void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
2085 Isolate* isolate = object->GetIsolate();
2086 Handle<Map> old_map(object->map());
2087 int old_number_of_fields;
2088 int number_of_fields = new_map->NumberOfFields();
2089 int inobject = new_map->inobject_properties();
2090 int unused = new_map->unused_property_fields();
2091
2092 // Nothing to do if no functions were converted to fields and no smis were
2093 // converted to doubles.
2094 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
2095 unused, &old_number_of_fields)) {
2096 object->synchronized_set_map(*new_map);
2097 return;
2098 }
2099
2100 int total_size = number_of_fields + unused;
2101 int external = total_size - inobject;
2102
2103 if (number_of_fields != old_number_of_fields &&
2104 new_map->GetBackPointer() == *old_map) {
2105 PropertyDetails details = new_map->GetLastDescriptorDetails();
2106
2107 if (old_map->unused_property_fields() > 0) {
2108 if (details.representation().IsDouble()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002109 FieldIndex index =
2110 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002111 if (new_map->IsUnboxedDoubleField(index)) {
2112 object->RawFastDoublePropertyAtPut(index, 0);
2113 } else {
2114 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2115 object->RawFastPropertyAtPut(index, *value);
2116 }
John Reck59135872010-11-02 12:39:01 -07002117 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002118 object->synchronized_set_map(*new_map);
2119 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002120 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002121
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002122 DCHECK(number_of_fields == old_number_of_fields + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002123 // This migration is a transition from a map that has run out of property
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002124 // space. Therefore it could be done by extending the backing store.
2125 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
2126 Handle<FixedArray> new_storage =
2127 FixedArray::CopySize(old_storage, external);
Steve Blocka7e24c12009-10-30 11:49:00 +00002128
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002129 // Properly initialize newly added property.
2130 Handle<Object> value;
2131 if (details.representation().IsDouble()) {
2132 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2133 } else {
2134 value = isolate->factory()->uninitialized_value();
John Reck59135872010-11-02 12:39:01 -07002135 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002136 DCHECK(details.type() == FIELD);
2137 int target_index = details.field_index() - inobject;
2138 DCHECK(target_index >= 0); // Must be a backing store index.
2139 new_storage->set(target_index, *value);
2140
2141 // From here on we cannot fail and we shouldn't GC anymore.
2142 DisallowHeapAllocation no_allocation;
2143
2144 // Set the new property value and do the map transition.
2145 object->set_properties(*new_storage);
2146 object->synchronized_set_map(*new_map);
2147 return;
John Reck59135872010-11-02 12:39:01 -07002148 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002149 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
2150
2151 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2152 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
2153 int old_nof = old_map->NumberOfOwnDescriptors();
2154 int new_nof = new_map->NumberOfOwnDescriptors();
2155
2156 // This method only supports generalizing instances to at least the same
2157 // number of properties.
2158 DCHECK(old_nof <= new_nof);
2159
2160 for (int i = 0; i < old_nof; i++) {
2161 PropertyDetails details = new_descriptors->GetDetails(i);
2162 if (details.type() != FIELD) continue;
2163 PropertyDetails old_details = old_descriptors->GetDetails(i);
2164 if (old_details.type() == CALLBACKS) {
2165 DCHECK(details.representation().IsTagged());
2166 continue;
2167 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002168 Representation old_representation = old_details.representation();
2169 Representation representation = details.representation();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002170 DCHECK(old_details.type() == CONSTANT ||
2171 old_details.type() == FIELD);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002172 Handle<Object> value;
2173 if (old_details.type() == CONSTANT) {
2174 value = handle(old_descriptors->GetValue(i), isolate);
2175 DCHECK(!old_representation.IsDouble() && !representation.IsDouble());
2176 } else {
2177 FieldIndex index = FieldIndex::ForDescriptor(*old_map, i);
2178 if (object->IsUnboxedDoubleField(index)) {
2179 double old = object->RawFastDoublePropertyAt(index);
2180 value = isolate->factory()->NewHeapNumber(
2181 old, representation.IsDouble() ? MUTABLE : IMMUTABLE);
2182
2183 } else {
2184 value = handle(object->RawFastPropertyAt(index), isolate);
2185 if (!old_representation.IsDouble() && representation.IsDouble()) {
2186 if (old_representation.IsNone()) {
2187 value = handle(Smi::FromInt(0), isolate);
2188 }
2189 value = Object::NewStorageFor(isolate, value, representation);
2190 } else if (old_representation.IsDouble() &&
2191 !representation.IsDouble()) {
2192 value = Object::WrapForRead(isolate, value, old_representation);
2193 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002194 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002195 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002196 DCHECK(!(representation.IsDouble() && value->IsSmi()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002197 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2198 if (target_index < 0) target_index += total_size;
2199 array->set(target_index, *value);
2200 }
2201
2202 for (int i = old_nof; i < new_nof; i++) {
2203 PropertyDetails details = new_descriptors->GetDetails(i);
2204 if (details.type() != FIELD) continue;
2205 Handle<Object> value;
2206 if (details.representation().IsDouble()) {
2207 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2208 } else {
2209 value = isolate->factory()->uninitialized_value();
2210 }
2211 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2212 if (target_index < 0) target_index += total_size;
2213 array->set(target_index, *value);
2214 }
2215
2216 // From here on we cannot fail and we shouldn't GC anymore.
2217 DisallowHeapAllocation no_allocation;
2218
2219 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2220 // avoid overwriting |one_pointer_filler_map|.
2221 int limit = Min(inobject, number_of_fields);
2222 for (int i = 0; i < limit; i++) {
2223 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002224 Object* value = array->get(external + i);
2225 // Can't use JSObject::FastPropertyAtPut() because proper map was not set
2226 // yet.
2227 if (new_map->IsUnboxedDoubleField(index)) {
2228 DCHECK(value->IsMutableHeapNumber());
2229 object->RawFastDoublePropertyAtPut(index,
2230 HeapNumber::cast(value)->value());
2231 } else {
2232 object->RawFastPropertyAtPut(index, value);
2233 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002234 }
2235
2236 Heap* heap = isolate->heap();
2237
2238 // If there are properties in the new backing store, trim it to the correct
2239 // size and install the backing store into the object.
2240 if (external > 0) {
2241 heap->RightTrimFixedArray<Heap::FROM_MUTATOR>(*array, inobject);
2242 object->set_properties(*array);
2243 }
2244
2245 // Create filler object past the new instance size.
2246 int new_instance_size = new_map->instance_size();
2247 int instance_size_delta = old_map->instance_size() - new_instance_size;
2248 DCHECK(instance_size_delta >= 0);
2249
2250 if (instance_size_delta > 0) {
2251 Address address = object->address();
2252 heap->CreateFillerObjectAt(
2253 address + new_instance_size, instance_size_delta);
2254 heap->AdjustLiveBytes(address, -instance_size_delta, Heap::FROM_MUTATOR);
2255 }
2256
2257 // We are storing the new map using release store after creating a filler for
2258 // the left-over space to avoid races with the sweeper thread.
2259 object->synchronized_set_map(*new_map);
2260}
2261
2262
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002263int Map::NumberOfFields() {
2264 DescriptorArray* descriptors = instance_descriptors();
2265 int result = 0;
2266 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2267 if (descriptors->GetDetails(i).type() == FIELD) result++;
2268 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002269 return result;
2270}
2271
2272
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2274 int modify_index,
2275 StoreMode store_mode,
2276 PropertyAttributes attributes,
2277 const char* reason) {
2278 Isolate* isolate = map->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002279 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
2280 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
2281 Handle<DescriptorArray> descriptors =
2282 DescriptorArray::CopyUpTo(old_descriptors, number_of_own_descriptors);
Steve Blocka7e24c12009-10-30 11:49:00 +00002283
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002284 for (int i = 0; i < number_of_own_descriptors; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002285 descriptors->SetRepresentation(i, Representation::Tagged());
2286 if (descriptors->GetDetails(i).type() == FIELD) {
2287 descriptors->SetValue(i, HeapType::Any());
John Reck59135872010-11-02 12:39:01 -07002288 }
2289 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002290
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002291 Handle<LayoutDescriptor> new_layout_descriptor(
2292 LayoutDescriptor::FastPointerLayout(), isolate);
2293 Handle<Map> new_map = CopyReplaceDescriptors(
2294 map, descriptors, new_layout_descriptor, OMIT_TRANSITION,
2295 MaybeHandle<Name>(), reason, SPECIAL_TRANSITION);
2296
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002297 // Unless the instance is being migrated, ensure that modify_index is a field.
2298 PropertyDetails details = descriptors->GetDetails(modify_index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002299 if (store_mode == FORCE_IN_OBJECT &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002300 (details.type() != FIELD || details.attributes() != attributes)) {
2301 int field_index = details.type() == FIELD ? details.field_index()
2302 : new_map->NumberOfFields();
2303 FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
2304 field_index, attributes, Representation::Tagged());
2305 descriptors->Replace(modify_index, &d);
2306 if (details.type() != FIELD) {
2307 int unused_property_fields = new_map->unused_property_fields() - 1;
2308 if (unused_property_fields < 0) {
2309 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07002310 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002311 new_map->set_unused_property_fields(unused_property_fields);
John Reck59135872010-11-02 12:39:01 -07002312 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002313 } else {
2314 DCHECK(details.attributes() == attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00002315 }
2316
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002317 if (FLAG_trace_generalization) {
2318 HeapType* field_type = (details.type() == FIELD)
2319 ? map->instance_descriptors()->GetFieldType(modify_index)
2320 : NULL;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002321 map->PrintGeneralization(
2322 stdout, reason, modify_index, new_map->NumberOfOwnDescriptors(),
2323 new_map->NumberOfOwnDescriptors(),
2324 details.type() == CONSTANT && store_mode == FORCE_IN_OBJECT,
2325 details.representation(), Representation::Tagged(), field_type,
2326 HeapType::Any());
Steve Blocka7e24c12009-10-30 11:49:00 +00002327 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002328 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002329}
2330
2331
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002332// static
2333Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2334 int modify_index,
2335 StoreMode store_mode,
2336 const char* reason) {
2337 PropertyDetails details =
2338 map->instance_descriptors()->GetDetails(modify_index);
2339 return CopyGeneralizeAllRepresentations(map, modify_index, store_mode,
2340 details.attributes(), reason);
2341}
Steve Blocka7e24c12009-10-30 11:49:00 +00002342
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002343
2344void Map::DeprecateTransitionTree() {
2345 if (is_deprecated()) return;
2346 if (HasTransitionArray()) {
2347 TransitionArray* transitions = this->transitions();
2348 for (int i = 0; i < transitions->number_of_transitions(); i++) {
2349 transitions->GetTarget(i)->DeprecateTransitionTree();
Steve Blocka7e24c12009-10-30 11:49:00 +00002350 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002351 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002352 deprecate();
2353 dependent_code()->DeoptimizeDependentCodeGroup(
2354 GetIsolate(), DependentCode::kTransitionGroup);
2355 NotifyLeafMapLayoutChange();
Steve Blocka7e24c12009-10-30 11:49:00 +00002356}
2357
2358
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002359// Invalidates a transition target at |key|, and installs |new_descriptors| over
2360// the current instance_descriptors to ensure proper sharing of descriptor
2361// arrays.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002362// Returns true if the transition target at given key was deprecated.
2363bool Map::DeprecateTarget(PropertyKind kind, Name* key,
2364 PropertyAttributes attributes,
2365 DescriptorArray* new_descriptors,
2366 LayoutDescriptor* new_layout_descriptor) {
2367 bool transition_target_deprecated = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002368 if (HasTransitionArray()) {
2369 TransitionArray* transitions = this->transitions();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002370 int transition = transitions->Search(kind, key, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002371 if (transition != TransitionArray::kNotFound) {
2372 transitions->GetTarget(transition)->DeprecateTransitionTree();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002373 transition_target_deprecated = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002374 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002375 }
2376
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002377 // Don't overwrite the empty descriptor array.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002378 if (NumberOfOwnDescriptors() == 0) return transition_target_deprecated;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002379
2380 DescriptorArray* to_replace = instance_descriptors();
2381 Map* current = this;
2382 GetHeap()->incremental_marking()->RecordWrites(to_replace);
2383 while (current->instance_descriptors() == to_replace) {
2384 current->SetEnumLength(kInvalidEnumCacheSentinel);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002385 current->UpdateDescriptors(new_descriptors, new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002386 Object* next = current->GetBackPointer();
2387 if (next->IsUndefined()) break;
2388 current = Map::cast(next);
2389 }
2390
2391 set_owns_descriptors(false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002392 return transition_target_deprecated;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002393}
2394
2395
2396Map* Map::FindRootMap() {
2397 Map* result = this;
2398 while (true) {
2399 Object* back = result->GetBackPointer();
2400 if (back->IsUndefined()) return result;
2401 result = Map::cast(back);
2402 }
2403}
2404
2405
2406Map* Map::FindLastMatchMap(int verbatim,
2407 int length,
2408 DescriptorArray* descriptors) {
2409 DisallowHeapAllocation no_allocation;
2410
2411 // This can only be called on roots of transition trees.
2412 DCHECK(GetBackPointer()->IsUndefined());
2413
2414 Map* current = this;
2415
2416 for (int i = verbatim; i < length; i++) {
2417 if (!current->HasTransitionArray()) break;
2418 Name* name = descriptors->GetKey(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002419 PropertyDetails details = descriptors->GetDetails(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002420 TransitionArray* transitions = current->transitions();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002421 int transition =
2422 transitions->Search(details.kind(), name, details.attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002423 if (transition == TransitionArray::kNotFound) break;
2424
2425 Map* next = transitions->GetTarget(transition);
2426 DescriptorArray* next_descriptors = next->instance_descriptors();
2427
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002428 PropertyDetails next_details = next_descriptors->GetDetails(i);
2429 if (details.type() != next_details.type()) break;
2430 if (details.attributes() != next_details.attributes()) break;
2431 if (!details.representation().Equals(next_details.representation())) break;
2432 if (next_details.type() == FIELD) {
2433 if (!descriptors->GetFieldType(i)->NowIs(
2434 next_descriptors->GetFieldType(i))) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002435 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002436 if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002437 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002438
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002439 current = next;
2440 }
2441 return current;
Steve Blocka7e24c12009-10-30 11:49:00 +00002442}
2443
2444
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002445Map* Map::FindFieldOwner(int descriptor) {
2446 DisallowHeapAllocation no_allocation;
2447 DCHECK_EQ(FIELD, instance_descriptors()->GetDetails(descriptor).type());
2448 Map* result = this;
2449 while (true) {
2450 Object* back = result->GetBackPointer();
2451 if (back->IsUndefined()) break;
2452 Map* parent = Map::cast(back);
2453 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
2454 result = parent;
Steve Blocka7e24c12009-10-30 11:49:00 +00002455 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002457}
2458
2459
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002460void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002461 Representation new_representation,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002462 Handle<HeapType> new_type) {
2463 DisallowHeapAllocation no_allocation;
2464 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
2465 if (details.type() != FIELD) return;
2466 if (HasTransitionArray()) {
2467 TransitionArray* transitions = this->transitions();
2468 for (int i = 0; i < transitions->number_of_transitions(); ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002469 transitions->GetTarget(i)
2470 ->UpdateFieldType(descriptor, name, new_representation, new_type);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002471 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002472 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002473 // It is allowed to change representation here only from None to something.
2474 DCHECK(details.representation().Equals(new_representation) ||
2475 details.representation().IsNone());
2476
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002477 // Skip if already updated the shared descriptor.
2478 if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return;
2479 FieldDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002480 new_type, details.attributes(), new_representation);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002481 instance_descriptors()->Replace(descriptor, &d);
2482}
2483
2484
2485// static
2486Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
2487 Handle<HeapType> type2,
2488 Isolate* isolate) {
2489 static const int kMaxClassesPerFieldType = 5;
2490 if (type1->NowIs(type2)) return type2;
2491 if (type2->NowIs(type1)) return type1;
2492 if (type1->NowStable() && type2->NowStable()) {
2493 Handle<HeapType> type = HeapType::Union(type1, type2, isolate);
2494 if (type->NumClasses() <= kMaxClassesPerFieldType) {
2495 DCHECK(type->NowStable());
2496 DCHECK(type1->NowIs(type));
2497 DCHECK(type2->NowIs(type));
2498 return type;
2499 }
2500 }
2501 return HeapType::Any(isolate);
2502}
2503
2504
2505// static
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002506void Map::GeneralizeFieldType(Handle<Map> map, int modify_index,
2507 Representation new_representation,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002508 Handle<HeapType> new_field_type) {
2509 Isolate* isolate = map->GetIsolate();
2510
2511 // Check if we actually need to generalize the field type at all.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002512 Handle<DescriptorArray> old_descriptors(map->instance_descriptors(), isolate);
2513 Representation old_representation =
2514 old_descriptors->GetDetails(modify_index).representation();
2515 Handle<HeapType> old_field_type(old_descriptors->GetFieldType(modify_index),
2516 isolate);
2517
2518 if (old_representation.Equals(new_representation) &&
2519 new_field_type->NowIs(old_field_type)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002520 DCHECK(Map::GeneralizeFieldType(old_field_type,
2521 new_field_type,
2522 isolate)->NowIs(old_field_type));
2523 return;
2524 }
2525
2526 // Determine the field owner.
2527 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
2528 Handle<DescriptorArray> descriptors(
2529 field_owner->instance_descriptors(), isolate);
2530 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
2531
2532 // Determine the generalized new field type.
2533 new_field_type = Map::GeneralizeFieldType(
2534 old_field_type, new_field_type, isolate);
2535
2536 PropertyDetails details = descriptors->GetDetails(modify_index);
2537 Handle<Name> name(descriptors->GetKey(modify_index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002538 field_owner->UpdateFieldType(modify_index, name, new_representation,
2539 new_field_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002540 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
2541 isolate, DependentCode::kFieldTypeGroup);
2542
2543 if (FLAG_trace_generalization) {
2544 map->PrintGeneralization(
2545 stdout, "field type generalization",
2546 modify_index, map->NumberOfOwnDescriptors(),
2547 map->NumberOfOwnDescriptors(), false,
2548 details.representation(), details.representation(),
2549 *old_field_type, *new_field_type);
2550 }
2551}
2552
2553
2554// Generalize the representation of the descriptor at |modify_index|.
2555// This method rewrites the transition tree to reflect the new change. To avoid
2556// high degrees over polymorphism, and to stabilize quickly, on every rewrite
2557// the new type is deduced by merging the current type with any potential new
2558// (partial) version of the type in the transition tree.
2559// To do this, on each rewrite:
2560// - Search the root of the transition tree using FindRootMap.
2561// - Find |target_map|, the newest matching version of this map using the keys
2562// in the |old_map|'s descriptor array to walk the transition tree.
2563// - Merge/generalize the descriptor array of the |old_map| and |target_map|.
2564// - Generalize the |modify_index| descriptor using |new_representation| and
2565// |new_field_type|.
2566// - Walk the tree again starting from the root towards |target_map|. Stop at
2567// |split_map|, the first map who's descriptor array does not match the merged
2568// descriptor array.
2569// - If |target_map| == |split_map|, |target_map| is in the expected state.
2570// Return it.
2571// - Otherwise, invalidate the outdated transition target from |target_map|, and
2572// replace its transition tree with a new branch for the updated descriptors.
2573Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
2574 int modify_index,
2575 Representation new_representation,
2576 Handle<HeapType> new_field_type,
2577 StoreMode store_mode) {
2578 Isolate* isolate = old_map->GetIsolate();
2579
2580 Handle<DescriptorArray> old_descriptors(
2581 old_map->instance_descriptors(), isolate);
2582 int old_nof = old_map->NumberOfOwnDescriptors();
2583 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2584 Representation old_representation = old_details.representation();
2585
2586 // It's fine to transition from None to anything but double without any
2587 // modification to the object, because the default uninitialized value for
2588 // representation None can be overwritten by both smi and tagged values.
2589 // Doubles, however, would require a box allocation.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002590 if (old_representation.IsNone() && !new_representation.IsNone() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002591 !new_representation.IsDouble()) {
2592 DCHECK(old_details.type() == FIELD);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002593 if (FLAG_trace_generalization) {
2594 old_map->PrintGeneralization(
2595 stdout, "uninitialized field",
2596 modify_index, old_map->NumberOfOwnDescriptors(),
2597 old_map->NumberOfOwnDescriptors(), false,
2598 old_representation, new_representation,
2599 old_descriptors->GetFieldType(modify_index), *new_field_type);
2600 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002601 Handle<Map> field_owner(old_map->FindFieldOwner(modify_index), isolate);
2602
2603 GeneralizeFieldType(field_owner, modify_index, new_representation,
2604 new_field_type);
2605 DCHECK(old_descriptors->GetDetails(modify_index).representation().Equals(
2606 new_representation));
2607 DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(new_field_type));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002608 return old_map;
2609 }
2610
2611 // Check the state of the root map.
2612 Handle<Map> root_map(old_map->FindRootMap(), isolate);
2613 if (!old_map->EquivalentToForTransition(*root_map)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002614 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2615 "GenAll_NotEquivalent");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002616 }
2617 int root_nof = root_map->NumberOfOwnDescriptors();
2618 if (modify_index < root_nof) {
2619 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002620 if ((old_details.type() != FIELD && store_mode == FORCE_IN_OBJECT) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002621 (old_details.type() == FIELD &&
2622 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
2623 !new_representation.fits_into(old_details.representation())))) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002624 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2625 "GenAll_RootModification");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002626 }
2627 }
2628
2629 Handle<Map> target_map = root_map;
2630 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002631 PropertyDetails old_details = old_descriptors->GetDetails(i);
2632 int j = target_map->SearchTransition(old_details.kind(),
2633 old_descriptors->GetKey(i),
2634 old_details.attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002635 if (j == TransitionArray::kNotFound) break;
2636 Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2637 Handle<DescriptorArray> tmp_descriptors = handle(
2638 tmp_map->instance_descriptors(), isolate);
2639
2640 // Check if target map is incompatible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002641 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2642 PropertyType old_type = old_details.type();
2643 PropertyType tmp_type = tmp_details.type();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002644 DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
2645 if ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
2646 (tmp_type != old_type ||
2647 tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
2648 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2649 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002650 }
2651 Representation old_representation = old_details.representation();
2652 Representation tmp_representation = tmp_details.representation();
2653 if (!old_representation.fits_into(tmp_representation) ||
2654 (!new_representation.fits_into(tmp_representation) &&
2655 modify_index == i)) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01002656 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002657 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002658 if (tmp_type == FIELD) {
2659 // Generalize the field type as necessary.
2660 Handle<HeapType> old_field_type = (old_type == FIELD)
2661 ? handle(old_descriptors->GetFieldType(i), isolate)
2662 : old_descriptors->GetValue(i)->OptimalType(
2663 isolate, tmp_representation);
2664 if (modify_index == i) {
2665 old_field_type = GeneralizeFieldType(
2666 new_field_type, old_field_type, isolate);
2667 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002668 GeneralizeFieldType(tmp_map, i, tmp_representation, old_field_type);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002669 } else if (tmp_type == CONSTANT) {
2670 if (old_type != CONSTANT ||
2671 old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
2672 break;
2673 }
2674 } else {
2675 DCHECK_EQ(tmp_type, old_type);
2676 DCHECK_EQ(tmp_descriptors->GetValue(i), old_descriptors->GetValue(i));
2677 }
2678 target_map = tmp_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002679 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002680
2681 // Directly change the map if the target map is more general.
2682 Handle<DescriptorArray> target_descriptors(
2683 target_map->instance_descriptors(), isolate);
2684 int target_nof = target_map->NumberOfOwnDescriptors();
2685 if (target_nof == old_nof &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002686 (store_mode != FORCE_IN_OBJECT ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002687 target_descriptors->GetDetails(modify_index).type() == FIELD)) {
2688 DCHECK(modify_index < target_nof);
2689 DCHECK(new_representation.fits_into(
2690 target_descriptors->GetDetails(modify_index).representation()));
2691 DCHECK(target_descriptors->GetDetails(modify_index).type() != FIELD ||
2692 new_field_type->NowIs(
2693 target_descriptors->GetFieldType(modify_index)));
2694 return target_map;
2695 }
2696
2697 // Find the last compatible target map in the transition tree.
2698 for (int i = target_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002699 PropertyDetails old_details = old_descriptors->GetDetails(i);
2700 int j = target_map->SearchTransition(old_details.kind(),
2701 old_descriptors->GetKey(i),
2702 old_details.attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002703 if (j == TransitionArray::kNotFound) break;
2704 Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2705 Handle<DescriptorArray> tmp_descriptors(
2706 tmp_map->instance_descriptors(), isolate);
2707
2708 // Check if target map is compatible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002709 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002710 DCHECK_EQ(old_details.attributes(), tmp_details.attributes());
2711 if ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
2712 (tmp_details.type() != old_details.type() ||
2713 tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
2714 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2715 "GenAll_Incompatible");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002716 }
2717 target_map = tmp_map;
2718 }
2719 target_nof = target_map->NumberOfOwnDescriptors();
2720 target_descriptors = handle(target_map->instance_descriptors(), isolate);
2721
2722 // Allocate a new descriptor array large enough to hold the required
2723 // descriptors, with minimally the exact same size as the old descriptor
2724 // array.
2725 int new_slack = Max(
2726 old_nof, old_descriptors->number_of_descriptors()) - old_nof;
2727 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
2728 isolate, old_nof, new_slack);
2729 DCHECK(new_descriptors->length() > target_descriptors->length() ||
2730 new_descriptors->NumberOfSlackDescriptors() > 0 ||
2731 new_descriptors->number_of_descriptors() ==
2732 old_descriptors->number_of_descriptors());
2733 DCHECK(new_descriptors->number_of_descriptors() == old_nof);
2734
2735 // 0 -> |root_nof|
2736 int current_offset = 0;
2737 for (int i = 0; i < root_nof; ++i) {
2738 PropertyDetails old_details = old_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002739 if (old_details.type() == FIELD) {
2740 current_offset += old_details.field_width_in_words();
2741 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002742 Descriptor d(handle(old_descriptors->GetKey(i), isolate),
2743 handle(old_descriptors->GetValue(i), isolate),
2744 old_details);
2745 new_descriptors->Set(i, &d);
2746 }
2747
2748 // |root_nof| -> |target_nof|
2749 for (int i = root_nof; i < target_nof; ++i) {
2750 Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
2751 PropertyDetails old_details = old_descriptors->GetDetails(i);
2752 PropertyDetails target_details = target_descriptors->GetDetails(i);
2753 target_details = target_details.CopyWithRepresentation(
2754 old_details.representation().generalize(
2755 target_details.representation()));
2756 if (modify_index == i) {
2757 target_details = target_details.CopyWithRepresentation(
2758 new_representation.generalize(target_details.representation()));
2759 }
2760 DCHECK_EQ(old_details.attributes(), target_details.attributes());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002761 if (old_details.type() == FIELD || target_details.type() == FIELD ||
2762 (modify_index == i && store_mode == FORCE_IN_OBJECT) ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002763 (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
2764 Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2765 ? handle(old_descriptors->GetFieldType(i), isolate)
2766 : old_descriptors->GetValue(i)->OptimalType(
2767 isolate, target_details.representation());
2768 Handle<HeapType> target_field_type = (target_details.type() == FIELD)
2769 ? handle(target_descriptors->GetFieldType(i), isolate)
2770 : target_descriptors->GetValue(i)->OptimalType(
2771 isolate, target_details.representation());
2772 target_field_type = GeneralizeFieldType(
2773 target_field_type, old_field_type, isolate);
2774 if (modify_index == i) {
2775 target_field_type = GeneralizeFieldType(
2776 target_field_type, new_field_type, isolate);
2777 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002778 FieldDescriptor d(target_key, current_offset, target_field_type,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002779 target_details.attributes(),
2780 target_details.representation());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002781 current_offset += d.GetDetails().field_width_in_words();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002782 new_descriptors->Set(i, &d);
2783 } else {
2784 DCHECK_NE(FIELD, target_details.type());
2785 Descriptor d(target_key,
2786 handle(target_descriptors->GetValue(i), isolate),
2787 target_details);
2788 new_descriptors->Set(i, &d);
2789 }
2790 }
2791
2792 // |target_nof| -> |old_nof|
2793 for (int i = target_nof; i < old_nof; ++i) {
2794 PropertyDetails old_details = old_descriptors->GetDetails(i);
2795 Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
2796 if (modify_index == i) {
2797 old_details = old_details.CopyWithRepresentation(
2798 new_representation.generalize(old_details.representation()));
2799 }
2800 if (old_details.type() == FIELD) {
2801 Handle<HeapType> old_field_type(
2802 old_descriptors->GetFieldType(i), isolate);
2803 if (modify_index == i) {
2804 old_field_type = GeneralizeFieldType(
2805 old_field_type, new_field_type, isolate);
2806 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002807 FieldDescriptor d(old_key, current_offset, old_field_type,
2808 old_details.attributes(), old_details.representation());
2809 current_offset += d.GetDetails().field_width_in_words();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002810 new_descriptors->Set(i, &d);
2811 } else {
2812 DCHECK(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002813 if (modify_index == i && store_mode == FORCE_IN_OBJECT) {
2814 FieldDescriptor d(
2815 old_key, current_offset,
2816 GeneralizeFieldType(old_descriptors->GetValue(i)->OptimalType(
2817 isolate, old_details.representation()),
2818 new_field_type, isolate),
2819 old_details.attributes(), old_details.representation());
2820 current_offset += d.GetDetails().field_width_in_words();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002821 new_descriptors->Set(i, &d);
2822 } else {
2823 DCHECK_NE(FIELD, old_details.type());
2824 Descriptor d(old_key,
2825 handle(old_descriptors->GetValue(i), isolate),
2826 old_details);
2827 new_descriptors->Set(i, &d);
2828 }
2829 }
2830 }
2831
2832 new_descriptors->Sort();
2833
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002834 DCHECK(store_mode != FORCE_IN_OBJECT ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002835 new_descriptors->GetDetails(modify_index).type() == FIELD);
2836
2837 Handle<Map> split_map(root_map->FindLastMatchMap(
2838 root_nof, old_nof, *new_descriptors), isolate);
2839 int split_nof = split_map->NumberOfOwnDescriptors();
2840 DCHECK_NE(old_nof, split_nof);
2841
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002842 Handle<LayoutDescriptor> new_layout_descriptor =
2843 LayoutDescriptor::New(split_map, new_descriptors, old_nof);
2844 PropertyDetails split_prop_details = old_descriptors->GetDetails(split_nof);
2845 bool transition_target_deprecated = split_map->DeprecateTarget(
2846 split_prop_details.kind(), old_descriptors->GetKey(split_nof),
2847 split_prop_details.attributes(), *new_descriptors,
2848 *new_layout_descriptor);
2849
2850 // If |transition_target_deprecated| is true then the transition array
2851 // already contains entry for given descriptor. This means that the transition
2852 // could be inserted regardless of whether transitions array is full or not.
2853 if (!transition_target_deprecated && !split_map->CanHaveMoreTransitions()) {
2854 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2855 "GenAll_CantHaveMoreTransitions");
2856 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002857
2858 if (FLAG_trace_generalization) {
2859 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2860 PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
2861 Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2862 ? handle(old_descriptors->GetFieldType(modify_index), isolate)
2863 : HeapType::Constant(handle(old_descriptors->GetValue(modify_index),
2864 isolate), isolate);
2865 Handle<HeapType> new_field_type = (new_details.type() == FIELD)
2866 ? handle(new_descriptors->GetFieldType(modify_index), isolate)
2867 : HeapType::Constant(handle(new_descriptors->GetValue(modify_index),
2868 isolate), isolate);
2869 old_map->PrintGeneralization(
2870 stdout, "", modify_index, split_nof, old_nof,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002871 old_details.type() == CONSTANT && store_mode == FORCE_IN_OBJECT,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002872 old_details.representation(), new_details.representation(),
2873 *old_field_type, *new_field_type);
2874 }
2875
2876 // Add missing transitions.
2877 Handle<Map> new_map = split_map;
2878 for (int i = split_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002879 new_map = CopyInstallDescriptors(new_map, i, new_descriptors,
2880 new_layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002881 }
2882 new_map->set_owns_descriptors(true);
2883 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002884}
2885
2886
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002887// Generalize the representation of all FIELD descriptors.
2888Handle<Map> Map::GeneralizeAllFieldRepresentations(
2889 Handle<Map> map) {
2890 Handle<DescriptorArray> descriptors(map->instance_descriptors());
2891 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
2892 if (descriptors->GetDetails(i).type() == FIELD) {
2893 map = GeneralizeRepresentation(map, i, Representation::Tagged(),
2894 HeapType::Any(map->GetIsolate()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002895 FORCE_IN_OBJECT);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002896 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002897 }
2898 return map;
2899}
2900
2901
2902// static
2903MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
2904 Handle<Map> proto_map(map);
2905 while (proto_map->prototype()->IsJSObject()) {
2906 Handle<JSObject> holder(JSObject::cast(proto_map->prototype()));
2907 proto_map = Handle<Map>(holder->map());
2908 if (proto_map->is_deprecated() && JSObject::TryMigrateInstance(holder)) {
2909 proto_map = Handle<Map>(holder->map());
2910 }
2911 }
2912 return TryUpdateInternal(map);
2913}
2914
2915
2916// static
2917Handle<Map> Map::Update(Handle<Map> map) {
2918 if (!map->is_deprecated()) return map;
2919 return GeneralizeRepresentation(map, 0, Representation::None(),
2920 HeapType::None(map->GetIsolate()),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002921 ALLOW_IN_DESCRIPTOR);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002922}
2923
2924
2925// static
2926MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
2927 DisallowHeapAllocation no_allocation;
2928 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
2929
2930 if (!old_map->is_deprecated()) return old_map;
2931
2932 // Check the state of the root map.
2933 Map* root_map = old_map->FindRootMap();
2934 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
2935 int root_nof = root_map->NumberOfOwnDescriptors();
2936
2937 int old_nof = old_map->NumberOfOwnDescriptors();
2938 DescriptorArray* old_descriptors = old_map->instance_descriptors();
2939
2940 Map* new_map = root_map;
2941 for (int i = root_nof; i < old_nof; ++i) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002942 PropertyDetails old_details = old_descriptors->GetDetails(i);
2943 int j = new_map->SearchTransition(old_details.kind(),
2944 old_descriptors->GetKey(i),
2945 old_details.attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002946 if (j == TransitionArray::kNotFound) return MaybeHandle<Map>();
2947 new_map = new_map->GetTransition(j);
2948 DescriptorArray* new_descriptors = new_map->instance_descriptors();
2949
2950 PropertyDetails new_details = new_descriptors->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002951 DCHECK_EQ(old_details.kind(), new_details.kind());
2952 DCHECK_EQ(old_details.attributes(), new_details.attributes());
2953 if (!old_details.representation().fits_into(new_details.representation())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002954 return MaybeHandle<Map>();
2955 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002956 Object* new_value = new_descriptors->GetValue(i);
2957 Object* old_value = old_descriptors->GetValue(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002958 switch (new_details.type()) {
2959 case FIELD: {
2960 PropertyType old_type = old_details.type();
2961 if (old_type == FIELD) {
2962 if (!HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) {
2963 return MaybeHandle<Map>();
2964 }
2965 } else {
2966 DCHECK(old_type == CONSTANT);
2967 if (!HeapType::cast(new_value)->NowContains(old_value)) {
2968 return MaybeHandle<Map>();
2969 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002970 }
2971 break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002972 }
2973 case ACCESSOR_FIELD:
2974 DCHECK(HeapType::Any()->Is(HeapType::cast(new_value)));
2975 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002976
2977 case CONSTANT:
2978 case CALLBACKS:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002979 if (old_details.location() == IN_OBJECT || old_value != new_value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002980 return MaybeHandle<Map>();
2981 }
2982 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002983 }
2984 }
2985 if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
2986 return handle(new_map);
2987}
2988
2989
2990MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
2991 Handle<Object> value) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002992 Handle<Name> name = it->name();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002993 Handle<JSObject> holder = it->GetHolder<JSObject>();
2994 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002995 if (interceptor->setter()->IsUndefined() ||
2996 (name->IsSymbol() && !interceptor->can_intercept_symbols())) {
2997 return MaybeHandle<Object>();
2998 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002999
3000 LOG(it->isolate(),
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003001 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003002 PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder,
3003 *holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003004 v8::GenericNamedPropertySetterCallback setter =
3005 v8::ToCData<v8::GenericNamedPropertySetterCallback>(
3006 interceptor->setter());
3007 v8::Handle<v8::Value> result =
3008 args.Call(setter, v8::Utils::ToLocal(name), v8::Utils::ToLocal(value));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003009 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
3010 if (!result.IsEmpty()) return value;
3011
3012 return MaybeHandle<Object>();
3013}
3014
3015
3016MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
3017 Handle<Name> name, Handle<Object> value,
3018 StrictMode strict_mode,
3019 StoreFromKeyed store_mode) {
3020 LookupIterator it(object, name);
3021 return SetProperty(&it, value, strict_mode, store_mode);
3022}
3023
3024
3025MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
3026 Handle<Object> value,
3027 StrictMode strict_mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003028 StoreFromKeyed store_mode,
3029 StorePropertyMode data_store_mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003030 // Make sure that the top context does not change when doing callbacks or
3031 // interceptor calls.
3032 AssertNoContextChange ncc(it->isolate());
3033
3034 bool done = false;
3035 for (; it->IsFound(); it->Next()) {
3036 switch (it->state()) {
3037 case LookupIterator::NOT_FOUND:
3038 UNREACHABLE();
3039
3040 case LookupIterator::ACCESS_CHECK:
3041 // TODO(verwaest): Remove the distinction. This is mostly bogus since we
3042 // don't know whether we'll want to fetch attributes or call a setter
3043 // until we find the property.
3044 if (it->HasAccess(v8::ACCESS_SET)) break;
3045 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
3046 strict_mode);
3047
3048 case LookupIterator::JSPROXY:
3049 if (it->HolderIsReceiverOrHiddenPrototype()) {
3050 return JSProxy::SetPropertyWithHandler(it->GetHolder<JSProxy>(),
3051 it->GetReceiver(), it->name(),
3052 value, strict_mode);
3053 } else {
3054 // TODO(verwaest): Use the MaybeHandle to indicate result.
3055 bool has_result = false;
3056 MaybeHandle<Object> maybe_result =
3057 JSProxy::SetPropertyViaPrototypesWithHandler(
3058 it->GetHolder<JSProxy>(), it->GetReceiver(), it->name(),
3059 value, strict_mode, &has_result);
3060 if (has_result) return maybe_result;
3061 done = true;
3062 }
3063 break;
3064
3065 case LookupIterator::INTERCEPTOR:
3066 if (it->HolderIsReceiverOrHiddenPrototype()) {
3067 MaybeHandle<Object> maybe_result =
3068 JSObject::SetPropertyWithInterceptor(it, value);
3069 if (!maybe_result.is_null()) return maybe_result;
3070 if (it->isolate()->has_pending_exception()) return maybe_result;
3071 } else {
3072 Maybe<PropertyAttributes> maybe_attributes =
3073 JSObject::GetPropertyAttributesWithInterceptor(
3074 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
3075 if (!maybe_attributes.has_value) return MaybeHandle<Object>();
3076 done = maybe_attributes.value != ABSENT;
3077 if (done && (maybe_attributes.value & READ_ONLY) != 0) {
3078 return WriteToReadOnlyProperty(it, value, strict_mode);
3079 }
3080 }
3081 break;
3082
3083 case LookupIterator::ACCESSOR:
3084 if (it->property_details().IsReadOnly()) {
3085 return WriteToReadOnlyProperty(it, value, strict_mode);
3086 }
3087 if (it->HolderIsReceiverOrHiddenPrototype() ||
3088 !it->GetAccessors()->IsDeclaredAccessorInfo()) {
3089 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
3090 it->GetHolder<JSObject>(),
3091 it->GetAccessors(), strict_mode);
3092 }
3093 done = true;
3094 break;
3095
3096 case LookupIterator::DATA:
3097 if (it->property_details().IsReadOnly()) {
3098 return WriteToReadOnlyProperty(it, value, strict_mode);
3099 }
3100 if (it->HolderIsReceiverOrHiddenPrototype()) {
3101 return SetDataProperty(it, value);
3102 }
3103 done = true;
3104 break;
3105
3106 case LookupIterator::TRANSITION:
3107 done = true;
3108 break;
3109 }
3110
3111 if (done) break;
3112 }
3113
3114 // If the receiver is the JSGlobalObject, the store was contextual. In case
3115 // the property did not exist yet on the global object itself, we have to
3116 // throw a reference error in strict mode.
3117 if (it->GetReceiver()->IsJSGlobalObject() && strict_mode == STRICT) {
3118 Handle<Object> args[1] = {it->name()};
3119 THROW_NEW_ERROR(it->isolate(),
3120 NewReferenceError("not_defined", HandleVector(args, 1)),
3121 Object);
3122 }
3123
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003124 if (data_store_mode == SUPER_PROPERTY) {
3125 LookupIterator own_lookup(it->GetReceiver(), it->name(),
3126 LookupIterator::OWN);
3127
3128 return JSObject::SetProperty(&own_lookup, value, strict_mode, store_mode,
3129 NORMAL_PROPERTY);
3130 }
3131
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003132 return AddDataProperty(it, value, NONE, strict_mode, store_mode);
3133}
3134
3135
3136MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it,
3137 Handle<Object> value,
3138 StrictMode strict_mode) {
3139 if (strict_mode != STRICT) return value;
3140
3141 Handle<Object> args[] = {it->name(), it->GetReceiver()};
3142 THROW_NEW_ERROR(it->isolate(),
3143 NewTypeError("strict_read_only_property",
3144 HandleVector(args, arraysize(args))),
3145 Object);
3146}
3147
3148
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003149MaybeHandle<Object> Object::WriteToReadOnlyElement(Isolate* isolate,
3150 Handle<Object> receiver,
3151 uint32_t index,
3152 Handle<Object> value,
3153 StrictMode strict_mode) {
3154 if (strict_mode != STRICT) return value;
3155
3156 Handle<Object> args[] = {isolate->factory()->NewNumberFromUint(index),
3157 receiver};
3158 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
3159 HandleVector(args, arraysize(args))),
3160 Object);
3161}
3162
3163
3164MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
3165 Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003166 // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
3167 // have own properties.
3168 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
3169
3170 // Store on the holder which may be hidden behind the receiver.
3171 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
3172
3173 // Old value for the observation change record.
3174 // Fetch before transforming the object since the encoding may become
3175 // incompatible with what's cached in |it|.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003176 bool is_observed = receiver->map()->is_observed() &&
3177 !it->isolate()->IsInternallyUsedPropertyName(it->name());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003178 MaybeHandle<Object> maybe_old;
3179 if (is_observed) maybe_old = it->GetDataValue();
3180
3181 // Possibly migrate to the most up-to-date map that will be able to store
3182 // |value| under it->name().
3183 it->PrepareForDataProperty(value);
3184
3185 // Write the property value.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003186 value = it->WriteDataValue(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003187
3188 // Send the change record if there are observers.
3189 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003190 RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
3191 receiver, "update", it->name(),
3192 maybe_old.ToHandleChecked()),
3193 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003194 }
3195
3196 return value;
3197}
3198
3199
3200MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
3201 Handle<Object> value,
3202 PropertyAttributes attributes,
3203 StrictMode strict_mode,
3204 StoreFromKeyed store_mode) {
3205 DCHECK(!it->GetReceiver()->IsJSProxy());
3206 if (!it->GetReceiver()->IsJSObject()) {
3207 // TODO(verwaest): Throw a TypeError with a more specific message.
3208 return WriteToReadOnlyProperty(it, value, strict_mode);
3209 }
3210
3211 Handle<JSObject> receiver = it->GetStoreTarget();
3212
3213 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
3214 // instead. If the prototype is Null, the proxy is detached.
3215 if (receiver->IsJSGlobalProxy()) return value;
3216
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003217 // If the receiver is Indexed Exotic object (currently only typed arrays),
3218 // disallow adding properties with numeric names.
3219 if (it->IsSpecialNumericIndex()) return value;
3220
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003221 // Possibly migrate to the most up-to-date map that will be able to store
3222 // |value| under it->name() with |attributes|.
3223 it->PrepareTransitionToDataProperty(value, attributes, store_mode);
3224 if (it->state() != LookupIterator::TRANSITION) {
3225 if (strict_mode == SLOPPY) return value;
3226
3227 Handle<Object> args[1] = {it->name()};
3228 THROW_NEW_ERROR(it->isolate(),
3229 NewTypeError("object_not_extensible",
3230 HandleVector(args, arraysize(args))),
3231 Object);
3232 }
3233 it->ApplyTransitionToDataProperty();
3234
3235 // TODO(verwaest): Encapsulate dictionary handling better.
3236 if (receiver->map()->is_dictionary_map()) {
3237 // TODO(verwaest): Probably should ensure this is done beforehand.
3238 it->InternalizeName();
3239 JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
3240 } else {
3241 // Write the property value.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003242 value = it->WriteDataValue(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003243 }
3244
3245 // Send the change record if there are observers.
3246 if (receiver->map()->is_observed() &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003247 !it->isolate()->IsInternallyUsedPropertyName(it->name())) {
3248 RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
3249 receiver, "add", it->name(),
3250 it->factory()->the_hole_value()),
3251 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003252 }
3253
3254 return value;
3255}
3256
3257
3258MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
3259 Handle<JSObject> object,
3260 uint32_t index,
3261 Handle<Object> value,
3262 bool* found,
3263 StrictMode strict_mode) {
3264 Isolate *isolate = object->GetIsolate();
3265 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd();
3266 iter.Advance()) {
3267 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
3268 return JSProxy::SetPropertyViaPrototypesWithHandler(
3269 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), object,
3270 isolate->factory()->Uint32ToString(index), // name
3271 value, strict_mode, found);
3272 }
3273 Handle<JSObject> js_proto =
3274 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
3275 if (!js_proto->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003276 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00003277 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003278 Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary());
Steve Blocka7e24c12009-10-30 11:49:00 +00003279 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003280 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003281 PropertyDetails details = dictionary->DetailsAt(entry);
3282 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01003283 *found = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003284 Handle<Object> structure(dictionary->ValueAt(entry), isolate);
3285 return SetElementWithCallback(object, structure, index, value, js_proto,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003286 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003287 }
3288 }
3289 }
Steve Block1e0659c2011-05-24 12:43:12 +01003290 *found = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003291 return isolate->factory()->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003292}
3293
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003294
3295void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
3296 // Only supports adding slack to owned descriptors.
3297 DCHECK(map->owns_descriptors());
3298
3299 Handle<DescriptorArray> descriptors(map->instance_descriptors());
3300 int old_size = map->NumberOfOwnDescriptors();
3301 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
3302
3303 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
3304 descriptors, old_size, slack);
3305
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003306 DisallowHeapAllocation no_allocation;
3307 // The descriptors are still the same, so keep the layout descriptor.
3308 LayoutDescriptor* layout_descriptor = map->GetLayoutDescriptor();
3309
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003310 if (old_size == 0) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003311 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003312 return;
3313 }
3314
3315 // If the source descriptors had an enum cache we copy it. This ensures
3316 // that the maps to which we push the new descriptor array back can rely
3317 // on a cache always being available once it is set. If the map has more
3318 // enumerated descriptors than available in the original cache, the cache
3319 // will be lazily replaced by the extended cache when needed.
3320 if (descriptors->HasEnumCache()) {
3321 new_descriptors->CopyEnumCacheFrom(*descriptors);
3322 }
3323
3324 // Replace descriptors by new_descriptors in all maps that share it.
3325 map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
3326
3327 Map* walk_map;
3328 for (Object* current = map->GetBackPointer();
3329 !current->IsUndefined();
3330 current = walk_map->GetBackPointer()) {
3331 walk_map = Map::cast(current);
3332 if (walk_map->instance_descriptors() != *descriptors) break;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003333 walk_map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003334 }
3335
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003336 map->UpdateDescriptors(*new_descriptors, layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003337}
3338
3339
3340template<class T>
3341static int AppendUniqueCallbacks(NeanderArray* callbacks,
3342 Handle<typename T::Array> array,
3343 int valid_descriptors) {
3344 int nof_callbacks = callbacks->length();
3345
3346 Isolate* isolate = array->GetIsolate();
3347 // Ensure the keys are unique names before writing them into the
3348 // instance descriptor. Since it may cause a GC, it has to be done before we
3349 // temporarily put the heap in an invalid state while appending descriptors.
3350 for (int i = 0; i < nof_callbacks; ++i) {
3351 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3352 if (entry->name()->IsUniqueName()) continue;
3353 Handle<String> key =
3354 isolate->factory()->InternalizeString(
3355 Handle<String>(String::cast(entry->name())));
3356 entry->set_name(*key);
3357 }
3358
3359 // Fill in new callback descriptors. Process the callbacks from
3360 // back to front so that the last callback with a given name takes
3361 // precedence over previously added callbacks with that name.
3362 for (int i = nof_callbacks - 1; i >= 0; i--) {
3363 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3364 Handle<Name> key(Name::cast(entry->name()));
3365 // Check if a descriptor with this name already exists before writing.
3366 if (!T::Contains(key, entry, valid_descriptors, array)) {
3367 T::Insert(key, entry, valid_descriptors, array);
3368 valid_descriptors++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003369 }
3370 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003371
3372 return valid_descriptors;
3373}
3374
3375struct DescriptorArrayAppender {
3376 typedef DescriptorArray Array;
3377 static bool Contains(Handle<Name> key,
3378 Handle<AccessorInfo> entry,
3379 int valid_descriptors,
3380 Handle<DescriptorArray> array) {
3381 DisallowHeapAllocation no_gc;
3382 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
3383 }
3384 static void Insert(Handle<Name> key,
3385 Handle<AccessorInfo> entry,
3386 int valid_descriptors,
3387 Handle<DescriptorArray> array) {
3388 DisallowHeapAllocation no_gc;
3389 CallbacksDescriptor desc(key, entry, entry->property_attributes());
3390 array->Append(&desc);
3391 }
3392};
3393
3394
3395struct FixedArrayAppender {
3396 typedef FixedArray Array;
3397 static bool Contains(Handle<Name> key,
3398 Handle<AccessorInfo> entry,
3399 int valid_descriptors,
3400 Handle<FixedArray> array) {
3401 for (int i = 0; i < valid_descriptors; i++) {
3402 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
3403 }
3404 return false;
3405 }
3406 static void Insert(Handle<Name> key,
3407 Handle<AccessorInfo> entry,
3408 int valid_descriptors,
3409 Handle<FixedArray> array) {
3410 DisallowHeapAllocation no_gc;
3411 array->set(valid_descriptors, *entry);
3412 }
3413};
3414
3415
3416void Map::AppendCallbackDescriptors(Handle<Map> map,
3417 Handle<Object> descriptors) {
3418 int nof = map->NumberOfOwnDescriptors();
3419 Handle<DescriptorArray> array(map->instance_descriptors());
3420 NeanderArray callbacks(descriptors);
3421 DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
3422 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
3423 map->SetNumberOfOwnDescriptors(nof);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003424}
3425
Steve Blocka7e24c12009-10-30 11:49:00 +00003426
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003427int AccessorInfo::AppendUnique(Handle<Object> descriptors,
3428 Handle<FixedArray> array,
3429 int valid_descriptors) {
3430 NeanderArray callbacks(descriptors);
3431 DCHECK(array->length() >= callbacks.length() + valid_descriptors);
3432 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
3433 array,
3434 valid_descriptors);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003435}
3436
3437
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003438static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003439 DCHECK(!map.is_null());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003440 for (int i = 0; i < maps->length(); ++i) {
3441 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
3442 }
3443 return false;
3444}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003445
Ben Murdoch85b71792012-04-11 18:30:58 +01003446
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003447template <class T>
3448static Handle<T> MaybeNull(T* p) {
3449 if (p == NULL) return Handle<T>::null();
3450 return Handle<T>(p);
3451}
3452
3453
3454Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003455 ElementsKind kind = elements_kind();
3456 Handle<Map> transitioned_map = Handle<Map>::null();
3457 Handle<Map> current_map(this);
3458 bool packed = IsFastPackedElementsKind(kind);
3459 if (IsTransitionableFastElementsKind(kind)) {
3460 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
3461 kind = GetNextMoreGeneralFastElementsKind(kind, false);
3462 Handle<Map> maybe_transitioned_map =
3463 MaybeNull(current_map->LookupElementsTransitionMap(kind));
3464 if (maybe_transitioned_map.is_null()) break;
3465 if (ContainsMap(candidates, maybe_transitioned_map) &&
3466 (packed || !IsFastPackedElementsKind(kind))) {
3467 transitioned_map = maybe_transitioned_map;
3468 if (!IsFastPackedElementsKind(kind)) packed = false;
3469 }
3470 current_map = maybe_transitioned_map;
Ben Murdoch85b71792012-04-11 18:30:58 +01003471 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003472 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003473 return transitioned_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003474}
Ben Murdoch85b71792012-04-11 18:30:58 +01003475
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003476
3477static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
3478 Map* current_map = map;
3479 int target_kind =
3480 IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind)
3481 ? to_kind
3482 : TERMINAL_FAST_ELEMENTS_KIND;
3483
3484 // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data
3485 // allows to change elements from arbitrary kind to any ExternalArray
3486 // elements kind. Satisfy its requirements, checking whether we already
3487 // have the cached transition.
3488 if (IsExternalArrayElementsKind(to_kind) &&
3489 !IsFixedTypedArrayElementsKind(map->elements_kind())) {
3490 if (map->HasElementsTransition()) {
3491 Map* next_map = map->elements_transition_map();
3492 if (next_map->elements_kind() == to_kind) return next_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003493 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003494 return map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003495 }
3496
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003497 ElementsKind kind = map->elements_kind();
3498 while (kind != target_kind) {
3499 kind = GetNextTransitionElementsKind(kind);
3500 if (!current_map->HasElementsTransition()) return current_map;
3501 current_map = current_map->elements_transition_map();
3502 }
3503
3504 if (to_kind != kind && current_map->HasElementsTransition()) {
3505 DCHECK(to_kind == DICTIONARY_ELEMENTS);
3506 Map* next_map = current_map->elements_transition_map();
3507 if (next_map->elements_kind() == to_kind) return next_map;
3508 }
3509
3510 DCHECK(current_map->elements_kind() == target_kind);
3511 return current_map;
3512}
3513
3514
3515Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
3516 Map* to_map = FindClosestElementsTransition(this, to_kind);
3517 if (to_map->elements_kind() == to_kind) return to_map;
3518 return NULL;
3519}
3520
3521
3522bool Map::IsMapInArrayPrototypeChain() {
3523 Isolate* isolate = GetIsolate();
3524 if (isolate->initial_array_prototype()->map() == this) {
3525 return true;
3526 }
3527
3528 if (isolate->initial_object_prototype()->map() == this) {
3529 return true;
3530 }
3531
3532 return false;
3533}
3534
3535
Emily Bernierd0a1eb72015-03-24 16:35:39 -04003536Handle<WeakCell> Map::WeakCellForMap(Handle<Map> map) {
3537 Isolate* isolate = map->GetIsolate();
3538 if (map->code_cache()->IsFixedArray()) {
3539 return isolate->factory()->NewWeakCell(map);
3540 }
3541 Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
3542 if (code_cache->weak_cell_cache()->IsWeakCell()) {
3543 return Handle<WeakCell>(WeakCell::cast(code_cache->weak_cell_cache()));
3544 }
3545 Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(map);
3546 code_cache->set_weak_cell_cache(*weak_cell);
3547 return weak_cell;
3548}
3549
3550
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003551static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
3552 ElementsKind to_kind) {
3553 DCHECK(IsTransitionElementsKind(map->elements_kind()));
3554
3555 Handle<Map> current_map = map;
3556
3557 ElementsKind kind = map->elements_kind();
3558 if (!map->is_prototype_map()) {
3559 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
3560 kind = GetNextTransitionElementsKind(kind);
3561 current_map =
3562 Map::CopyAsElementsKind(current_map, kind, INSERT_TRANSITION);
3563 }
3564 }
3565
3566 // In case we are exiting the fast elements kind system, just add the map in
3567 // the end.
3568 if (kind != to_kind) {
3569 current_map = Map::CopyAsElementsKind(
3570 current_map, to_kind, INSERT_TRANSITION);
3571 }
3572
3573 DCHECK(current_map->elements_kind() == to_kind);
3574 return current_map;
3575}
3576
3577
3578Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
3579 ElementsKind to_kind) {
3580 ElementsKind from_kind = map->elements_kind();
3581 if (from_kind == to_kind) return map;
3582
3583 Isolate* isolate = map->GetIsolate();
3584 Context* native_context = isolate->context()->native_context();
3585 Object* maybe_array_maps = native_context->js_array_maps();
3586 if (maybe_array_maps->IsFixedArray()) {
3587 DisallowHeapAllocation no_gc;
3588 FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
3589 if (array_maps->get(from_kind) == *map) {
3590 Object* maybe_transitioned_map = array_maps->get(to_kind);
3591 if (maybe_transitioned_map->IsMap()) {
3592 return handle(Map::cast(maybe_transitioned_map));
Ben Murdoch85b71792012-04-11 18:30:58 +01003593 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003594 }
3595 }
3596
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003597 return TransitionElementsToSlow(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003598}
3599
3600
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003601Handle<Map> Map::TransitionElementsToSlow(Handle<Map> map,
3602 ElementsKind to_kind) {
3603 ElementsKind from_kind = map->elements_kind();
3604
3605 if (from_kind == to_kind) {
3606 return map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003607 }
3608
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003609 bool allow_store_transition =
3610 // Only remember the map transition if there is not an already existing
3611 // non-matching element transition.
3612 !map->IsUndefined() && !map->is_dictionary_map() &&
3613 IsTransitionElementsKind(from_kind);
3614
3615 // Only store fast element maps in ascending generality.
3616 if (IsFastElementsKind(to_kind)) {
3617 allow_store_transition &=
3618 IsTransitionableFastElementsKind(from_kind) &&
3619 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003620 }
3621
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003622 if (!allow_store_transition) {
3623 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003624 }
3625
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003626 return Map::AsElementsKind(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003627}
3628
3629
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003630// static
3631Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
3632 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003633
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003634 if (closest_map->elements_kind() == kind) {
3635 return closest_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003636 }
3637
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003638 return AddMissingElementsTransitions(closest_map, kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003639}
3640
3641
3642Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3643 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003644 Handle<Map> map(object->map());
3645 return Map::TransitionElementsTo(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003646}
3647
3648
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003649Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
3650 Handle<Name> name) {
3651 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003652
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003653 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3654 if (name->IsSymbol()) return maybe(false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003655
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003656 Handle<Object> args[] = { name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003657 Handle<Object> result;
3658 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3659 isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(),
3660 arraysize(args), args),
3661 Maybe<bool>());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003662
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003663 return maybe(result->BooleanValue());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003664}
3665
3666
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003667MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
3668 Handle<Object> receiver,
3669 Handle<Name> name,
3670 Handle<Object> value,
3671 StrictMode strict_mode) {
3672 Isolate* isolate = proxy->GetIsolate();
3673
3674 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3675 if (name->IsSymbol()) return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003676
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003677 Handle<Object> args[] = { receiver, name, value };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003678 RETURN_ON_EXCEPTION(
3679 isolate,
3680 CallTrap(proxy,
3681 "set",
3682 isolate->derived_set_trap(),
3683 arraysize(args),
3684 args),
3685 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003686
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003687 return value;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003688}
3689
3690
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003691MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
3692 Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
3693 Handle<Object> value, StrictMode strict_mode, bool* done) {
3694 Isolate* isolate = proxy->GetIsolate();
3695 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003696
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003697 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3698 if (name->IsSymbol()) {
3699 *done = false;
3700 return isolate->factory()->the_hole_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003701 }
3702
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003703 *done = true; // except where redefined...
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003704 Handle<Object> args[] = { name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003705 Handle<Object> result;
3706 ASSIGN_RETURN_ON_EXCEPTION(
3707 isolate, result,
3708 CallTrap(proxy,
3709 "getPropertyDescriptor",
3710 Handle<Object>(),
3711 arraysize(args),
3712 args),
3713 Object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003714
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003715 if (result->IsUndefined()) {
3716 *done = false;
3717 return isolate->factory()->the_hole_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003718 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003719
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003720 // Emulate [[GetProperty]] semantics for proxies.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003721 Handle<Object> argv[] = { result };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003722 Handle<Object> desc;
3723 ASSIGN_RETURN_ON_EXCEPTION(
3724 isolate, desc,
3725 Execution::Call(isolate,
3726 isolate->to_complete_property_descriptor(),
3727 result,
3728 arraysize(argv),
3729 argv),
3730 Object);
3731
3732 // [[GetProperty]] requires to check that all properties are configurable.
3733 Handle<String> configurable_name =
3734 isolate->factory()->InternalizeOneByteString(
3735 STATIC_CHAR_VECTOR("configurable_"));
3736 Handle<Object> configurable =
3737 Object::GetProperty(desc, configurable_name).ToHandleChecked();
3738 DCHECK(configurable->IsBoolean());
3739 if (configurable->IsFalse()) {
3740 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3741 STATIC_CHAR_VECTOR("getPropertyDescriptor"));
3742 Handle<Object> args[] = { handler, trap, name };
3743 THROW_NEW_ERROR(isolate, NewTypeError("proxy_prop_not_configurable",
3744 HandleVector(args, arraysize(args))),
3745 Object);
3746 }
3747 DCHECK(configurable->IsTrue());
3748
3749 // Check for DataDescriptor.
3750 Handle<String> hasWritable_name =
3751 isolate->factory()->InternalizeOneByteString(
3752 STATIC_CHAR_VECTOR("hasWritable_"));
3753 Handle<Object> hasWritable =
3754 Object::GetProperty(desc, hasWritable_name).ToHandleChecked();
3755 DCHECK(hasWritable->IsBoolean());
3756 if (hasWritable->IsTrue()) {
3757 Handle<String> writable_name = isolate->factory()->InternalizeOneByteString(
3758 STATIC_CHAR_VECTOR("writable_"));
3759 Handle<Object> writable =
3760 Object::GetProperty(desc, writable_name).ToHandleChecked();
3761 DCHECK(writable->IsBoolean());
3762 *done = writable->IsFalse();
3763 if (!*done) return isolate->factory()->the_hole_value();
3764 if (strict_mode == SLOPPY) return value;
3765 Handle<Object> args[] = { name, receiver };
3766 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
3767 HandleVector(args, arraysize(args))),
3768 Object);
3769 }
3770
3771 // We have an AccessorDescriptor.
3772 Handle<String> set_name =
3773 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("set_"));
3774 Handle<Object> setter = Object::GetProperty(desc, set_name).ToHandleChecked();
3775 if (!setter->IsUndefined()) {
3776 // TODO(rossberg): nicer would be to cast to some JSCallable here...
3777 return SetPropertyWithDefinedSetter(
3778 receiver, Handle<JSReceiver>::cast(setter), value);
3779 }
3780
3781 if (strict_mode == SLOPPY) return value;
3782 Handle<Object> args2[] = { name, proxy };
3783 THROW_NEW_ERROR(isolate, NewTypeError("no_setter_in_callback",
3784 HandleVector(args2, arraysize(args2))),
3785 Object);
3786}
3787
3788
3789MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
3790 Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
3791 Isolate* isolate = proxy->GetIsolate();
3792
3793 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3794 if (name->IsSymbol()) return isolate->factory()->false_value();
3795
3796 Handle<Object> args[] = { name };
3797 Handle<Object> result;
3798 ASSIGN_RETURN_ON_EXCEPTION(
3799 isolate, result,
3800 CallTrap(proxy,
3801 "delete",
3802 Handle<Object>(),
3803 arraysize(args),
3804 args),
3805 Object);
3806
3807 bool result_bool = result->BooleanValue();
3808 if (mode == STRICT_DELETION && !result_bool) {
3809 Handle<Object> handler(proxy->handler(), isolate);
3810 Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
3811 STATIC_CHAR_VECTOR("delete"));
3812 Handle<Object> args[] = { handler, trap_name };
3813 THROW_NEW_ERROR(isolate, NewTypeError("handler_failed",
3814 HandleVector(args, arraysize(args))),
3815 Object);
3816 }
3817 return isolate->factory()->ToBoolean(result_bool);
3818}
3819
3820
3821MaybeHandle<Object> JSProxy::DeleteElementWithHandler(
3822 Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
3823 Isolate* isolate = proxy->GetIsolate();
3824 Handle<String> name = isolate->factory()->Uint32ToString(index);
3825 return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
3826}
3827
3828
3829Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
3830 Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name) {
3831 Isolate* isolate = proxy->GetIsolate();
3832 HandleScope scope(isolate);
3833
3834 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3835 if (name->IsSymbol()) return maybe(ABSENT);
3836
3837 Handle<Object> args[] = { name };
3838 Handle<Object> result;
3839 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3840 isolate, result,
3841 proxy->CallTrap(proxy, "getPropertyDescriptor", Handle<Object>(),
3842 arraysize(args), args),
3843 Maybe<PropertyAttributes>());
3844
3845 if (result->IsUndefined()) return maybe(ABSENT);
3846
3847 Handle<Object> argv[] = { result };
3848 Handle<Object> desc;
3849 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3850 isolate, desc,
3851 Execution::Call(isolate, isolate->to_complete_property_descriptor(),
3852 result, arraysize(argv), argv),
3853 Maybe<PropertyAttributes>());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003854
3855 // Convert result to PropertyAttributes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003856 Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
3857 STATIC_CHAR_VECTOR("enumerable_"));
3858 Handle<Object> enumerable;
3859 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, enumerable,
3860 Object::GetProperty(desc, enum_n),
3861 Maybe<PropertyAttributes>());
3862 Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
3863 STATIC_CHAR_VECTOR("configurable_"));
3864 Handle<Object> configurable;
3865 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, configurable,
3866 Object::GetProperty(desc, conf_n),
3867 Maybe<PropertyAttributes>());
3868 Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
3869 STATIC_CHAR_VECTOR("writable_"));
3870 Handle<Object> writable;
3871 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, writable,
3872 Object::GetProperty(desc, writ_n),
3873 Maybe<PropertyAttributes>());
3874 if (!writable->BooleanValue()) {
3875 Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
3876 STATIC_CHAR_VECTOR("set_"));
3877 Handle<Object> setter;
3878 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, setter,
3879 Object::GetProperty(desc, set_n),
3880 Maybe<PropertyAttributes>());
3881 writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
3882 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003883
3884 if (configurable->IsFalse()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003885 Handle<Object> handler(proxy->handler(), isolate);
3886 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3887 STATIC_CHAR_VECTOR("getPropertyDescriptor"));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003888 Handle<Object> args[] = { handler, trap, name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003889 Handle<Object> error;
3890 MaybeHandle<Object> maybe_error = isolate->factory()->NewTypeError(
3891 "proxy_prop_not_configurable", HandleVector(args, arraysize(args)));
3892 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
3893 return maybe(NONE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003894 }
3895
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003896 int attributes = NONE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003897 if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3898 if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3899 if (!writable->BooleanValue()) attributes |= READ_ONLY;
3900 return maybe(static_cast<PropertyAttributes>(attributes));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003901}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003902
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003903
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003904Maybe<PropertyAttributes> JSProxy::GetElementAttributeWithHandler(
3905 Handle<JSProxy> proxy, Handle<JSReceiver> receiver, uint32_t index) {
3906 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003907 Handle<String> name = isolate->factory()->Uint32ToString(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003908 return GetPropertyAttributesWithHandler(proxy, receiver, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003909}
3910
3911
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003912void JSProxy::Fix(Handle<JSProxy> proxy) {
3913 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003914
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003915 // Save identity hash.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003916 Handle<Object> hash(proxy->GetIdentityHash(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003917
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003918 if (proxy->IsJSFunctionProxy()) {
3919 isolate->factory()->BecomeJSFunction(proxy);
Ben Murdoch589d6972011-11-30 16:04:58 +00003920 // Code will be set on the JavaScript side.
3921 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003922 isolate->factory()->BecomeJSObject(proxy);
Ben Murdoch589d6972011-11-30 16:04:58 +00003923 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003924 DCHECK(proxy->IsJSObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003925
3926 // Inherit identity, if it was present.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003927 if (hash->IsSmi()) {
3928 JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
3929 Handle<Smi>::cast(hash));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003930 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003931}
3932
3933
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003934MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
3935 const char* name,
3936 Handle<Object> derived,
3937 int argc,
3938 Handle<Object> argv[]) {
3939 Isolate* isolate = proxy->GetIsolate();
3940 Handle<Object> handler(proxy->handler(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003941
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003942 Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
3943 Handle<Object> trap;
3944 ASSIGN_RETURN_ON_EXCEPTION(
3945 isolate, trap,
3946 Object::GetPropertyOrElement(handler, trap_name),
3947 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003948
3949 if (trap->IsUndefined()) {
3950 if (derived.is_null()) {
3951 Handle<Object> args[] = { handler, trap_name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003952 THROW_NEW_ERROR(isolate,
3953 NewTypeError("handler_trap_missing",
3954 HandleVector(args, arraysize(args))),
3955 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003956 }
3957 trap = Handle<Object>(derived);
3958 }
3959
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003960 return Execution::Call(isolate, trap, handler, argc, argv);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003961}
3962
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003963
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003964void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
3965 DCHECK(object->map()->inobject_properties() == map->inobject_properties());
3966 ElementsKind obj_kind = object->map()->elements_kind();
3967 ElementsKind map_kind = map->elements_kind();
3968 if (map_kind != obj_kind) {
3969 ElementsKind to_kind = map_kind;
3970 if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
3971 IsDictionaryElementsKind(obj_kind)) {
3972 to_kind = obj_kind;
John Reck59135872010-11-02 12:39:01 -07003973 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003974 if (IsDictionaryElementsKind(to_kind)) {
3975 NormalizeElements(object);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003976 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003977 TransitionElementsKind(object, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003978 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003979 map = Map::AsElementsKind(map, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003981 JSObject::MigrateToMap(object, map);
3982}
3983
3984
3985void JSObject::MigrateInstance(Handle<JSObject> object) {
3986 Handle<Map> original_map(object->map());
3987 Handle<Map> map = Map::Update(original_map);
3988 map->set_migration_target(true);
3989 MigrateToMap(object, map);
3990 if (FLAG_trace_migration) {
3991 object->PrintInstanceMigration(stdout, *original_map, *map);
3992 }
3993}
3994
3995
3996// static
3997bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
3998 Isolate* isolate = object->GetIsolate();
3999 DisallowDeoptimization no_deoptimization(isolate);
4000 Handle<Map> original_map(object->map(), isolate);
4001 Handle<Map> new_map;
4002 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
4003 return false;
4004 }
4005 JSObject::MigrateToMap(object, new_map);
4006 if (FLAG_trace_migration) {
4007 object->PrintInstanceMigration(stdout, *original_map, object->map());
4008 }
4009 return true;
4010}
4011
4012
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004013void JSObject::WriteToField(int descriptor, Object* value) {
4014 DisallowHeapAllocation no_gc;
4015
4016 DescriptorArray* desc = map()->instance_descriptors();
4017 PropertyDetails details = desc->GetDetails(descriptor);
4018
4019 DCHECK(details.type() == FIELD);
4020
4021 FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
4022 if (details.representation().IsDouble()) {
4023 // Nothing more to be done.
4024 if (value->IsUninitialized()) return;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004025 if (IsUnboxedDoubleField(index)) {
4026 RawFastDoublePropertyAtPut(index, value->Number());
4027 } else {
4028 HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
4029 DCHECK(box->IsMutableHeapNumber());
4030 box->set_value(value->Number());
4031 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004032 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004033 RawFastPropertyAtPut(index, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004034 }
4035}
4036
4037
4038void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
4039 Handle<Object> value,
4040 PropertyAttributes attributes) {
4041 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
4042 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
4043#ifdef DEBUG
4044 uint32_t index;
4045 DCHECK(!object->IsJSProxy());
4046 DCHECK(!name->AsArrayIndex(&index));
4047 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
4048 DCHECK(maybe.has_value);
4049 DCHECK(!it.IsFound());
4050 DCHECK(object->map()->is_extensible() ||
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004051 it.isolate()->IsInternallyUsedPropertyName(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004052#endif
4053 AddDataProperty(&it, value, attributes, STRICT,
4054 CERTAINLY_NOT_STORE_FROM_KEYED).Check();
4055}
4056
4057
4058// Reconfigures a property to a data property with attributes, even if it is not
4059// reconfigurable.
4060MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
4061 Handle<JSObject> object,
4062 Handle<Name> name,
4063 Handle<Object> value,
4064 PropertyAttributes attributes,
4065 ExecutableAccessorInfoHandling handling) {
4066 DCHECK(!value->IsTheHole());
4067 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
4068 bool is_observed = object->map()->is_observed() &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004069 !it.isolate()->IsInternallyUsedPropertyName(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004070 for (; it.IsFound(); it.Next()) {
4071 switch (it.state()) {
4072 case LookupIterator::INTERCEPTOR:
4073 case LookupIterator::JSPROXY:
4074 case LookupIterator::NOT_FOUND:
4075 case LookupIterator::TRANSITION:
4076 UNREACHABLE();
4077
4078 case LookupIterator::ACCESS_CHECK:
4079 if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
4080 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
4081 }
4082 break;
4083
4084 case LookupIterator::ACCESSOR: {
4085 PropertyDetails details = it.property_details();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004086 // Ensure the context isn't changed after calling into accessors.
4087 AssertNoContextChange ncc(it.isolate());
4088
4089 Handle<Object> accessors = it.GetAccessors();
4090
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004091 // Special handling for ExecutableAccessorInfo, which behaves like a
4092 // data property.
4093 if (handling == DONT_FORCE_FIELD &&
4094 accessors->IsExecutableAccessorInfo()) {
4095 Handle<Object> result;
4096 ASSIGN_RETURN_ON_EXCEPTION(
4097 it.isolate(), result,
4098 JSObject::SetPropertyWithAccessor(it.GetReceiver(), it.name(),
4099 value, it.GetHolder<JSObject>(),
4100 accessors, STRICT),
4101 Object);
4102 DCHECK(result->SameValue(*value));
4103
4104 if (details.attributes() == attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004105 return value;
4106 }
4107
4108 // Reconfigure the accessor if attributes mismatch.
4109 Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor(
4110 it.isolate(), Handle<ExecutableAccessorInfo>::cast(accessors));
4111 new_data->set_property_attributes(attributes);
4112 // By clearing the setter we don't have to introduce a lookup to
4113 // the setter, simply make it unavailable to reflect the
4114 // attributes.
4115 if (attributes & READ_ONLY) new_data->clear_setter();
4116 SetPropertyCallback(object, name, new_data, attributes);
4117 if (is_observed) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004118 RETURN_ON_EXCEPTION(
4119 it.isolate(),
4120 EnqueueChangeRecord(object, "reconfigure", name,
4121 it.isolate()->factory()->the_hole_value()),
4122 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004123 }
4124 return value;
4125 }
4126
4127 it.ReconfigureDataProperty(value, attributes);
4128 it.PrepareForDataProperty(value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004129 value = it.WriteDataValue(value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004130
4131 if (is_observed) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004132 RETURN_ON_EXCEPTION(
4133 it.isolate(),
4134 EnqueueChangeRecord(object, "reconfigure", name,
4135 it.isolate()->factory()->the_hole_value()),
4136 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004137 }
4138
Iain Merrick75681382010-08-19 15:07:18 +01004139 return value;
4140 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004141
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004142 case LookupIterator::DATA: {
4143 PropertyDetails details = it.property_details();
4144 Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
4145 // Regular property update if the attributes match.
4146 if (details.attributes() == attributes) {
4147 return SetDataProperty(&it, value);
4148 }
4149 // Reconfigure the data property if the attributes mismatch.
4150 if (is_observed) old_value = it.GetDataValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00004151
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004152 it.ReconfigureDataProperty(value, attributes);
4153 it.PrepareForDataProperty(value);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004154 value = it.WriteDataValue(value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004155
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004156 if (is_observed) {
4157 if (old_value->SameValue(*value)) {
4158 old_value = it.isolate()->factory()->the_hole_value();
4159 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004160 RETURN_ON_EXCEPTION(
4161 it.isolate(),
4162 EnqueueChangeRecord(object, "reconfigure", name, old_value),
4163 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004164 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004165
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004166 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00004167 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004168 }
4169 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004170
4171 return AddDataProperty(&it, value, attributes, STRICT,
4172 CERTAINLY_NOT_STORE_FROM_KEYED);
Steve Blocka7e24c12009-10-30 11:49:00 +00004173}
4174
4175
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004176Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
4177 Handle<JSObject> holder,
4178 Handle<Object> receiver,
4179 Handle<Name> name) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004180 Isolate* isolate = holder->GetIsolate();
4181 HandleScope scope(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01004182
Steve Blocka7e24c12009-10-30 11:49:00 +00004183 // Make sure that the top context does not change when doing
4184 // callbacks or interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004185 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00004186
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004187 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004188 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
4189 return maybe(ABSENT);
4190 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004191 PropertyCallbackArguments args(
4192 isolate, interceptor->data(), *receiver, *holder);
Steve Blocka7e24c12009-10-30 11:49:00 +00004193 if (!interceptor->query()->IsUndefined()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004194 v8::GenericNamedPropertyQueryCallback query =
4195 v8::ToCData<v8::GenericNamedPropertyQueryCallback>(
4196 interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01004197 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004198 ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004199 v8::Handle<v8::Integer> result = args.Call(query, v8::Utils::ToLocal(name));
Steve Blocka7e24c12009-10-30 11:49:00 +00004200 if (!result.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004201 DCHECK(result->IsInt32());
4202 return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
Steve Blocka7e24c12009-10-30 11:49:00 +00004203 }
4204 } else if (!interceptor->getter()->IsUndefined()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004205 v8::GenericNamedPropertyGetterCallback getter =
4206 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
4207 interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01004208 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004209 ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004210 v8::Handle<v8::Value> result = args.Call(getter, v8::Utils::ToLocal(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004211 if (!result.IsEmpty()) return maybe(DONT_ENUM);
Steve Blocka7e24c12009-10-30 11:49:00 +00004212 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004213
4214 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
4215 return maybe(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00004216}
4217
4218
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004219Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
4220 Handle<JSReceiver> object, Handle<Name> name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004221 // Check whether the name is an array index.
4222 uint32_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004223 if (object->IsJSObject() && name->AsArrayIndex(&index)) {
4224 return GetOwnElementAttribute(object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00004225 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004226 LookupIterator it(object, name, LookupIterator::HIDDEN);
4227 return GetPropertyAttributes(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +00004228}
4229
4230
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004231Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
4232 LookupIterator* it) {
4233 for (; it->IsFound(); it->Next()) {
4234 switch (it->state()) {
4235 case LookupIterator::NOT_FOUND:
4236 case LookupIterator::TRANSITION:
4237 UNREACHABLE();
4238 case LookupIterator::JSPROXY:
4239 return JSProxy::GetPropertyAttributesWithHandler(
4240 it->GetHolder<JSProxy>(), it->GetReceiver(), it->name());
4241 case LookupIterator::INTERCEPTOR: {
4242 Maybe<PropertyAttributes> result =
4243 JSObject::GetPropertyAttributesWithInterceptor(
4244 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
4245 if (!result.has_value) return result;
4246 if (result.value != ABSENT) return result;
4247 break;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004248 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004249 case LookupIterator::ACCESS_CHECK:
4250 if (it->HasAccess(v8::ACCESS_HAS)) break;
4251 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
4252 case LookupIterator::ACCESSOR:
4253 case LookupIterator::DATA:
4254 return maybe(it->property_details().attributes());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004255 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004256 }
4257 return maybe(ABSENT);
4258}
4259
4260
4261Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver(
4262 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4263 bool check_prototype) {
4264 Isolate* isolate = object->GetIsolate();
4265
4266 // Check access rights if needed.
4267 if (object->IsAccessCheckNeeded()) {
4268 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004269 return GetElementAttributesWithFailedAccessCheck(isolate, object,
4270 receiver, index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004271 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004272 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004273
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004274 if (object->IsJSGlobalProxy()) {
4275 PrototypeIterator iter(isolate, object);
4276 if (iter.IsAtEnd()) return maybe(ABSENT);
4277 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4278 return JSObject::GetElementAttributeWithReceiver(
4279 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4280 index, check_prototype);
John Reck59135872010-11-02 12:39:01 -07004281 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004282
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004283 // Check for lookup interceptor except when bootstrapping.
4284 if (object->HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4285 return JSObject::GetElementAttributeWithInterceptor(
4286 object, receiver, index, check_prototype);
4287 }
4288
4289 return GetElementAttributeWithoutInterceptor(
4290 object, receiver, index, check_prototype);
4291}
4292
4293
4294Maybe<PropertyAttributes> JSObject::GetElementAttributeWithInterceptor(
4295 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4296 bool check_prototype) {
4297 Isolate* isolate = object->GetIsolate();
4298 HandleScope scope(isolate);
4299
4300 // Make sure that the top context does not change when doing
4301 // callbacks or interceptor calls.
4302 AssertNoContextChange ncc(isolate);
4303
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004304 Maybe<PropertyAttributes> from_interceptor =
4305 GetElementAttributeFromInterceptor(object, receiver, index);
4306 if (!from_interceptor.has_value) return Maybe<PropertyAttributes>();
4307 if (from_interceptor.value != ABSENT) return maybe(from_interceptor.value);
4308
4309 return GetElementAttributeWithoutInterceptor(object, receiver, index,
4310 check_prototype);
4311}
4312
4313
4314Maybe<PropertyAttributes> JSObject::GetElementAttributeFromInterceptor(
4315 Handle<JSObject> object, Handle<Object> receiver, uint32_t index) {
4316 Isolate* isolate = object->GetIsolate();
4317 AssertNoContextChange ncc(isolate);
4318
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004319 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
4320 PropertyCallbackArguments args(
4321 isolate, interceptor->data(), *receiver, *object);
4322 if (!interceptor->query()->IsUndefined()) {
4323 v8::IndexedPropertyQueryCallback query =
4324 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
4325 LOG(isolate,
4326 ApiIndexedPropertyAccess("interceptor-indexed-has", *object, index));
4327 v8::Handle<v8::Integer> result = args.Call(query, index);
4328 if (!result.IsEmpty())
4329 return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
4330 } else if (!interceptor->getter()->IsUndefined()) {
4331 v8::IndexedPropertyGetterCallback getter =
4332 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
4333 LOG(isolate,
4334 ApiIndexedPropertyAccess(
4335 "interceptor-indexed-get-has", *object, index));
4336 v8::Handle<v8::Value> result = args.Call(getter, index);
4337 if (!result.IsEmpty()) return maybe(NONE);
4338 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004339 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
4340 return maybe(ABSENT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004341}
4342
4343
4344Maybe<PropertyAttributes> JSObject::GetElementAttributeWithoutInterceptor(
4345 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4346 bool check_prototype) {
4347 PropertyAttributes attr = object->GetElementsAccessor()->GetAttributes(
4348 receiver, object, index);
4349 if (attr != ABSENT) return maybe(attr);
4350
4351 // Handle [] on String objects.
4352 if (object->IsStringObjectWithCharacterAt(index)) {
4353 return maybe(static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE));
4354 }
4355
4356 if (!check_prototype) return maybe(ABSENT);
4357
4358 PrototypeIterator iter(object->GetIsolate(), object);
4359 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
4360 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
4361 return JSProxy::GetElementAttributeWithHandler(
4362 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4363 index);
4364 }
4365 if (iter.IsAtEnd()) return maybe(ABSENT);
4366 return GetElementAttributeWithReceiver(
4367 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4368 index, true);
4369}
4370
4371
4372Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
4373 Handle<FixedArray> array(
4374 isolate->factory()->NewFixedArray(kEntries, TENURED));
4375 return Handle<NormalizedMapCache>::cast(array);
4376}
4377
4378
4379MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
4380 PropertyNormalizationMode mode) {
4381 DisallowHeapAllocation no_gc;
4382 Object* value = FixedArray::get(GetIndex(fast_map));
4383 if (!value->IsMap() ||
4384 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
4385 return MaybeHandle<Map>();
4386 }
4387 return handle(Map::cast(value));
4388}
4389
4390
4391void NormalizedMapCache::Set(Handle<Map> fast_map,
4392 Handle<Map> normalized_map) {
4393 DisallowHeapAllocation no_gc;
4394 DCHECK(normalized_map->is_dictionary_map());
4395 FixedArray::set(GetIndex(fast_map), *normalized_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004396}
4397
4398
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004399void NormalizedMapCache::Clear() {
4400 int entries = length();
4401 for (int i = 0; i != entries; i++) {
4402 set_undefined(i);
4403 }
4404}
4405
4406
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004407void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
4408 Handle<Name> name,
4409 Handle<Code> code) {
4410 Handle<Map> map(object->map());
4411 Map::UpdateCodeCache(map, name, code);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004412}
4413
4414
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004415void JSObject::NormalizeProperties(Handle<JSObject> object,
4416 PropertyNormalizationMode mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004417 int expected_additional_properties,
4418 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004419 if (!object->HasFastProperties()) return;
4420
4421 Handle<Map> map(object->map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004422 Handle<Map> new_map = Map::Normalize(map, mode, reason);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004423
4424 MigrateFastToSlow(object, new_map, expected_additional_properties);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004425}
4426
4427
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004428void JSObject::MigrateFastToSlow(Handle<JSObject> object,
4429 Handle<Map> new_map,
4430 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004431 // The global object is always normalized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004432 DCHECK(!object->IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01004433 // JSGlobalProxy must never be normalized
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004434 DCHECK(!object->IsJSGlobalProxy());
Steve Block1e0659c2011-05-24 12:43:12 +01004435
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004436 Isolate* isolate = object->GetIsolate();
4437 HandleScope scope(isolate);
4438 Handle<Map> map(object->map());
Steve Block44f0eee2011-05-26 01:26:41 +01004439
Steve Blocka7e24c12009-10-30 11:49:00 +00004440 // Allocate new content.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004441 int real_size = map->NumberOfOwnDescriptors();
4442 int property_count = real_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00004443 if (expected_additional_properties > 0) {
4444 property_count += expected_additional_properties;
4445 } else {
4446 property_count += 2; // Make space for two more properties.
4447 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004448 Handle<NameDictionary> dictionary =
4449 NameDictionary::New(isolate, property_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004450
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004451 Handle<DescriptorArray> descs(map->instance_descriptors());
4452 for (int i = 0; i < real_size; i++) {
4453 PropertyDetails details = descs->GetDetails(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004454 Handle<Name> key(descs->GetKey(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00004455 switch (details.type()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004456 case CONSTANT: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004457 Handle<Object> value(descs->GetConstant(i), isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004458 PropertyDetails d(details.attributes(), FIELD, i + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004459 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00004460 break;
4461 }
4462 case FIELD: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004463 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004464 Handle<Object> value;
4465 if (object->IsUnboxedDoubleField(index)) {
4466 double old_value = object->RawFastDoublePropertyAt(index);
4467 value = isolate->factory()->NewHeapNumber(old_value);
4468 } else {
4469 value = handle(object->RawFastPropertyAt(index), isolate);
4470 if (details.representation().IsDouble()) {
4471 DCHECK(value->IsMutableHeapNumber());
4472 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
4473 value = isolate->factory()->NewHeapNumber(old->value());
4474 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004475 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004476 PropertyDetails d(details.attributes(), FIELD, i + 1);
4477 dictionary = NameDictionary::Add(dictionary, key, value, d);
4478 break;
4479 }
4480 case ACCESSOR_FIELD: {
4481 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4482 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
4483 PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004484 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00004485 break;
4486 }
4487 case CALLBACKS: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004488 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004489 PropertyDetails d(details.attributes(), CALLBACKS, i + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004490 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00004491 break;
4492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004493 }
4494 }
4495
4496 // Copy the next enumeration index from instance descriptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004497 dictionary->SetNextEnumerationIndex(real_size + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004498
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004499 // From here on we cannot fail and we shouldn't GC anymore.
4500 DisallowHeapAllocation no_allocation;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004501
4502 // Resize the object in the heap if necessary.
4503 int new_instance_size = new_map->instance_size();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004504 int instance_size_delta = map->instance_size() - new_instance_size;
4505 DCHECK(instance_size_delta >= 0);
4506
4507 if (instance_size_delta > 0) {
4508 Heap* heap = isolate->heap();
4509 heap->CreateFillerObjectAt(object->address() + new_instance_size,
4510 instance_size_delta);
4511 heap->AdjustLiveBytes(object->address(), -instance_size_delta,
4512 Heap::FROM_MUTATOR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004513 }
4514
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004515 // We are storing the new map using release store after creating a filler for
4516 // the left-over space to avoid races with the sweeper thread.
4517 object->synchronized_set_map(*new_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004518
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004519 object->set_properties(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00004520
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004521 // Ensure that in-object space of slow-mode object does not contain random
4522 // garbage.
4523 int inobject_properties = new_map->inobject_properties();
4524 for (int i = 0; i < inobject_properties; i++) {
4525 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
4526 object->RawFastPropertyAtPut(index, Smi::FromInt(0));
4527 }
4528
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004529 isolate->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00004530
4531#ifdef DEBUG
4532 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004533 OFStream os(stdout);
4534 os << "Object properties have been normalized:\n";
4535 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00004536 }
4537#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004538}
4539
4540
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004541void JSObject::MigrateSlowToFast(Handle<JSObject> object,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004542 int unused_property_fields,
4543 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004544 if (object->HasFastProperties()) return;
4545 DCHECK(!object->IsGlobalObject());
4546 Isolate* isolate = object->GetIsolate();
4547 Factory* factory = isolate->factory();
4548 Handle<NameDictionary> dictionary(object->property_dictionary());
4549
4550 // Make sure we preserve dictionary representation if there are too many
4551 // descriptors.
4552 int number_of_elements = dictionary->NumberOfElements();
4553 if (number_of_elements > kMaxNumberOfDescriptors) return;
4554
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004555 Handle<FixedArray> iteration_order;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004556 if (number_of_elements != dictionary->NextEnumerationIndex()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004557 iteration_order =
4558 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
4559 } else {
4560 iteration_order = NameDictionary::BuildIterationIndicesArray(dictionary);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004561 }
4562
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004563 int instance_descriptor_length = iteration_order->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004564 int number_of_fields = 0;
4565
4566 // Compute the length of the instance descriptor.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004567 for (int i = 0; i < instance_descriptor_length; i++) {
4568 int index = Smi::cast(iteration_order->get(i))->value();
4569 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
4570
4571 Object* value = dictionary->ValueAt(index);
4572 PropertyType type = dictionary->DetailsAt(index).type();
4573 if (type == FIELD && !value->IsJSFunction()) {
4574 number_of_fields += 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004575 }
4576 }
4577
4578 int inobject_props = object->map()->inobject_properties();
4579
4580 // Allocate new map.
4581 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
4582 new_map->set_dictionary_map(false);
4583
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004584#if TRACE_MAPS
4585 if (FLAG_trace_maps) {
4586 PrintF("[TraceMaps: SlowToFast from= %p to= %p reason= %s ]\n",
4587 reinterpret_cast<void*>(object->map()),
4588 reinterpret_cast<void*>(*new_map), reason);
4589 }
4590#endif
4591
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004592 if (instance_descriptor_length == 0) {
4593 DisallowHeapAllocation no_gc;
4594 DCHECK_LE(unused_property_fields, inobject_props);
4595 // Transform the object.
4596 new_map->set_unused_property_fields(inobject_props);
4597 object->synchronized_set_map(*new_map);
4598 object->set_properties(isolate->heap()->empty_fixed_array());
4599 // Check that it really works.
4600 DCHECK(object->HasFastProperties());
4601 return;
4602 }
4603
4604 // Allocate the instance descriptor.
4605 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
4606 isolate, instance_descriptor_length);
4607
4608 int number_of_allocated_fields =
4609 number_of_fields + unused_property_fields - inobject_props;
4610 if (number_of_allocated_fields < 0) {
4611 // There is enough inobject space for all fields (including unused).
4612 number_of_allocated_fields = 0;
4613 unused_property_fields = inobject_props - number_of_fields;
4614 }
4615
4616 // Allocate the fixed array for the fields.
4617 Handle<FixedArray> fields = factory->NewFixedArray(
4618 number_of_allocated_fields);
4619
4620 // Fill in the instance descriptor and the fields.
4621 int current_offset = 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004622 for (int i = 0; i < instance_descriptor_length; i++) {
4623 int index = Smi::cast(iteration_order->get(i))->value();
4624 Object* k = dictionary->KeyAt(index);
4625 DCHECK(dictionary->IsKey(k));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004626
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004627 Object* value = dictionary->ValueAt(index);
4628 Handle<Name> key;
4629 if (k->IsSymbol()) {
4630 key = handle(Symbol::cast(k));
4631 } else {
4632 // Ensure the key is a unique name before writing into the
4633 // instance descriptor.
4634 key = factory->InternalizeString(handle(String::cast(k)));
4635 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004636
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004637 PropertyDetails details = dictionary->DetailsAt(index);
4638 int enumeration_index = details.dictionary_index();
4639 PropertyType type = details.type();
4640
4641 if (value->IsJSFunction()) {
4642 ConstantDescriptor d(key, handle(value, isolate), details.attributes());
4643 descriptors->Set(enumeration_index - 1, &d);
4644 } else if (type == FIELD) {
4645 if (current_offset < inobject_props) {
4646 object->InObjectPropertyAtPut(current_offset, value,
4647 UPDATE_WRITE_BARRIER);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004648 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004649 int offset = current_offset - inobject_props;
4650 fields->set(offset, value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004651 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004652 FieldDescriptor d(key, current_offset, details.attributes(),
4653 // TODO(verwaest): value->OptimalRepresentation();
4654 Representation::Tagged());
4655 current_offset += d.GetDetails().field_width_in_words();
4656 descriptors->Set(enumeration_index - 1, &d);
4657 } else if (type == CALLBACKS) {
4658 CallbacksDescriptor d(key, handle(value, isolate), details.attributes());
4659 descriptors->Set(enumeration_index - 1, &d);
4660 } else {
4661 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004662 }
4663 }
4664 DCHECK(current_offset == number_of_fields);
4665
4666 descriptors->Sort();
4667
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004668 Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
4669 new_map, descriptors, descriptors->number_of_descriptors());
4670
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004671 DisallowHeapAllocation no_gc;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004672 new_map->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004673 new_map->set_unused_property_fields(unused_property_fields);
4674
4675 // Transform the object.
4676 object->synchronized_set_map(*new_map);
4677
4678 object->set_properties(*fields);
4679 DCHECK(object->IsJSObject());
4680
4681 // Check that it really works.
4682 DCHECK(object->HasFastProperties());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004683}
4684
4685
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004686void JSObject::ResetElements(Handle<JSObject> object) {
4687 Isolate* isolate = object->GetIsolate();
4688 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
4689 if (object->map()->has_dictionary_elements()) {
4690 Handle<SeededNumberDictionary> new_elements =
4691 SeededNumberDictionary::New(isolate, 0);
4692 object->set_elements(*new_elements);
4693 } else {
4694 object->set_elements(object->map()->GetInitialElements());
4695 }
4696}
4697
4698
4699static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
4700 Handle<FixedArrayBase> array,
4701 int length,
4702 Handle<SeededNumberDictionary> dictionary) {
4703 Isolate* isolate = array->GetIsolate();
4704 Factory* factory = isolate->factory();
4705 bool has_double_elements = array->IsFixedDoubleArray();
4706 for (int i = 0; i < length; i++) {
4707 Handle<Object> value;
4708 if (has_double_elements) {
4709 Handle<FixedDoubleArray> double_array =
4710 Handle<FixedDoubleArray>::cast(array);
4711 if (double_array->is_the_hole(i)) {
4712 value = factory->the_hole_value();
4713 } else {
4714 value = factory->NewHeapNumber(double_array->get_scalar(i));
4715 }
4716 } else {
4717 value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
4718 }
4719 if (!value->IsTheHole()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04004720 PropertyDetails details(NONE, FIELD, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004721 dictionary =
4722 SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
4723 }
4724 }
4725 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00004726}
4727
4728
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004729Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4730 Handle<JSObject> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004731 DCHECK(!object->HasExternalArrayElements() &&
4732 !object->HasFixedTypedArrayElements());
4733 Isolate* isolate = object->GetIsolate();
Steve Block8defd9f2010-07-08 12:39:36 +01004734
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004735 // Find the backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004736 Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004737 bool is_arguments =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004738 (array->map() == isolate->heap()->sloppy_arguments_elements_map());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004739 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004740 array = handle(FixedArrayBase::cast(
4741 Handle<FixedArray>::cast(array)->get(1)));
John Reck59135872010-11-02 12:39:01 -07004742 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004743 if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array);
Steve Blocka7e24c12009-10-30 11:49:00 +00004744
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004745 DCHECK(object->HasFastSmiOrObjectElements() ||
4746 object->HasFastDoubleElements() ||
4747 object->HasFastArgumentsElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004748 // Compute the effective length and allocate a new backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004749 int length = object->IsJSArray()
4750 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004751 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004752 int old_capacity = 0;
4753 int used_elements = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004754 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements);
4755 Handle<SeededNumberDictionary> dictionary =
4756 SeededNumberDictionary::New(isolate, used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004757
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004758 dictionary = CopyFastElementsToDictionary(array, length, dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00004759
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004760 // Switch to using the dictionary as the backing storage for elements.
4761 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004762 FixedArray::cast(object->elements())->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004763 } else {
4764 // Set the new map first to satify the elements type assert in
4765 // set_elements().
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004766 Handle<Map> new_map =
4767 JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS);
4768
4769 JSObject::MigrateToMap(object, new_map);
4770 object->set_elements(*dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004771 }
4772
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004773 isolate->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00004774
4775#ifdef DEBUG
4776 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004777 OFStream os(stdout);
4778 os << "Object elements have been normalized:\n";
4779 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00004780 }
4781#endif
4782
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004783 DCHECK(object->HasDictionaryElements() ||
4784 object->HasDictionaryArgumentsElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004785 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00004786}
4787
4788
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004789static Smi* GenerateIdentityHash(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004790 int hash_value;
4791 int attempts = 0;
4792 do {
4793 // Generate a random 32-bit hash value but limit range to fit
4794 // within a smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004795 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004796 attempts++;
4797 } while (hash_value == 0 && attempts < 30);
4798 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
4799
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004800 return Smi::FromInt(hash_value);
4801}
4802
4803
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004804void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
4805 DCHECK(!object->IsJSGlobalProxy());
4806 Isolate* isolate = object->GetIsolate();
4807 SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004808}
4809
4810
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004811template<typename ProxyType>
4812static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
4813 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004814
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004815 Handle<Object> maybe_hash(proxy->hash(), isolate);
4816 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004817
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004818 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4819 proxy->set_hash(*hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004820 return hash;
4821}
4822
4823
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004824Object* JSObject::GetIdentityHash() {
4825 DisallowHeapAllocation no_gc;
4826 Isolate* isolate = GetIsolate();
4827 if (IsJSGlobalProxy()) {
4828 return JSGlobalProxy::cast(this)->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004829 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004830 Object* stored_value =
4831 GetHiddenProperty(isolate->factory()->identity_hash_string());
4832 return stored_value->IsSmi()
4833 ? stored_value
4834 : isolate->heap()->undefined_value();
4835}
4836
4837
4838Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
4839 if (object->IsJSGlobalProxy()) {
4840 return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
4841 }
4842
4843 Isolate* isolate = object->GetIsolate();
4844
4845 Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
4846 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
4847
4848 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4849 SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004850 return hash;
4851}
4852
4853
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004854Object* JSProxy::GetIdentityHash() {
4855 return this->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004856}
4857
4858
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004859Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
4860 return GetOrCreateIdentityHashHelper(proxy);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004861}
4862
4863
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004864Object* JSObject::GetHiddenProperty(Handle<Name> key) {
4865 DisallowHeapAllocation no_gc;
4866 DCHECK(key->IsUniqueName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004867 if (IsJSGlobalProxy()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004868 // JSGlobalProxies store their hash internally.
4869 DCHECK(*key != GetHeap()->identity_hash_string());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004870 // For a proxy, use the prototype as target object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004871 PrototypeIterator iter(GetIsolate(), this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004872 // If the proxy is detached, return undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004873 if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
4874 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
4875 return JSObject::cast(iter.GetCurrent())->GetHiddenProperty(key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004876 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004877 DCHECK(!IsJSGlobalProxy());
4878 Object* inline_value = GetHiddenPropertiesHashTable();
4879
4880 if (inline_value->IsSmi()) {
4881 // Handle inline-stored identity hash.
4882 if (*key == GetHeap()->identity_hash_string()) {
4883 return inline_value;
4884 } else {
4885 return GetHeap()->the_hole_value();
4886 }
4887 }
4888
4889 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
4890
4891 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4892 Object* entry = hashtable->Lookup(key);
4893 return entry;
4894}
4895
4896
4897Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
4898 Handle<Name> key,
4899 Handle<Object> value) {
4900 Isolate* isolate = object->GetIsolate();
4901
4902 DCHECK(key->IsUniqueName());
4903 if (object->IsJSGlobalProxy()) {
4904 // JSGlobalProxies store their hash internally.
4905 DCHECK(*key != *isolate->factory()->identity_hash_string());
4906 // For a proxy, use the prototype as target object.
4907 PrototypeIterator iter(isolate, object);
4908 // If the proxy is detached, return undefined.
4909 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
4910 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4911 return SetHiddenProperty(
4912 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key,
4913 value);
4914 }
4915 DCHECK(!object->IsJSGlobalProxy());
4916
4917 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
4918
4919 // If there is no backing store yet, store the identity hash inline.
4920 if (value->IsSmi() &&
4921 *key == *isolate->factory()->identity_hash_string() &&
4922 (inline_value->IsUndefined() || inline_value->IsSmi())) {
4923 return JSObject::SetHiddenPropertiesHashTable(object, value);
4924 }
4925
4926 Handle<ObjectHashTable> hashtable =
4927 GetOrCreateHiddenPropertiesHashtable(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004928
4929 // If it was found, check if the key is already in the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004930 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
4931 value);
4932 if (*new_table != *hashtable) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004933 // If adding the key expanded the dictionary (i.e., Add returned a new
4934 // dictionary), store it back to the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004935 SetHiddenPropertiesHashTable(object, new_table);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004936 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004937
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004938 // Return this to mark success.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004939 return object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004940}
4941
4942
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004943void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
4944 Isolate* isolate = object->GetIsolate();
4945 DCHECK(key->IsUniqueName());
4946
4947 if (object->IsJSGlobalProxy()) {
4948 PrototypeIterator iter(isolate, object);
4949 if (iter.IsAtEnd()) return;
4950 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4951 return DeleteHiddenProperty(
4952 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004953 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004954
4955 Object* inline_value = object->GetHiddenPropertiesHashTable();
4956
4957 // We never delete (inline-stored) identity hashes.
4958 DCHECK(*key != *isolate->factory()->identity_hash_string());
4959 if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
4960
4961 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
4962 bool was_present = false;
4963 ObjectHashTable::Remove(hashtable, key, &was_present);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004964}
4965
4966
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004967bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
4968 Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
4969 LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
4970 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
4971 // Cannot get an exception since the hidden_string isn't accessible to JS.
4972 DCHECK(maybe.has_value);
4973 return maybe.value != ABSENT;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004974}
4975
4976
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004977Object* JSObject::GetHiddenPropertiesHashTable() {
4978 DCHECK(!IsJSGlobalProxy());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004979 if (HasFastProperties()) {
4980 // If the object has fast properties, check whether the first slot
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004981 // in the descriptor array matches the hidden string. Since the
4982 // hidden strings hash code is zero (and no other name has hash
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004983 // code zero) it will always occupy the first entry if present.
4984 DescriptorArray* descriptors = this->map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004985 if (descriptors->number_of_descriptors() > 0) {
4986 int sorted_index = descriptors->GetSortedKeyIndex(0);
4987 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
4988 sorted_index < map()->NumberOfOwnDescriptors()) {
4989 DCHECK(descriptors->GetType(sorted_index) == FIELD);
4990 DCHECK(descriptors->GetDetails(sorted_index).representation().
4991 IsCompatibleForLoad(Representation::Tagged()));
4992 FieldIndex index = FieldIndex::ForDescriptor(this->map(),
4993 sorted_index);
4994 return this->RawFastPropertyAt(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004995 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004996 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004997 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004998 } else {
4999 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005000 }
5001 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005002 Isolate* isolate = GetIsolate();
5003 LookupIterator it(handle(this), isolate->factory()->hidden_string(),
5004 LookupIterator::OWN_SKIP_INTERCEPTOR);
5005 // Access check is always skipped for the hidden string anyways.
5006 return *GetDataProperty(&it);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005007 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005008}
5009
5010Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
5011 Handle<JSObject> object) {
5012 Isolate* isolate = object->GetIsolate();
5013
5014 static const int kInitialCapacity = 4;
5015 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
5016 if (inline_value->IsHashTable()) {
5017 return Handle<ObjectHashTable>::cast(inline_value);
5018 }
5019
5020 Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
5021 isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
5022
5023 if (inline_value->IsSmi()) {
5024 // We were storing the identity hash inline and now allocated an actual
5025 // dictionary. Put the identity hash into the new dictionary.
5026 hashtable = ObjectHashTable::Put(hashtable,
5027 isolate->factory()->identity_hash_string(),
5028 inline_value);
5029 }
5030
5031 SetHiddenPropertiesHashTable(object, hashtable);
5032 return hashtable;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005033}
5034
5035
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005036Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
5037 Handle<Object> value) {
5038 DCHECK(!object->IsJSGlobalProxy());
5039 Isolate* isolate = object->GetIsolate();
5040 Handle<Name> name = isolate->factory()->hidden_string();
5041 SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
5042 return object;
5043}
5044
5045
5046MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
5047 Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name) {
5048 Isolate* isolate = holder->GetIsolate();
5049
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005050 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005051 if (interceptor->deleter()->IsUndefined() ||
5052 (name->IsSymbol() && !interceptor->can_intercept_symbols())) {
5053 return MaybeHandle<Object>();
5054 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005055
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005056 v8::GenericNamedPropertyDeleterCallback deleter =
5057 v8::ToCData<v8::GenericNamedPropertyDeleterCallback>(
5058 interceptor->deleter());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005059 LOG(isolate,
5060 ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name));
5061 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
5062 *holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005063 v8::Handle<v8::Boolean> result = args.Call(deleter, v8::Utils::ToLocal(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005064 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5065 if (result.IsEmpty()) return MaybeHandle<Object>();
5066
5067 DCHECK(result->IsBoolean());
5068 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5069 result_internal->VerifyApiCallResultType();
5070 // Rebox CustomArguments::kReturnValueOffset before returning.
5071 return handle(*result_internal, isolate);
5072}
5073
5074
5075MaybeHandle<Object> JSObject::DeleteElementWithInterceptor(
5076 Handle<JSObject> object,
5077 uint32_t index) {
5078 Isolate* isolate = object->GetIsolate();
5079 Factory* factory = isolate->factory();
5080
5081 // Make sure that the top context does not change when doing
5082 // callbacks or interceptor calls.
5083 AssertNoContextChange ncc(isolate);
5084
5085 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
5086 if (interceptor->deleter()->IsUndefined()) return factory->false_value();
5087 v8::IndexedPropertyDeleterCallback deleter =
5088 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5089 LOG(isolate,
5090 ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
5091 PropertyCallbackArguments args(
5092 isolate, interceptor->data(), *object, *object);
5093 v8::Handle<v8::Boolean> result = args.Call(deleter, index);
5094 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5095 if (!result.IsEmpty()) {
5096 DCHECK(result->IsBoolean());
5097 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5098 result_internal->VerifyApiCallResultType();
5099 // Rebox CustomArguments::kReturnValueOffset before returning.
5100 return handle(*result_internal, isolate);
5101 }
5102 MaybeHandle<Object> delete_result = object->GetElementsAccessor()->Delete(
5103 object, index, NORMAL_DELETION);
5104 return delete_result;
5105}
5106
5107
5108MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
5109 uint32_t index,
5110 DeleteMode mode) {
5111 Isolate* isolate = object->GetIsolate();
5112 Factory* factory = isolate->factory();
5113
5114 // Check access rights if needed.
5115 if (object->IsAccessCheckNeeded() &&
5116 !isolate->MayIndexedAccess(object, index, v8::ACCESS_DELETE)) {
5117 isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE);
5118 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5119 return factory->false_value();
5120 }
5121
5122 if (object->IsStringObjectWithCharacterAt(index)) {
5123 if (mode == STRICT_DELETION) {
5124 // Deleting a non-configurable property in strict mode.
5125 Handle<Object> name = factory->NewNumberFromUint(index);
5126 Handle<Object> args[2] = { name, object };
5127 THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
5128 HandleVector(args, 2)),
5129 Object);
5130 }
5131 return factory->false_value();
5132 }
5133
5134 if (object->IsJSGlobalProxy()) {
5135 PrototypeIterator iter(isolate, object);
5136 if (iter.IsAtEnd()) return factory->false_value();
5137 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
5138 return DeleteElement(
5139 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
5140 mode);
5141 }
5142
5143 Handle<Object> old_value;
5144 bool should_enqueue_change_record = false;
5145 if (object->map()->is_observed()) {
5146 Maybe<bool> maybe = HasOwnElement(object, index);
5147 if (!maybe.has_value) return MaybeHandle<Object>();
5148 should_enqueue_change_record = maybe.value;
5149 if (should_enqueue_change_record) {
5150 if (!GetOwnElementAccessorPair(object, index).is_null()) {
5151 old_value = Handle<Object>::cast(factory->the_hole_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005152 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005153 old_value = Object::GetElement(
5154 isolate, object, index).ToHandleChecked();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005155 }
5156 }
5157 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005158
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005159 // Skip interceptor if forcing deletion.
5160 MaybeHandle<Object> maybe_result;
5161 if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
5162 maybe_result = DeleteElementWithInterceptor(object, index);
5163 } else {
5164 maybe_result = object->GetElementsAccessor()->Delete(object, index, mode);
John Reck59135872010-11-02 12:39:01 -07005165 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005166 Handle<Object> result;
5167 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
Steve Blocka7e24c12009-10-30 11:49:00 +00005168
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005169 if (should_enqueue_change_record) {
5170 Maybe<bool> maybe = HasOwnElement(object, index);
5171 if (!maybe.has_value) return MaybeHandle<Object>();
5172 if (!maybe.value) {
5173 Handle<String> name = factory->Uint32ToString(index);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005174 RETURN_ON_EXCEPTION(
5175 isolate, EnqueueChangeRecord(object, "delete", name, old_value),
5176 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +00005177 }
5178 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005179
5180 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005181}
5182
5183
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005184MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
5185 Handle<Name> name,
5186 DeleteMode delete_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005187 // ECMA-262, 3rd, 8.6.2.5
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005188 DCHECK(name->IsName());
Steve Blocka7e24c12009-10-30 11:49:00 +00005189
5190 uint32_t index = 0;
5191 if (name->AsArrayIndex(&index)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005192 return DeleteElement(object, index, delete_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00005193 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005194
5195 // Skip interceptors on FORCE_DELETION.
5196 LookupIterator::Configuration config =
5197 delete_mode == FORCE_DELETION ? LookupIterator::HIDDEN_SKIP_INTERCEPTOR
5198 : LookupIterator::HIDDEN;
5199
5200 LookupIterator it(object, name, config);
5201
5202 bool is_observed = object->map()->is_observed() &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005203 !it.isolate()->IsInternallyUsedPropertyName(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005204 Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
5205
5206 for (; it.IsFound(); it.Next()) {
5207 switch (it.state()) {
5208 case LookupIterator::JSPROXY:
5209 case LookupIterator::NOT_FOUND:
5210 case LookupIterator::TRANSITION:
5211 UNREACHABLE();
5212 case LookupIterator::ACCESS_CHECK:
5213 if (it.HasAccess(v8::ACCESS_DELETE)) break;
5214 it.isolate()->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
5215 v8::ACCESS_DELETE);
5216 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it.isolate(), Object);
5217 return it.isolate()->factory()->false_value();
5218 case LookupIterator::INTERCEPTOR: {
5219 MaybeHandle<Object> maybe_result =
5220 JSObject::DeletePropertyWithInterceptor(it.GetHolder<JSObject>(),
5221 object, it.name());
5222 // Delete with interceptor succeeded. Return result.
5223 if (!maybe_result.is_null()) return maybe_result;
5224 // An exception was thrown in the interceptor. Propagate.
5225 if (it.isolate()->has_pending_exception()) return maybe_result;
5226 break;
5227 }
5228 case LookupIterator::DATA:
5229 if (is_observed) {
5230 old_value = it.GetDataValue();
5231 }
5232 // Fall through.
5233 case LookupIterator::ACCESSOR: {
5234 if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
5235 // Fail if the property is not configurable.
5236 if (delete_mode == STRICT_DELETION) {
5237 Handle<Object> args[2] = {name, object};
5238 THROW_NEW_ERROR(it.isolate(),
5239 NewTypeError("strict_delete_property",
5240 HandleVector(args, arraysize(args))),
5241 Object);
5242 }
5243 return it.isolate()->factory()->false_value();
5244 }
5245
5246 PropertyNormalizationMode mode = object->map()->is_prototype_map()
5247 ? KEEP_INOBJECT_PROPERTIES
5248 : CLEAR_INOBJECT_PROPERTIES;
5249 Handle<JSObject> holder = it.GetHolder<JSObject>();
5250 // TODO(verwaest): Remove this temporary compatibility hack when blink
5251 // tests are updated.
5252 if (!holder.is_identical_to(object) &&
5253 !(object->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
5254 return it.isolate()->factory()->true_value();
5255 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005256 NormalizeProperties(holder, mode, 0, "DeletingProperty");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005257 Handle<Object> result =
5258 DeleteNormalizedProperty(holder, name, delete_mode);
5259 ReoptimizeIfPrototype(holder);
5260
5261 if (is_observed) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005262 RETURN_ON_EXCEPTION(
5263 it.isolate(),
5264 EnqueueChangeRecord(object, "delete", name, old_value), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005265 }
5266
5267 return result;
5268 }
5269 }
5270 }
5271
5272 return it.isolate()->factory()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00005273}
5274
5275
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005276MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
5277 uint32_t index,
5278 DeleteMode mode) {
5279 if (object->IsJSProxy()) {
5280 return JSProxy::DeleteElementWithHandler(
5281 Handle<JSProxy>::cast(object), index, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005282 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005283 return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005284}
5285
5286
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005287MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
5288 Handle<Name> name,
5289 DeleteMode mode) {
5290 if (object->IsJSProxy()) {
5291 return JSProxy::DeletePropertyWithHandler(
5292 Handle<JSProxy>::cast(object), name, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005293 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005294 return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005295}
5296
5297
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005298bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5299 ElementsKind kind,
5300 Object* object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005301 DCHECK(IsFastObjectElementsKind(kind) ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005302 kind == DICTIONARY_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005303 if (IsFastObjectElementsKind(kind)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005304 int length = IsJSArray()
5305 ? Smi::cast(JSArray::cast(this)->length())->value()
5306 : elements->length();
5307 for (int i = 0; i < length; ++i) {
5308 Object* element = elements->get(i);
5309 if (!element->IsTheHole() && element == object) return true;
5310 }
5311 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00005312 Object* key =
5313 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005314 if (!key->IsUndefined()) return true;
5315 }
5316 return false;
5317}
5318
5319
Steve Blocka7e24c12009-10-30 11:49:00 +00005320// Check whether this object references another object.
5321bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01005322 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005323 Heap* heap = GetHeap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005324 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +00005325
5326 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01005327 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005328 return true;
5329 }
5330
5331 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01005332 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005333 return true;
5334 }
5335
5336 // Check if the object is among the named properties.
5337 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01005338 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005339 return true;
5340 }
5341
5342 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005343 ElementsKind kind = GetElementsKind();
5344 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005345 // Raw pixels and external arrays do not reference other
5346 // objects.
5347#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
5348 case EXTERNAL_##TYPE##_ELEMENTS: \
5349 case TYPE##_ELEMENTS: \
Steve Blocka7e24c12009-10-30 11:49:00 +00005350 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005351
5352 TYPED_ARRAYS(TYPED_ARRAY_CASE)
5353#undef TYPED_ARRAY_CASE
5354
5355 case FAST_DOUBLE_ELEMENTS:
5356 case FAST_HOLEY_DOUBLE_ELEMENTS:
5357 break;
5358 case FAST_SMI_ELEMENTS:
5359 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005360 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005361 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005362 case FAST_HOLEY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00005363 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005364 FixedArray* elements = FixedArray::cast(this->elements());
5365 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00005366 break;
5367 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005368 case SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005369 FixedArray* parameter_map = FixedArray::cast(elements());
5370 // Check the mapped parameters.
5371 int length = parameter_map->length();
5372 for (int i = 2; i < length; ++i) {
5373 Object* value = parameter_map->get(i);
5374 if (!value->IsTheHole() && value == obj) return true;
5375 }
5376 // Check the arguments.
5377 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005378 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5379 FAST_HOLEY_ELEMENTS;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005380 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00005381 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005382 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005383 }
5384
Steve Block6ded16b2010-05-10 14:33:55 +01005385 // For functions check the context.
5386 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005387 // Get the constructor function for arguments array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005388 Map* arguments_map =
5389 heap->isolate()->context()->native_context()->sloppy_arguments_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00005390 JSFunction* arguments_function =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005391 JSFunction::cast(arguments_map->constructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00005392
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005393 // Get the context and don't check if it is the native context.
Steve Blocka7e24c12009-10-30 11:49:00 +00005394 JSFunction* f = JSFunction::cast(this);
5395 Context* context = f->context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005396 if (context->IsNativeContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005397 return false;
5398 }
5399
5400 // Check the non-special context slots.
5401 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5402 // Only check JS objects.
5403 if (context->get(i)->IsJSObject()) {
5404 JSObject* ctxobj = JSObject::cast(context->get(i));
5405 // If it is an arguments array check the content.
5406 if (ctxobj->map()->constructor() == arguments_function) {
5407 if (ctxobj->ReferencesObject(obj)) {
5408 return true;
5409 }
5410 } else if (ctxobj == obj) {
5411 return true;
5412 }
5413 }
5414 }
5415
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005416 // Check the context extension (if any) if it can have references.
5417 if (context->has_extension() && !context->IsCatchContext()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005418 // With harmony scoping, a JSFunction may have a global context.
5419 // TODO(mvstanton): walk into the ScopeInfo.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005420 if (FLAG_harmony_scoping && context->IsScriptContext()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005421 return false;
5422 }
5423
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005424 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00005425 }
5426 }
5427
5428 // No references to object.
5429 return false;
5430}
5431
5432
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005433MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005434 if (!object->map()->is_extensible()) return object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005435
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005436 if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) {
5437 return PreventExtensionsWithTransition<NONE>(object);
5438 }
5439
5440 Isolate* isolate = object->GetIsolate();
5441
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005442 if (object->IsAccessCheckNeeded() &&
5443 !isolate->MayNamedAccess(
5444 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5445 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5446 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5447 return isolate->factory()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005448 }
5449
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005450 if (object->IsJSGlobalProxy()) {
5451 PrototypeIterator iter(isolate, object);
5452 if (iter.IsAtEnd()) return object;
5453 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
5454 return PreventExtensions(
5455 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
Steve Block1e0659c2011-05-24 12:43:12 +01005456 }
5457
Ben Murdoch257744e2011-11-30 15:57:28 +00005458 // It's not possible to seal objects with external array elements
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005459 if (object->HasExternalArrayElements() ||
5460 object->HasFixedTypedArrayElements()) {
5461 THROW_NEW_ERROR(isolate,
5462 NewTypeError("cant_prevent_ext_external_array_elements",
5463 HandleVector(&object, 1)),
5464 Object);
Ben Murdoch257744e2011-11-30 15:57:28 +00005465 }
5466
Steve Block8defd9f2010-07-08 12:39:36 +01005467 // If there are fast elements we normalize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005468 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
5469 DCHECK(object->HasDictionaryElements() ||
5470 object->HasDictionaryArgumentsElements());
5471
Steve Block8defd9f2010-07-08 12:39:36 +01005472 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005473 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01005474
5475 // Do a map transition, other objects with this map may still
5476 // be extensible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005477 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005478 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005479
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005480 new_map->set_is_extensible(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005481 JSObject::MigrateToMap(object, new_map);
5482 DCHECK(!object->map()->is_extensible());
5483
5484 if (object->map()->is_observed()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005485 RETURN_ON_EXCEPTION(
5486 isolate,
5487 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
5488 isolate->factory()->the_hole_value()),
5489 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005490 }
5491 return object;
5492}
5493
5494
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005495Handle<SeededNumberDictionary> JSObject::GetNormalizedElementDictionary(
5496 Handle<JSObject> object) {
5497 DCHECK(!object->elements()->IsDictionary());
5498 Isolate* isolate = object->GetIsolate();
5499 int length = object->IsJSArray()
5500 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5501 : object->elements()->length();
5502 if (length > 0) {
5503 int capacity = 0;
5504 int used = 0;
5505 object->GetElementsCapacityAndUsage(&capacity, &used);
5506 Handle<SeededNumberDictionary> new_element_dictionary =
5507 SeededNumberDictionary::New(isolate, used);
5508
5509 // Move elements to a dictionary; avoid calling NormalizeElements to avoid
5510 // unnecessary transitions.
5511 return CopyFastElementsToDictionary(handle(object->elements()), length,
5512 new_element_dictionary);
5513 }
5514 // No existing elements, use a pre-allocated empty backing store
5515 return isolate->factory()->empty_slow_element_dictionary();
5516}
5517
5518
5519template <typename Dictionary>
5520static void ApplyAttributesToDictionary(Dictionary* dictionary,
5521 const PropertyAttributes attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005522 int capacity = dictionary->Capacity();
5523 for (int i = 0; i < capacity; i++) {
5524 Object* k = dictionary->KeyAt(i);
5525 if (dictionary->IsKey(k) &&
5526 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
5527 PropertyDetails details = dictionary->DetailsAt(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005528 int attrs = attributes;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005529 // READ_ONLY is an invalid attribute for JS setters/getters.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005530 if ((attributes & READ_ONLY) && details.type() == CALLBACKS) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005531 Object* v = dictionary->ValueAt(i);
5532 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005533 if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005534 }
5535 details = details.CopyAddAttributes(
5536 static_cast<PropertyAttributes>(attrs));
5537 dictionary->DetailsAtPut(i, details);
5538 }
5539 }
5540}
5541
5542
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005543template <PropertyAttributes attrs>
5544MaybeHandle<Object> JSObject::PreventExtensionsWithTransition(
5545 Handle<JSObject> object) {
5546 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN);
5547
5548 // Sealing/freezing sloppy arguments should be handled elsewhere.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005549 DCHECK(!object->HasSloppyArgumentsElements());
5550 DCHECK(!object->map()->is_observed());
5551
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005552 Isolate* isolate = object->GetIsolate();
5553 if (object->IsAccessCheckNeeded() &&
5554 !isolate->MayNamedAccess(
5555 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5556 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5557 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5558 return isolate->factory()->false_value();
5559 }
5560
5561 if (object->IsJSGlobalProxy()) {
5562 PrototypeIterator iter(isolate, object);
5563 if (iter.IsAtEnd()) return object;
5564 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005565 return PreventExtensionsWithTransition<attrs>(
5566 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005567 }
5568
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005569 // It's not possible to seal or freeze objects with external array elements
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005570 if (object->HasExternalArrayElements() ||
5571 object->HasFixedTypedArrayElements()) {
5572 THROW_NEW_ERROR(isolate,
5573 NewTypeError("cant_prevent_ext_external_array_elements",
5574 HandleVector(&object, 1)),
5575 Object);
5576 }
5577
5578 Handle<SeededNumberDictionary> new_element_dictionary;
5579 if (!object->elements()->IsDictionary()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005580 new_element_dictionary = GetNormalizedElementDictionary(object);
5581 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005582
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005583 Handle<Symbol> transition_marker;
5584 if (attrs == NONE) {
5585 transition_marker = isolate->factory()->nonextensible_symbol();
5586 } else if (attrs == SEALED) {
5587 transition_marker = isolate->factory()->sealed_symbol();
5588 } else {
5589 DCHECK(attrs == FROZEN);
5590 transition_marker = isolate->factory()->frozen_symbol();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005591 }
5592
5593 Handle<Map> old_map(object->map(), isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005594 int transition_index = old_map->SearchSpecialTransition(*transition_marker);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005595 if (transition_index != TransitionArray::kNotFound) {
5596 Handle<Map> transition_map(old_map->GetTransition(transition_index));
5597 DCHECK(transition_map->has_dictionary_elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005598 DCHECK(!transition_map->is_extensible());
5599 JSObject::MigrateToMap(object, transition_map);
5600 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005601 // Create a new descriptor array with the appropriate property attributes
5602 Handle<Map> new_map = Map::CopyForPreventExtensions(
5603 old_map, attrs, transition_marker, "CopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005604 JSObject::MigrateToMap(object, new_map);
5605 } else {
5606 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
5607 // Slow path: need to normalize properties for safety
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005608 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0,
5609 "SlowPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005610
5611 // Create a new map, since other objects with this map may be extensible.
5612 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005613 Handle<Map> new_map =
5614 Map::Copy(handle(object->map()), "SlowCopyForPreventExtensions");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005615 new_map->set_is_extensible(false);
5616 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
5617 JSObject::MigrateToMap(object, new_map);
5618
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005619 if (attrs != NONE) {
5620 ApplyAttributesToDictionary(object->property_dictionary(), attrs);
5621 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005622 }
5623
5624 DCHECK(object->map()->has_dictionary_elements());
5625 if (!new_element_dictionary.is_null()) {
5626 object->set_elements(*new_element_dictionary);
5627 }
5628
5629 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
5630 SeededNumberDictionary* dictionary = object->element_dictionary();
5631 // Make sure we never go back to the fast case
5632 dictionary->set_requires_slow_elements();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005633 if (attrs != NONE) {
5634 ApplyAttributesToDictionary(dictionary, attrs);
5635 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005636 }
5637
5638 return object;
5639}
5640
5641
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005642MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
5643 return PreventExtensionsWithTransition<FROZEN>(object);
5644}
5645
5646
5647MaybeHandle<Object> JSObject::Seal(Handle<JSObject> object) {
5648 return PreventExtensionsWithTransition<SEALED>(object);
5649}
5650
5651
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005652void JSObject::SetObserved(Handle<JSObject> object) {
5653 DCHECK(!object->IsJSGlobalProxy());
5654 DCHECK(!object->IsJSGlobalObject());
5655 Isolate* isolate = object->GetIsolate();
5656 Handle<Map> new_map;
5657 Handle<Map> old_map(object->map(), isolate);
5658 DCHECK(!old_map->is_observed());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005659 int transition_index =
5660 old_map->SearchSpecialTransition(isolate->heap()->observed_symbol());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005661 if (transition_index != TransitionArray::kNotFound) {
5662 new_map = handle(old_map->GetTransition(transition_index), isolate);
5663 DCHECK(new_map->is_observed());
5664 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5665 new_map = Map::CopyForObserved(old_map);
5666 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005667 new_map = Map::Copy(old_map, "SlowObserved");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005668 new_map->set_is_observed();
5669 }
5670 JSObject::MigrateToMap(object, new_map);
5671}
5672
5673
5674Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
5675 Representation representation,
5676 FieldIndex index) {
5677 Isolate* isolate = object->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005678 if (object->IsUnboxedDoubleField(index)) {
5679 double value = object->RawFastDoublePropertyAt(index);
5680 return isolate->factory()->NewHeapNumber(value);
5681 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005682 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
5683 return Object::WrapForRead(isolate, raw_value, representation);
5684}
5685
5686
5687template<class ContextObject>
5688class JSObjectWalkVisitor {
5689 public:
5690 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
5691 JSObject::DeepCopyHints hints)
5692 : site_context_(site_context),
5693 copying_(copying),
5694 hints_(hints) {}
5695
5696 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
5697
5698 protected:
5699 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
5700 Handle<JSObject> object,
5701 Handle<JSObject> value) {
5702 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5703 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
5704 site_context()->ExitScope(current_site, value);
5705 return copy_of_value;
5706 }
5707
5708 inline ContextObject* site_context() { return site_context_; }
5709 inline Isolate* isolate() { return site_context()->isolate(); }
5710
5711 inline bool copying() const { return copying_; }
5712
5713 private:
5714 ContextObject* site_context_;
5715 const bool copying_;
5716 const JSObject::DeepCopyHints hints_;
5717};
5718
5719
5720template <class ContextObject>
5721MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
5722 Handle<JSObject> object) {
5723 Isolate* isolate = this->isolate();
5724 bool copying = this->copying();
5725 bool shallow = hints_ == JSObject::kObjectIsShallow;
5726
5727 if (!shallow) {
5728 StackLimitCheck check(isolate);
5729
5730 if (check.HasOverflowed()) {
5731 isolate->StackOverflow();
5732 return MaybeHandle<JSObject>();
5733 }
5734 }
5735
5736 if (object->map()->is_deprecated()) {
5737 JSObject::MigrateInstance(object);
5738 }
5739
5740 Handle<JSObject> copy;
5741 if (copying) {
5742 Handle<AllocationSite> site_to_pass;
5743 if (site_context()->ShouldCreateMemento(object)) {
5744 site_to_pass = site_context()->current();
5745 }
5746 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
5747 object, site_to_pass);
5748 } else {
5749 copy = object;
5750 }
5751
5752 DCHECK(copying || copy.is_identical_to(object));
5753
5754 ElementsKind kind = copy->GetElementsKind();
5755 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
5756 FixedArray::cast(copy->elements())->map() ==
5757 isolate->heap()->fixed_cow_array_map()) {
5758 isolate->counters()->cow_arrays_created_runtime()->Increment();
5759 }
5760
5761 if (!shallow) {
5762 HandleScope scope(isolate);
5763
5764 // Deep copy own properties.
5765 if (copy->HasFastProperties()) {
5766 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
5767 int limit = copy->map()->NumberOfOwnDescriptors();
5768 for (int i = 0; i < limit; i++) {
5769 PropertyDetails details = descriptors->GetDetails(i);
5770 if (details.type() != FIELD) continue;
5771 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005772 if (object->IsUnboxedDoubleField(index)) {
5773 if (copying) {
5774 double value = object->RawFastDoublePropertyAt(index);
5775 copy->RawFastDoublePropertyAtPut(index, value);
5776 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005777 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005778 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
5779 if (value->IsJSObject()) {
5780 ASSIGN_RETURN_ON_EXCEPTION(
5781 isolate, value,
5782 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5783 JSObject);
5784 if (copying) {
5785 copy->FastPropertyAtPut(index, *value);
5786 }
5787 } else {
5788 if (copying) {
5789 Representation representation = details.representation();
5790 value = Object::NewStorageFor(isolate, value, representation);
5791 copy->FastPropertyAtPut(index, *value);
5792 }
5793 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005794 }
5795 }
5796 } else {
5797 Handle<FixedArray> names =
5798 isolate->factory()->NewFixedArray(copy->NumberOfOwnProperties());
5799 copy->GetOwnPropertyNames(*names, 0);
5800 for (int i = 0; i < names->length(); i++) {
5801 DCHECK(names->get(i)->IsString());
5802 Handle<String> key_string(String::cast(names->get(i)));
5803 Maybe<PropertyAttributes> maybe =
5804 JSReceiver::GetOwnPropertyAttributes(copy, key_string);
5805 DCHECK(maybe.has_value);
5806 PropertyAttributes attributes = maybe.value;
5807 // Only deep copy fields from the object literal expression.
5808 // In particular, don't try to copy the length attribute of
5809 // an array.
5810 if (attributes != NONE) continue;
5811 Handle<Object> value =
5812 Object::GetProperty(copy, key_string).ToHandleChecked();
5813 if (value->IsJSObject()) {
5814 Handle<JSObject> result;
5815 ASSIGN_RETURN_ON_EXCEPTION(
5816 isolate, result,
5817 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5818 JSObject);
5819 if (copying) {
5820 // Creating object copy for literals. No strict mode needed.
5821 JSObject::SetProperty(copy, key_string, result, SLOPPY).Assert();
5822 }
5823 }
5824 }
5825 }
5826
5827 // Deep copy own elements.
5828 // Pixel elements cannot be created using an object literal.
5829 DCHECK(!copy->HasExternalArrayElements());
5830 switch (kind) {
5831 case FAST_SMI_ELEMENTS:
5832 case FAST_ELEMENTS:
5833 case FAST_HOLEY_SMI_ELEMENTS:
5834 case FAST_HOLEY_ELEMENTS: {
5835 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
5836 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
5837#ifdef DEBUG
5838 for (int i = 0; i < elements->length(); i++) {
5839 DCHECK(!elements->get(i)->IsJSObject());
5840 }
5841#endif
5842 } else {
5843 for (int i = 0; i < elements->length(); i++) {
5844 Handle<Object> value(elements->get(i), isolate);
5845 DCHECK(value->IsSmi() ||
5846 value->IsTheHole() ||
5847 (IsFastObjectElementsKind(copy->GetElementsKind())));
5848 if (value->IsJSObject()) {
5849 Handle<JSObject> result;
5850 ASSIGN_RETURN_ON_EXCEPTION(
5851 isolate, result,
5852 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5853 JSObject);
5854 if (copying) {
5855 elements->set(i, *result);
5856 }
5857 }
5858 }
5859 }
5860 break;
5861 }
5862 case DICTIONARY_ELEMENTS: {
5863 Handle<SeededNumberDictionary> element_dictionary(
5864 copy->element_dictionary());
5865 int capacity = element_dictionary->Capacity();
5866 for (int i = 0; i < capacity; i++) {
5867 Object* k = element_dictionary->KeyAt(i);
5868 if (element_dictionary->IsKey(k)) {
5869 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
5870 if (value->IsJSObject()) {
5871 Handle<JSObject> result;
5872 ASSIGN_RETURN_ON_EXCEPTION(
5873 isolate, result,
5874 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5875 JSObject);
5876 if (copying) {
5877 element_dictionary->ValueAtPut(i, *result);
5878 }
5879 }
5880 }
5881 }
5882 break;
5883 }
5884 case SLOPPY_ARGUMENTS_ELEMENTS:
5885 UNIMPLEMENTED();
5886 break;
5887
5888
5889#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
5890 case EXTERNAL_##TYPE##_ELEMENTS: \
5891 case TYPE##_ELEMENTS: \
5892
5893 TYPED_ARRAYS(TYPED_ARRAY_CASE)
5894#undef TYPED_ARRAY_CASE
5895
5896 case FAST_DOUBLE_ELEMENTS:
5897 case FAST_HOLEY_DOUBLE_ELEMENTS:
5898 // No contained objects, nothing to do.
5899 break;
5900 }
5901 }
5902
5903 return copy;
5904}
5905
5906
5907MaybeHandle<JSObject> JSObject::DeepWalk(
5908 Handle<JSObject> object,
5909 AllocationSiteCreationContext* site_context) {
5910 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
5911 kNoHints);
5912 MaybeHandle<JSObject> result = v.StructureWalk(object);
5913 Handle<JSObject> for_assert;
5914 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
5915 return result;
5916}
5917
5918
5919MaybeHandle<JSObject> JSObject::DeepCopy(
5920 Handle<JSObject> object,
5921 AllocationSiteUsageContext* site_context,
5922 DeepCopyHints hints) {
5923 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
5924 MaybeHandle<JSObject> copy = v.StructureWalk(object);
5925 Handle<JSObject> for_assert;
5926 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
5927 return copy;
Steve Block8defd9f2010-07-08 12:39:36 +01005928}
5929
5930
Steve Blocka7e24c12009-10-30 11:49:00 +00005931// Tests for the fast common case for property enumeration:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005932// - This object and all prototypes has an enum cache (which means that
5933// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00005934// - This object has no elements.
5935// - No prototype has enumerable properties/elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005936bool JSReceiver::IsSimpleEnum() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005937 for (PrototypeIterator iter(GetIsolate(), this,
5938 PrototypeIterator::START_AT_RECEIVER);
5939 !iter.IsAtEnd(); iter.Advance()) {
5940 if (!iter.GetCurrent()->IsJSObject()) return false;
5941 JSObject* curr = JSObject::cast(iter.GetCurrent());
5942 int enum_length = curr->map()->EnumLength();
5943 if (enum_length == kInvalidEnumCacheSentinel) return false;
5944 if (curr->IsAccessCheckNeeded()) return false;
5945 DCHECK(!curr->HasNamedInterceptor());
5946 DCHECK(!curr->HasIndexedInterceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +00005947 if (curr->NumberOfEnumElements() > 0) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005948 if (curr != this && enum_length != 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005949 }
5950 return true;
5951}
5952
5953
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005954static bool FilterKey(Object* key, PropertyAttributes filter) {
5955 if ((filter & SYMBOLIC) && key->IsSymbol()) {
5956 return true;
5957 }
5958
5959 if ((filter & PRIVATE_SYMBOL) &&
5960 key->IsSymbol() && Symbol::cast(key)->is_private()) {
5961 return true;
5962 }
5963
5964 if ((filter & STRING) && !key->IsSymbol()) {
5965 return true;
5966 }
5967
5968 return false;
5969}
5970
5971
5972int Map::NumberOfDescribedProperties(DescriptorFlag which,
5973 PropertyAttributes filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005974 int result = 0;
5975 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005976 int limit = which == ALL_DESCRIPTORS
5977 ? descs->number_of_descriptors()
5978 : NumberOfOwnDescriptors();
5979 for (int i = 0; i < limit; i++) {
5980 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
5981 !FilterKey(descs->GetKey(i), filter)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005982 result++;
5983 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005984 }
5985 return result;
5986}
5987
5988
Steve Blocka7e24c12009-10-30 11:49:00 +00005989int Map::NextFreePropertyIndex() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005990 int free_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005991 int number_of_own_descriptors = NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00005992 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005993 for (int i = 0; i < number_of_own_descriptors; i++) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04005994 PropertyDetails details = descs->GetDetails(i);
5995 if (details.type() == FIELD) {
5996 int candidate = details.field_index() + details.field_width_in_words();
5997 if (candidate > free_index) free_index = candidate;
Steve Blocka7e24c12009-10-30 11:49:00 +00005998 }
5999 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006000 return free_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00006001}
6002
6003
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006004static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
6005 int len = array->length();
6006 for (int i = 0; i < len; i++) {
6007 Object* e = array->get(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006008 if (!(e->IsName() || e->IsNumber())) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006009 }
6010 return true;
6011}
6012
6013
6014static Handle<FixedArray> ReduceFixedArrayTo(
6015 Handle<FixedArray> array, int length) {
6016 DCHECK(array->length() >= length);
6017 if (array->length() == length) return array;
6018
6019 Handle<FixedArray> new_array =
6020 array->GetIsolate()->factory()->NewFixedArray(length);
6021 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
6022 return new_array;
6023}
6024
6025
6026static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
6027 bool cache_result) {
6028 Isolate* isolate = object->GetIsolate();
6029 if (object->HasFastProperties()) {
6030 int own_property_count = object->map()->EnumLength();
6031 // If the enum length of the given map is set to kInvalidEnumCache, this
6032 // means that the map itself has never used the present enum cache. The
6033 // first step to using the cache is to set the enum length of the map by
6034 // counting the number of own descriptors that are not DONT_ENUM or
6035 // SYMBOLIC.
6036 if (own_property_count == kInvalidEnumCacheSentinel) {
6037 own_property_count = object->map()->NumberOfDescribedProperties(
6038 OWN_DESCRIPTORS, DONT_SHOW);
6039 } else {
6040 DCHECK(own_property_count == object->map()->NumberOfDescribedProperties(
6041 OWN_DESCRIPTORS, DONT_SHOW));
Steve Blocka7e24c12009-10-30 11:49:00 +00006042 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006043
6044 if (object->map()->instance_descriptors()->HasEnumCache()) {
6045 DescriptorArray* desc = object->map()->instance_descriptors();
6046 Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
6047
6048 // In case the number of properties required in the enum are actually
6049 // present, we can reuse the enum cache. Otherwise, this means that the
6050 // enum cache was generated for a previous (smaller) version of the
6051 // Descriptor Array. In that case we regenerate the enum cache.
6052 if (own_property_count <= keys->length()) {
6053 if (cache_result) object->map()->SetEnumLength(own_property_count);
6054 isolate->counters()->enum_cache_hits()->Increment();
6055 return ReduceFixedArrayTo(keys, own_property_count);
6056 }
6057 }
6058
6059 Handle<Map> map(object->map());
6060
6061 if (map->instance_descriptors()->IsEmpty()) {
6062 isolate->counters()->enum_cache_hits()->Increment();
6063 if (cache_result) map->SetEnumLength(0);
6064 return isolate->factory()->empty_fixed_array();
6065 }
6066
6067 isolate->counters()->enum_cache_misses()->Increment();
6068
6069 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
6070 own_property_count);
6071 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
6072 own_property_count);
6073
6074 Handle<DescriptorArray> descs =
6075 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
6076
6077 int size = map->NumberOfOwnDescriptors();
6078 int index = 0;
6079
6080 for (int i = 0; i < size; i++) {
6081 PropertyDetails details = descs->GetDetails(i);
6082 Object* key = descs->GetKey(i);
6083 if (!(details.IsDontEnum() || key->IsSymbol())) {
6084 storage->set(index, key);
6085 if (!indices.is_null()) {
6086 if (details.type() != FIELD) {
6087 indices = Handle<FixedArray>();
6088 } else {
6089 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
6090 int load_by_field_index = field_index.GetLoadByFieldIndex();
6091 indices->set(index, Smi::FromInt(load_by_field_index));
6092 }
6093 }
6094 index++;
6095 }
6096 }
6097 DCHECK(index == storage->length());
6098
6099 Handle<FixedArray> bridge_storage =
6100 isolate->factory()->NewFixedArray(
6101 DescriptorArray::kEnumCacheBridgeLength);
6102 DescriptorArray* desc = object->map()->instance_descriptors();
6103 desc->SetEnumCache(*bridge_storage,
6104 *storage,
6105 indices.is_null() ? Object::cast(Smi::FromInt(0))
6106 : Object::cast(*indices));
6107 if (cache_result) {
6108 object->map()->SetEnumLength(own_property_count);
6109 }
6110 return storage;
6111 } else {
6112 Handle<NameDictionary> dictionary(object->property_dictionary());
6113 int length = dictionary->NumberOfEnumElements();
6114 if (length == 0) {
6115 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
6116 }
6117 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
6118 dictionary->CopyEnumKeysTo(*storage);
6119 return storage;
Steve Blocka7e24c12009-10-30 11:49:00 +00006120 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006121}
6122
6123
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006124MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
6125 KeyCollectionType type) {
6126 USE(ContainsOnlyValidKeys);
6127 Isolate* isolate = object->GetIsolate();
6128 Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
6129 Handle<JSFunction> arguments_function(
6130 JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006131
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006132 // Only collect keys if access is permitted.
6133 for (PrototypeIterator iter(isolate, object,
6134 PrototypeIterator::START_AT_RECEIVER);
6135 !iter.IsAtEnd(); iter.Advance()) {
6136 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
6137 Handle<JSProxy> proxy(JSProxy::cast(*PrototypeIterator::GetCurrent(iter)),
6138 isolate);
6139 Handle<Object> args[] = { proxy };
6140 Handle<Object> names;
6141 ASSIGN_RETURN_ON_EXCEPTION(
6142 isolate, names,
6143 Execution::Call(isolate,
6144 isolate->proxy_enumerate(),
6145 object,
6146 arraysize(args),
6147 args),
6148 FixedArray);
6149 ASSIGN_RETURN_ON_EXCEPTION(
6150 isolate, content,
6151 FixedArray::AddKeysFromArrayLike(
6152 content, Handle<JSObject>::cast(names)),
6153 FixedArray);
6154 break;
6155 }
Steve Block44f0eee2011-05-26 01:26:41 +01006156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006157 Handle<JSObject> current =
6158 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
6159
6160 // Check access rights if required.
6161 if (current->IsAccessCheckNeeded() &&
6162 !isolate->MayNamedAccess(
6163 current, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
6164 isolate->ReportFailedAccessCheck(current, v8::ACCESS_KEYS);
6165 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
6166 break;
6167 }
6168
6169 // Compute the element keys.
6170 Handle<FixedArray> element_keys =
6171 isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
6172 current->GetEnumElementKeys(*element_keys);
6173 ASSIGN_RETURN_ON_EXCEPTION(
6174 isolate, content,
6175 FixedArray::UnionOfKeys(content, element_keys),
6176 FixedArray);
6177 DCHECK(ContainsOnlyValidKeys(content));
6178
6179 // Add the element keys from the interceptor.
6180 if (current->HasIndexedInterceptor()) {
6181 Handle<JSObject> result;
6182 if (JSObject::GetKeysForIndexedInterceptor(
6183 current, object).ToHandle(&result)) {
6184 ASSIGN_RETURN_ON_EXCEPTION(
6185 isolate, content,
6186 FixedArray::AddKeysFromArrayLike(content, result),
6187 FixedArray);
6188 }
6189 DCHECK(ContainsOnlyValidKeys(content));
6190 }
6191
6192 // We can cache the computed property keys if access checks are
6193 // not needed and no interceptors are involved.
6194 //
6195 // We do not use the cache if the object has elements and
6196 // therefore it does not make sense to cache the property names
6197 // for arguments objects. Arguments objects will always have
6198 // elements.
6199 // Wrapped strings have elements, but don't have an elements
6200 // array or dictionary. So the fast inline test for whether to
6201 // use the cache says yes, so we should not create a cache.
6202 bool cache_enum_keys =
6203 ((current->map()->constructor() != *arguments_function) &&
6204 !current->IsJSValue() &&
6205 !current->IsAccessCheckNeeded() &&
6206 !current->HasNamedInterceptor() &&
6207 !current->HasIndexedInterceptor());
6208 // Compute the property keys and cache them if possible.
6209 ASSIGN_RETURN_ON_EXCEPTION(
6210 isolate, content,
6211 FixedArray::UnionOfKeys(
6212 content, GetEnumPropertyKeys(current, cache_enum_keys)),
6213 FixedArray);
6214 DCHECK(ContainsOnlyValidKeys(content));
6215
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006216 // Add the non-symbol property keys from the interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006217 if (current->HasNamedInterceptor()) {
6218 Handle<JSObject> result;
6219 if (JSObject::GetKeysForNamedInterceptor(
6220 current, object).ToHandle(&result)) {
6221 ASSIGN_RETURN_ON_EXCEPTION(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006222 isolate, content, FixedArray::AddKeysFromArrayLike(
6223 content, result, FixedArray::NON_SYMBOL_KEYS),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006224 FixedArray);
6225 }
6226 DCHECK(ContainsOnlyValidKeys(content));
6227 }
6228
6229 // If we only want own properties we bail out after the first
6230 // iteration.
6231 if (type == OWN_ONLY) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006232 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006233 return content;
Steve Blocka7e24c12009-10-30 11:49:00 +00006234}
6235
6236
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006237// Try to update an accessor in an elements dictionary. Return true if the
6238// update succeeded, and false otherwise.
6239static bool UpdateGetterSetterInDictionary(
6240 SeededNumberDictionary* dictionary,
6241 uint32_t index,
6242 Object* getter,
6243 Object* setter,
6244 PropertyAttributes attributes) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006245 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006246 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006247 Object* result = dictionary->ValueAt(entry);
6248 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006249 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006250 DCHECK(details.IsConfigurable());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006251 if (details.attributes() != attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006252 dictionary->DetailsAtPut(
6253 entry,
6254 PropertyDetails(attributes, CALLBACKS, index));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006255 }
6256 AccessorPair::cast(result)->SetComponents(getter, setter);
6257 return true;
6258 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006259 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006260 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006261}
6262
6263
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006264void JSObject::DefineElementAccessor(Handle<JSObject> object,
6265 uint32_t index,
6266 Handle<Object> getter,
6267 Handle<Object> setter,
6268 PropertyAttributes attributes) {
6269 switch (object->GetElementsKind()) {
6270 case FAST_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006271 case FAST_ELEMENTS:
6272 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006273 case FAST_HOLEY_SMI_ELEMENTS:
6274 case FAST_HOLEY_ELEMENTS:
6275 case FAST_HOLEY_DOUBLE_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006276 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006277
6278#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
6279 case EXTERNAL_##TYPE##_ELEMENTS: \
6280 case TYPE##_ELEMENTS: \
6281
6282 TYPED_ARRAYS(TYPED_ARRAY_CASE)
6283#undef TYPED_ARRAY_CASE
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006284 // Ignore getters and setters on pixel and external array elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006285 return;
6286
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006287 case DICTIONARY_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006288 if (UpdateGetterSetterInDictionary(object->element_dictionary(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006289 index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006290 *getter,
6291 *setter,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006292 attributes)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006293 return;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006294 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006295 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006296 case SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006297 // Ascertain whether we have read-only properties or an existing
6298 // getter/setter pair in an arguments elements dictionary backing
6299 // store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006300 FixedArray* parameter_map = FixedArray::cast(object->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006301 uint32_t length = parameter_map->length();
6302 Object* probe =
6303 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
6304 if (probe == NULL || probe->IsTheHole()) {
6305 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
6306 if (arguments->IsDictionary()) {
6307 SeededNumberDictionary* dictionary =
6308 SeededNumberDictionary::cast(arguments);
6309 if (UpdateGetterSetterInDictionary(dictionary,
6310 index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006311 *getter,
6312 *setter,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006313 attributes)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006314 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006315 }
6316 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006317 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006318 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00006319 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006320 }
6321
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006322 Isolate* isolate = object->GetIsolate();
6323 Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
6324 accessors->SetComponents(*getter, *setter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006325
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006326 SetElementCallback(object, index, accessors, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006327}
6328
6329
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006330bool Map::DictionaryElementsInPrototypeChainOnly() {
6331 if (IsDictionaryElementsKind(elements_kind())) {
6332 return false;
6333 }
6334
6335 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
6336 if (iter.GetCurrent()->IsJSProxy()) {
6337 // Be conservative, don't walk into proxies.
6338 return true;
6339 }
6340
6341 if (IsDictionaryElementsKind(
6342 JSObject::cast(iter.GetCurrent())->map()->elements_kind())) {
6343 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00006344 }
6345 }
6346
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006347 return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01006348}
6349
6350
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006351void JSObject::SetElementCallback(Handle<JSObject> object,
6352 uint32_t index,
6353 Handle<Object> structure,
6354 PropertyAttributes attributes) {
6355 Heap* heap = object->GetHeap();
6356 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01006357
6358 // Normalize elements to make this operation simple.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006359 bool had_dictionary_elements = object->HasDictionaryElements();
6360 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6361 DCHECK(object->HasDictionaryElements() ||
6362 object->HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01006363 // Update the dictionary with the new CALLBACKS property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006364 dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6365 details);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006366 dictionary->set_requires_slow_elements();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006367
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006368 // Update the dictionary backing store on the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006369 if (object->elements()->map() == heap->sloppy_arguments_elements_map()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006370 // Also delete any parameter alias.
6371 //
6372 // TODO(kmillikin): when deleting the last parameter alias we could
6373 // switch to a direct backing store without the parameter map. This
6374 // would allow GC of the context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006375 FixedArray* parameter_map = FixedArray::cast(object->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006376 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006377 parameter_map->set(index + 2, heap->the_hole_value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006378 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006379 parameter_map->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006380 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006381 object->set_elements(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00006382
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006383 if (!had_dictionary_elements) {
6384 // KeyedStoreICs (at least the non-generic ones) need a reset.
6385 heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
6386 }
6387 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006388}
6389
6390
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006391void JSObject::SetPropertyCallback(Handle<JSObject> object,
6392 Handle<Name> name,
6393 Handle<Object> structure,
6394 PropertyAttributes attributes) {
6395 PropertyNormalizationMode mode = object->map()->is_prototype_map()
6396 ? KEEP_INOBJECT_PROPERTIES
6397 : CLEAR_INOBJECT_PROPERTIES;
Leon Clarkef7060e22010-06-03 12:02:55 +01006398 // Normalize object to make this operation simple.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006399 NormalizeProperties(object, mode, 0, "SetPropertyCallback");
Leon Clarkef7060e22010-06-03 12:02:55 +01006400
6401 // For the global object allocate a new map to invalidate the global inline
6402 // caches which have a global property cell reference directly in the code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006403 if (object->IsGlobalObject()) {
6404 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
6405 DCHECK(new_map->is_dictionary_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006406#if TRACE_MAPS
6407 if (FLAG_trace_maps) {
6408 PrintF("[TraceMaps: GlobalPropertyCallback from= %p to= %p ]\n",
6409 reinterpret_cast<void*>(object->map()),
6410 reinterpret_cast<void*>(*new_map));
6411 }
6412#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006413 JSObject::MigrateToMap(object, new_map);
6414
Ben Murdochb0fe1622011-05-05 13:52:32 +01006415 // When running crankshaft, changing the map is not enough. We
6416 // need to deoptimize all functions that rely on this global
6417 // object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006418 Deoptimizer::DeoptimizeGlobalObject(*object);
Leon Clarkef7060e22010-06-03 12:02:55 +01006419 }
6420
6421 // Update the dictionary with the new CALLBACKS property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006422 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6423 SetNormalizedProperty(object, name, structure, details);
Leon Clarkef7060e22010-06-03 12:02:55 +01006424
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006425 ReoptimizeIfPrototype(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006426}
6427
6428
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006429MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
6430 Handle<Name> name,
6431 Handle<Object> getter,
6432 Handle<Object> setter,
6433 PropertyAttributes attributes) {
6434 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006435 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006436 if (object->IsAccessCheckNeeded() &&
6437 !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6438 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6439 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6440 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006441 }
6442
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006443 if (object->IsJSGlobalProxy()) {
6444 PrototypeIterator iter(isolate, object);
6445 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
6446 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
6447 DefineAccessor(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
6448 name, getter, setter, attributes);
6449 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006450 }
6451
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006452 // Make sure that the top context does not change when doing callbacks or
6453 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006454 AssertNoContextChange ncc(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006455
6456 // Try to flatten before operating on the string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006457 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006458
6459 uint32_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006460 bool is_element = name->AsArrayIndex(&index);
6461
6462 Handle<Object> old_value = isolate->factory()->the_hole_value();
6463 bool is_observed = object->map()->is_observed() &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006464 !isolate->IsInternallyUsedPropertyName(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006465 bool preexists = false;
6466 if (is_observed) {
6467 if (is_element) {
6468 Maybe<bool> maybe = HasOwnElement(object, index);
6469 // Workaround for a GCC 4.4.3 bug which leads to "‘preexists’ may be used
6470 // uninitialized in this function".
6471 if (!maybe.has_value) {
6472 DCHECK(false);
6473 return isolate->factory()->undefined_value();
6474 }
6475 preexists = maybe.value;
6476 if (preexists && GetOwnElementAccessorPair(object, index).is_null()) {
6477 old_value =
6478 Object::GetElement(isolate, object, index).ToHandleChecked();
6479 }
6480 } else {
6481 LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
6482 CHECK(GetPropertyAttributes(&it).has_value);
6483 preexists = it.IsFound();
6484 if (preexists && (it.state() == LookupIterator::DATA ||
6485 it.GetAccessors()->IsAccessorInfo())) {
6486 old_value = GetProperty(&it).ToHandleChecked();
6487 }
6488 }
6489 }
6490
6491 if (is_element) {
6492 DefineElementAccessor(object, index, getter, setter, attributes);
6493 } else {
6494 DCHECK(getter->IsSpecFunction() || getter->IsUndefined() ||
6495 getter->IsNull());
6496 DCHECK(setter->IsSpecFunction() || setter->IsUndefined() ||
6497 setter->IsNull());
6498 // At least one of the accessors needs to be a new value.
6499 DCHECK(!getter->IsNull() || !setter->IsNull());
6500 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
6501 if (it.state() == LookupIterator::ACCESS_CHECK) {
6502 // We already did an access check before. We do have access.
6503 it.Next();
6504 }
6505 if (!getter->IsNull()) {
6506 it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
6507 }
6508 if (!setter->IsNull()) {
6509 it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
6510 }
6511 }
6512
6513 if (is_observed) {
6514 const char* type = preexists ? "reconfigure" : "add";
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006515 RETURN_ON_EXCEPTION(
6516 isolate, EnqueueChangeRecord(object, type, name, old_value), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006517 }
6518
6519 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006520}
6521
6522
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006523MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6524 Handle<AccessorInfo> info) {
6525 Isolate* isolate = object->GetIsolate();
6526 Factory* factory = isolate->factory();
6527 Handle<Name> name(Name::cast(info->name()));
6528
Leon Clarkef7060e22010-06-03 12:02:55 +01006529 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006530 if (object->IsAccessCheckNeeded() &&
6531 !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6532 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6533 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6534 return factory->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01006535 }
6536
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006537 if (object->IsJSGlobalProxy()) {
6538 PrototypeIterator iter(isolate, object);
6539 if (iter.IsAtEnd()) return object;
6540 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
6541 return SetAccessor(
6542 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), info);
Leon Clarkef7060e22010-06-03 12:02:55 +01006543 }
6544
6545 // Make sure that the top context does not change when doing callbacks or
6546 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006547 AssertNoContextChange ncc(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01006548
6549 // Try to flatten before operating on the string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006550 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
Leon Clarkef7060e22010-06-03 12:02:55 +01006551
6552 uint32_t index = 0;
6553 bool is_element = name->AsArrayIndex(&index);
6554
6555 if (is_element) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006556 if (object->IsJSArray()) return factory->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01006557
6558 // Accessors overwrite previous callbacks (cf. with getters/setters).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006559 switch (object->GetElementsKind()) {
6560 case FAST_SMI_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01006561 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006562 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006563 case FAST_HOLEY_SMI_ELEMENTS:
6564 case FAST_HOLEY_ELEMENTS:
6565 case FAST_HOLEY_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01006566 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006567
6568#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
6569 case EXTERNAL_##TYPE##_ELEMENTS: \
6570 case TYPE##_ELEMENTS: \
6571
6572 TYPED_ARRAYS(TYPED_ARRAY_CASE)
6573#undef TYPED_ARRAY_CASE
Leon Clarkef7060e22010-06-03 12:02:55 +01006574 // Ignore getters and setters on pixel and external array
6575 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006576 return factory->undefined_value();
6577
Leon Clarkef7060e22010-06-03 12:02:55 +01006578 case DICTIONARY_ELEMENTS:
6579 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006580 case SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006581 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01006582 break;
6583 }
6584
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006585 SetElementCallback(object, index, info, info->property_attributes());
Leon Clarkef7060e22010-06-03 12:02:55 +01006586 } else {
6587 // Lookup the name.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006588 LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
6589 CHECK(GetPropertyAttributes(&it).has_value);
Leon Clarkef7060e22010-06-03 12:02:55 +01006590 // ES5 forbids turning a property into an accessor if it's not
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006591 // configurable. See 8.6.1 (Table 5).
6592 if (it.IsFound() && (it.IsReadOnly() || !it.IsConfigurable())) {
6593 return factory->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01006594 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006595
6596 SetPropertyCallback(object, name, info, info->property_attributes());
Leon Clarkef7060e22010-06-03 12:02:55 +01006597 }
6598
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006599 return object;
Leon Clarkef7060e22010-06-03 12:02:55 +01006600}
6601
6602
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006603MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
6604 Handle<Name> name,
6605 AccessorComponent component) {
6606 Isolate* isolate = object->GetIsolate();
Steve Block44f0eee2011-05-26 01:26:41 +01006607
Steve Blocka7e24c12009-10-30 11:49:00 +00006608 // Make sure that the top context does not change when doing callbacks or
6609 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006610 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006611
6612 // Make the lookup and include prototypes.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006613 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006614 if (name->AsArrayIndex(&index)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006615 for (PrototypeIterator iter(isolate, object,
6616 PrototypeIterator::START_AT_RECEIVER);
6617 !iter.IsAtEnd(); iter.Advance()) {
6618 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
6619 // Check access rights if needed.
6620 if (current->IsAccessCheckNeeded() &&
6621 !isolate->MayNamedAccess(Handle<JSObject>::cast(current), name,
6622 v8::ACCESS_HAS)) {
6623 isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(current),
6624 v8::ACCESS_HAS);
6625 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6626 return isolate->factory()->undefined_value();
6627 }
6628
6629 if (current->IsJSObject() &&
6630 Handle<JSObject>::cast(current)->HasDictionaryElements()) {
6631 JSObject* js_object = JSObject::cast(*current);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006632 SeededNumberDictionary* dictionary = js_object->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00006633 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006634 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006635 Object* element = dictionary->ValueAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006636 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6637 element->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006638 return handle(AccessorPair::cast(element)->GetComponent(component),
6639 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006640 }
6641 }
6642 }
6643 }
6644 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006645 LookupIterator it(object, name,
6646 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
6647 for (; it.IsFound(); it.Next()) {
6648 switch (it.state()) {
6649 case LookupIterator::INTERCEPTOR:
6650 case LookupIterator::NOT_FOUND:
6651 case LookupIterator::TRANSITION:
6652 UNREACHABLE();
6653
6654 case LookupIterator::ACCESS_CHECK:
6655 if (it.HasAccess(v8::ACCESS_HAS)) continue;
6656 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
6657 v8::ACCESS_HAS);
6658 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6659 return isolate->factory()->undefined_value();
6660
6661 case LookupIterator::JSPROXY:
6662 return isolate->factory()->undefined_value();
6663
6664 case LookupIterator::DATA:
6665 continue;
6666 case LookupIterator::ACCESSOR: {
6667 Handle<Object> maybe_pair = it.GetAccessors();
6668 if (maybe_pair->IsAccessorPair()) {
6669 return handle(
6670 AccessorPair::cast(*maybe_pair)->GetComponent(component),
6671 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006672 }
6673 }
6674 }
6675 }
6676 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006677 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006678}
6679
6680
6681Object* JSObject::SlowReverseLookup(Object* value) {
6682 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006683 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00006684 DescriptorArray* descs = map()->instance_descriptors();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006685 bool value_is_number = value->IsNumber();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006686 for (int i = 0; i < number_of_own_descriptors; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006687 if (descs->GetType(i) == FIELD) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006688 FieldIndex field_index = FieldIndex::ForDescriptor(map(), i);
6689 if (IsUnboxedDoubleField(field_index)) {
6690 if (value_is_number) {
6691 double property = RawFastDoublePropertyAt(field_index);
6692 if (property == value->Number()) {
6693 return descs->GetKey(i);
6694 }
6695 }
6696 } else {
6697 Object* property = RawFastPropertyAt(field_index);
6698 if (field_index.is_double()) {
6699 DCHECK(property->IsMutableHeapNumber());
6700 if (value_is_number && property->Number() == value->Number()) {
6701 return descs->GetKey(i);
6702 }
6703 } else if (property == value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006704 return descs->GetKey(i);
6705 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006706 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006707 } else if (descs->GetType(i) == CONSTANT) {
6708 if (descs->GetConstant(i) == value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006709 return descs->GetKey(i);
6710 }
6711 }
6712 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01006713 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006714 } else {
6715 return property_dictionary()->SlowReverseLookup(value);
6716 }
6717}
6718
6719
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006720Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
6721 Handle<Map> result = map->GetIsolate()->factory()->NewMap(
6722 map->instance_type(), instance_size);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006723 result->SetPrototype(handle(map->prototype(), map->GetIsolate()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006724 result->set_constructor(map->constructor());
6725 result->set_bit_field(map->bit_field());
6726 result->set_bit_field2(map->bit_field2());
6727 int new_bit_field3 = map->bit_field3();
6728 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
6729 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
6730 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
6731 kInvalidEnumCacheSentinel);
6732 new_bit_field3 = Deprecated::update(new_bit_field3, false);
6733 if (!map->is_dictionary_map()) {
6734 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
John Reck59135872010-11-02 12:39:01 -07006735 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006736 new_bit_field3 = Counter::update(new_bit_field3, kRetainingCounterStart);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006737 result->set_bit_field3(new_bit_field3);
Steve Blocka7e24c12009-10-30 11:49:00 +00006738 return result;
6739}
6740
6741
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006742Handle<Map> Map::Normalize(Handle<Map> fast_map, PropertyNormalizationMode mode,
6743 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006744 DCHECK(!fast_map->is_dictionary_map());
6745
6746 Isolate* isolate = fast_map->GetIsolate();
6747 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
6748 isolate);
6749 bool use_cache = !maybe_cache->IsUndefined();
6750 Handle<NormalizedMapCache> cache;
6751 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
6752
6753 Handle<Map> new_map;
6754 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
6755#ifdef VERIFY_HEAP
6756 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
6757#endif
6758#ifdef ENABLE_SLOW_DCHECKS
6759 if (FLAG_enable_slow_asserts) {
6760 // The cached map should match newly created normalized map bit-by-bit,
6761 // except for the code cache, which can contain some ics which can be
6762 // applied to the shared map.
6763 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
6764
6765 DCHECK(memcmp(fresh->address(),
6766 new_map->address(),
6767 Map::kCodeCacheOffset) == 0);
6768 STATIC_ASSERT(Map::kDependentCodeOffset ==
6769 Map::kCodeCacheOffset + kPointerSize);
6770 int offset = Map::kDependentCodeOffset + kPointerSize;
6771 DCHECK(memcmp(fresh->address() + offset,
6772 new_map->address() + offset,
6773 Map::kSize - offset) == 0);
6774 }
6775#endif
6776 } else {
6777 new_map = Map::CopyNormalized(fast_map, mode);
6778 if (use_cache) {
6779 cache->Set(fast_map, new_map);
6780 isolate->counters()->normalized_maps()->Increment();
6781 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006782#if TRACE_MAPS
6783 if (FLAG_trace_maps) {
6784 PrintF("[TraceMaps: Normalize from= %p to= %p reason= %s ]\n",
6785 reinterpret_cast<void*>(*fast_map),
6786 reinterpret_cast<void*>(*new_map), reason);
6787 }
6788#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006789 }
6790 fast_map->NotifyLeafMapLayoutChange();
6791 return new_map;
6792}
6793
6794
6795Handle<Map> Map::CopyNormalized(Handle<Map> map,
6796 PropertyNormalizationMode mode) {
6797 int new_instance_size = map->instance_size();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006798 if (mode == CLEAR_INOBJECT_PROPERTIES) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006799 new_instance_size -= map->inobject_properties() * kPointerSize;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006800 }
6801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006802 Handle<Map> result = RawCopy(map, new_instance_size);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006803
6804 if (mode != CLEAR_INOBJECT_PROPERTIES) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006805 result->set_inobject_properties(map->inobject_properties());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006806 }
6807
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006808 result->set_dictionary_map(true);
6809 result->set_migration_target(false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006810
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006811#ifdef VERIFY_HEAP
6812 if (FLAG_verify_heap) result->DictionaryMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006813#endif
6814
6815 return result;
6816}
6817
6818
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006819Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
6820 Handle<Map> result = RawCopy(map, map->instance_size());
6821
6822 // Please note instance_type and instance_size are set when allocated.
6823 result->set_inobject_properties(map->inobject_properties());
6824 result->set_unused_property_fields(map->unused_property_fields());
6825
6826 result->set_pre_allocated_property_fields(
6827 map->pre_allocated_property_fields());
6828 result->ClearCodeCache(map->GetHeap());
6829 map->NotifyLeafMapLayoutChange();
6830 return result;
6831}
6832
6833
6834Handle<Map> Map::ShareDescriptor(Handle<Map> map,
6835 Handle<DescriptorArray> descriptors,
6836 Descriptor* descriptor) {
6837 // Sanity check. This path is only to be taken if the map owns its descriptor
6838 // array, implying that its NumberOfOwnDescriptors equals the number of
6839 // descriptors in the descriptor array.
6840 DCHECK(map->NumberOfOwnDescriptors() ==
6841 map->instance_descriptors()->number_of_descriptors());
6842
6843 Handle<Map> result = CopyDropDescriptors(map);
6844 Handle<Name> name = descriptor->GetKey();
6845
6846 // Ensure there's space for the new descriptor in the shared descriptor array.
6847 if (descriptors->NumberOfSlackDescriptors() == 0) {
6848 int old_size = descriptors->number_of_descriptors();
6849 if (old_size == 0) {
6850 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
6851 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006852 EnsureDescriptorSlack(
6853 map, SlackForArraySize(old_size, kMaxNumberOfDescriptors));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006854 descriptors = handle(map->instance_descriptors());
6855 }
John Reck59135872010-11-02 12:39:01 -07006856 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006857
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006858 Handle<LayoutDescriptor> layout_descriptor =
6859 FLAG_unbox_double_fields
6860 ? LayoutDescriptor::Append(map, descriptor->GetDetails())
6861 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
6862
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006863 {
6864 DisallowHeapAllocation no_gc;
6865 descriptors->Append(descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006866 result->InitializeDescriptors(*descriptors, *layout_descriptor);
John Reck59135872010-11-02 12:39:01 -07006867 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006868
6869 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006870 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006871
6872 return result;
6873}
6874
6875
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006876#if TRACE_MAPS
6877
6878// static
6879void Map::TraceTransition(const char* what, Map* from, Map* to, Name* name) {
6880 if (FLAG_trace_maps) {
6881 PrintF("[TraceMaps: %s from= %p to= %p name= ", what,
6882 reinterpret_cast<void*>(from), reinterpret_cast<void*>(to));
6883 name->NameShortPrint();
6884 PrintF(" ]\n");
6885 }
6886}
6887
6888
6889// static
6890void Map::TraceAllTransitions(Map* map) {
6891 if (!map->HasTransitionArray()) return;
6892 TransitionArray* transitions = map->transitions();
6893 for (int i = 0; i < transitions->number_of_transitions(); ++i) {
6894 Map* target = transitions->GetTarget(i);
6895 Map::TraceTransition("Transition", map, target, transitions->GetKey(i));
6896 Map::TraceAllTransitions(target);
6897 }
6898}
6899
6900#endif // TRACE_MAPS
6901
6902
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006903void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
6904 Handle<Name> name, SimpleTransitionFlag flag) {
6905 parent->set_owns_descriptors(false);
6906 if (parent->is_prototype_map()) {
6907 DCHECK(child->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006908#if TRACE_MAPS
6909 Map::TraceTransition("NoTransition", *parent, *child, *name);
6910#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006911 } else {
6912 Handle<TransitionArray> transitions =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006913 TransitionArray::Insert(parent, name, child, flag);
6914 if (!parent->HasTransitionArray() ||
6915 *transitions != parent->transitions()) {
6916 parent->set_transitions(*transitions);
6917 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006918 child->SetBackPointer(*parent);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006919 if (child->prototype()->IsJSObject()) {
6920 Handle<JSObject> proto(JSObject::cast(child->prototype()));
6921 if (!child->ShouldRegisterAsPrototypeUser(proto)) {
6922 JSObject::UnregisterPrototypeUser(proto, child);
6923 }
6924 }
6925#if TRACE_MAPS
6926 Map::TraceTransition("Transition", *parent, *child, *name);
6927#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006928 }
6929}
6930
6931
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006932Handle<Map> Map::CopyReplaceDescriptors(
6933 Handle<Map> map, Handle<DescriptorArray> descriptors,
6934 Handle<LayoutDescriptor> layout_descriptor, TransitionFlag flag,
6935 MaybeHandle<Name> maybe_name, const char* reason,
6936 SimpleTransitionFlag simple_flag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006937 DCHECK(descriptors->IsSortedNoDuplicates());
6938
6939 Handle<Map> result = CopyDropDescriptors(map);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006940
6941 if (!map->is_prototype_map()) {
6942 if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006943 result->InitializeDescriptors(*descriptors, *layout_descriptor);
6944
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006945 Handle<Name> name;
6946 CHECK(maybe_name.ToHandle(&name));
6947 ConnectTransition(map, result, name, simple_flag);
6948 } else {
6949 int length = descriptors->number_of_descriptors();
6950 for (int i = 0; i < length; i++) {
6951 descriptors->SetRepresentation(i, Representation::Tagged());
6952 if (descriptors->GetDetails(i).type() == FIELD) {
6953 descriptors->SetValue(i, HeapType::Any());
6954 }
6955 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006956 result->InitializeDescriptors(*descriptors,
6957 LayoutDescriptor::FastPointerLayout());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006958 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006959 } else {
6960 result->InitializeDescriptors(*descriptors, *layout_descriptor);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006961 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006962#if TRACE_MAPS
6963 if (FLAG_trace_maps &&
6964 // Mirror conditions above that did not call ConnectTransition().
6965 (map->is_prototype_map() ||
6966 !(flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()))) {
6967 PrintF("[TraceMaps: ReplaceDescriptors from= %p to= %p reason= %s ]\n",
6968 reinterpret_cast<void*>(*map), reinterpret_cast<void*>(*result),
6969 reason);
6970 }
6971#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006972
6973 return result;
6974}
6975
6976
6977// Since this method is used to rewrite an existing transition tree, it can
6978// always insert transitions without checking.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006979Handle<Map> Map::CopyInstallDescriptors(
6980 Handle<Map> map, int new_descriptor, Handle<DescriptorArray> descriptors,
6981 Handle<LayoutDescriptor> full_layout_descriptor) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006982 DCHECK(descriptors->IsSortedNoDuplicates());
6983
6984 Handle<Map> result = CopyDropDescriptors(map);
6985
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006986 result->set_instance_descriptors(*descriptors);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006987 result->SetNumberOfOwnDescriptors(new_descriptor + 1);
6988
6989 int unused_property_fields = map->unused_property_fields();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006990 PropertyDetails details = descriptors->GetDetails(new_descriptor);
6991 if (details.type() == FIELD) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006992 unused_property_fields = map->unused_property_fields() - 1;
6993 if (unused_property_fields < 0) {
6994 unused_property_fields += JSObject::kFieldsAdded;
6995 }
6996 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006997 result->set_unused_property_fields(unused_property_fields);
6998
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006999 if (FLAG_unbox_double_fields) {
7000 Handle<LayoutDescriptor> layout_descriptor =
7001 LayoutDescriptor::AppendIfFastOrUseFull(map, details,
7002 full_layout_descriptor);
7003 result->set_layout_descriptor(*layout_descriptor);
7004 SLOW_DCHECK(result->layout_descriptor()->IsConsistentWithMap(*result));
7005 result->set_visitor_id(StaticVisitorBase::GetVisitorId(*result));
7006 }
7007
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007008 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007009 ConnectTransition(map, result, name, SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007010
7011 return result;
7012}
7013
7014
7015Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
7016 TransitionFlag flag) {
7017 if (flag == INSERT_TRANSITION) {
7018 DCHECK(!map->HasElementsTransition() ||
7019 ((map->elements_transition_map()->elements_kind() ==
7020 DICTIONARY_ELEMENTS ||
7021 IsExternalArrayElementsKind(
7022 map->elements_transition_map()->elements_kind())) &&
7023 (kind == DICTIONARY_ELEMENTS ||
7024 IsExternalArrayElementsKind(kind))));
7025 DCHECK(!IsFastElementsKind(kind) ||
7026 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
7027 DCHECK(kind != map->elements_kind());
7028 }
7029
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007030 bool insert_transition = flag == INSERT_TRANSITION &&
7031 map->CanHaveMoreTransitions() &&
7032 !map->HasElementsTransition();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007033
7034 if (insert_transition && map->owns_descriptors()) {
7035 // In case the map owned its own descriptors, share the descriptors and
7036 // transfer ownership to the new map.
7037 Handle<Map> new_map = CopyDropDescriptors(map);
7038
7039 ConnectElementsTransition(map, new_map);
7040
7041 new_map->set_elements_kind(kind);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007042 // The properties did not change, so reuse descriptors.
7043 new_map->InitializeDescriptors(map->instance_descriptors(),
7044 map->GetLayoutDescriptor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007045 return new_map;
7046 }
7047
7048 // In case the map did not own its own descriptors, a split is forced by
7049 // copying the map; creating a new descriptor array cell.
7050 // Create a new free-floating map only if we are not allowed to store it.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007051 Handle<Map> new_map = Copy(map, "CopyAsElementsKind");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007052
7053 new_map->set_elements_kind(kind);
7054
7055 if (insert_transition) {
7056 ConnectElementsTransition(map, new_map);
7057 }
7058
Steve Block8defd9f2010-07-08 12:39:36 +01007059 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00007060}
7061
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007062
7063Handle<Map> Map::CopyForObserved(Handle<Map> map) {
7064 DCHECK(!map->is_observed());
7065
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007066 Isolate* isolate = map->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007067
7068 // In case the map owned its own descriptors, share the descriptors and
7069 // transfer ownership to the new map.
7070 Handle<Map> new_map;
7071 if (map->owns_descriptors()) {
7072 new_map = CopyDropDescriptors(map);
7073 } else {
7074 DCHECK(!map->is_prototype_map());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007075 new_map = Copy(map, "CopyForObserved");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007076 }
7077
7078 new_map->set_is_observed();
7079 if (map->owns_descriptors()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007080 // The properties did not change, so reuse descriptors.
7081 new_map->InitializeDescriptors(map->instance_descriptors(),
7082 map->GetLayoutDescriptor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007083 }
7084
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007085 if (map->CanHaveMoreTransitions()) {
7086 Handle<Name> name = isolate->factory()->observed_symbol();
7087 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION);
7088 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007089 return new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007090}
Steve Blocka7e24c12009-10-30 11:49:00 +00007091
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007092
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007093Handle<Map> Map::Copy(Handle<Map> map, const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007094 Handle<DescriptorArray> descriptors(map->instance_descriptors());
7095 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
7096 Handle<DescriptorArray> new_descriptors =
7097 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007098 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
7099 map->GetIsolate());
7100 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
7101 OMIT_TRANSITION, MaybeHandle<Name>(), reason,
7102 SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007103}
7104
7105
7106Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007107 Handle<Map> copy =
7108 Copy(handle(isolate->object_function()->initial_map()), "MapCreate");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007109
7110 // Check that we do not overflow the instance size when adding the extra
7111 // inobject properties. If the instance size overflows, we allocate as many
7112 // properties as we can as inobject properties.
7113 int max_extra_properties =
7114 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
7115
7116 if (inobject_properties > max_extra_properties) {
7117 inobject_properties = max_extra_properties;
7118 }
7119
7120 int new_instance_size =
7121 JSObject::kHeaderSize + kPointerSize * inobject_properties;
7122
7123 // Adjust the map with the extra inobject properties.
7124 copy->set_inobject_properties(inobject_properties);
7125 copy->set_unused_property_fields(inobject_properties);
7126 copy->set_instance_size(new_instance_size);
7127 copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
7128 return copy;
7129}
7130
7131
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007132Handle<Map> Map::CopyForPreventExtensions(Handle<Map> map,
7133 PropertyAttributes attrs_to_add,
7134 Handle<Symbol> transition_marker,
7135 const char* reason) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007136 int num_descriptors = map->NumberOfOwnDescriptors();
7137 Isolate* isolate = map->GetIsolate();
7138 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007139 handle(map->instance_descriptors(), isolate), num_descriptors,
7140 attrs_to_add);
7141 Handle<LayoutDescriptor> new_layout_descriptor(map->GetLayoutDescriptor(),
7142 isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007143 Handle<Map> new_map = CopyReplaceDescriptors(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007144 map, new_desc, new_layout_descriptor, INSERT_TRANSITION,
7145 transition_marker, reason, SPECIAL_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007146 new_map->set_is_extensible(false);
7147 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
7148 return new_map;
7149}
7150
7151
7152bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
7153 PropertyDetails details = GetDetails(descriptor);
7154 switch (details.type()) {
7155 case FIELD:
7156 return value->FitsRepresentation(details.representation()) &&
7157 GetFieldType(descriptor)->NowContains(value);
7158
7159 case CONSTANT:
7160 DCHECK(GetConstant(descriptor) != value ||
7161 value->FitsRepresentation(details.representation()));
7162 return GetConstant(descriptor) == value;
7163
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007164 case ACCESSOR_FIELD:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007165 case CALLBACKS:
7166 return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007167 }
7168
7169 UNREACHABLE();
7170 return false;
7171}
7172
7173
7174Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
7175 Handle<Object> value) {
7176 // Dictionaries can store any property value.
7177 if (map->is_dictionary_map()) return map;
7178
7179 // Migrate to the newest map before storing the property.
7180 map = Update(map);
7181
7182 Handle<DescriptorArray> descriptors(map->instance_descriptors());
7183
7184 if (descriptors->CanHoldValue(descriptor, *value)) return map;
7185
7186 Isolate* isolate = map->GetIsolate();
7187 Representation representation = value->OptimalRepresentation();
7188 Handle<HeapType> type = value->OptimalType(isolate, representation);
7189
7190 return GeneralizeRepresentation(map, descriptor, representation, type,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007191 FORCE_IN_OBJECT);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007192}
7193
7194
7195Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
7196 Handle<Object> value,
7197 PropertyAttributes attributes,
7198 StoreFromKeyed store_mode) {
7199 // Dictionary maps can always have additional data properties.
7200 if (map->is_dictionary_map()) return map;
7201
7202 // Migrate to the newest map before storing the property.
7203 map = Update(map);
7204
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007205 int index = map->SearchTransition(DATA, *name, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007206 if (index != TransitionArray::kNotFound) {
7207 Handle<Map> transition(map->GetTransition(index));
7208 int descriptor = transition->LastAdded();
7209
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007210 DCHECK_EQ(attributes, transition->instance_descriptors()
7211 ->GetDetails(descriptor)
7212 .attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007213
7214 return Map::PrepareForDataProperty(transition, descriptor, value);
7215 }
7216
7217 TransitionFlag flag = INSERT_TRANSITION;
7218 MaybeHandle<Map> maybe_map;
7219 if (value->IsJSFunction()) {
7220 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
7221 } else if (!map->TooManyFastProperties(store_mode)) {
7222 Isolate* isolate = name->GetIsolate();
7223 Representation representation = value->OptimalRepresentation();
7224 Handle<HeapType> type = value->OptimalType(isolate, representation);
7225 maybe_map =
7226 Map::CopyWithField(map, name, type, attributes, representation, flag);
7227 }
7228
7229 Handle<Map> result;
7230 if (!maybe_map.ToHandle(&result)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007231#if TRACE_MAPS
7232 if (FLAG_trace_maps) {
7233 Vector<char> name_buffer = Vector<char>::New(100);
7234 name->NameShortPrint(name_buffer);
7235 Vector<char> buffer = Vector<char>::New(128);
7236 SNPrintF(buffer, "TooManyFastProperties %s", name_buffer.start());
7237 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, buffer.start());
7238 }
7239#endif
7240 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES,
7241 "TooManyFastProperties");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007242 }
7243
7244 return result;
7245}
7246
7247
7248Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
7249 PropertyAttributes attributes) {
7250 // Dictionaries have to be reconfigured in-place.
7251 DCHECK(!map->is_dictionary_map());
7252
7253 // For now, give up on transitioning and just create a unique map.
7254 // TODO(verwaest/ishell): Cache transitions with different attributes.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007255 return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_IN_OBJECT,
7256 attributes,
7257 "GenAll_AttributesMismatch");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007258}
7259
7260
7261Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
7262 Handle<Name> name,
7263 AccessorComponent component,
7264 Handle<Object> accessor,
7265 PropertyAttributes attributes) {
7266 Isolate* isolate = name->GetIsolate();
7267
7268 // Dictionary maps can always have additional data properties.
7269 if (map->is_dictionary_map()) {
7270 // For global objects, property cells are inlined. We need to change the
7271 // map.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007272 if (map->IsGlobalObjectMap()) return Copy(map, "GlobalAccessor");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007273 return map;
7274 }
7275
7276 // Migrate to the newest map before transitioning to the new property.
7277 map = Update(map);
7278
7279 PropertyNormalizationMode mode = map->is_prototype_map()
7280 ? KEEP_INOBJECT_PROPERTIES
7281 : CLEAR_INOBJECT_PROPERTIES;
7282
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007283 int index = map->SearchTransition(ACCESSOR, *name, attributes);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007284 if (index != TransitionArray::kNotFound) {
7285 Handle<Map> transition(map->GetTransition(index));
7286 DescriptorArray* descriptors = transition->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007287 int descriptor = transition->LastAdded();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007288 DCHECK(descriptors->GetKey(descriptor)->Equals(*name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007289
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007290 DCHECK_EQ(ACCESSOR, descriptors->GetDetails(descriptor).kind());
7291 DCHECK_EQ(attributes, descriptors->GetDetails(descriptor).attributes());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007292
7293 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
7294 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007295 return Map::Normalize(map, mode, "TransitionToAccessorFromNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007296 }
7297
7298 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
7299 if (pair->get(component) != *accessor) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007300 return Map::Normalize(map, mode, "TransitionToDifferentAccessor");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007301 }
7302
7303 return transition;
7304 }
7305
7306 Handle<AccessorPair> pair;
7307 DescriptorArray* old_descriptors = map->instance_descriptors();
7308 int descriptor = old_descriptors->SearchWithCache(*name, *map);
7309 if (descriptor != DescriptorArray::kNotFound) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007310 if (descriptor != map->LastAdded()) {
7311 return Map::Normalize(map, mode, "AccessorsOverwritingNonLast");
7312 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007313 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
7314 if (old_details.type() != CALLBACKS) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007315 return Map::Normalize(map, mode, "AccessorsOverwritingNonAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007316 }
7317
7318 if (old_details.attributes() != attributes) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007319 return Map::Normalize(map, mode, "AccessorsWithAttributes");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007320 }
7321
7322 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
7323 if (!maybe_pair->IsAccessorPair()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007324 return Map::Normalize(map, mode, "AccessorsOverwritingNonPair");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007325 }
7326
7327 Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
7328 if (current == *accessor) return map;
7329
7330 if (!current->IsTheHole()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007331 return Map::Normalize(map, mode, "AccessorsOverwritingAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007332 }
7333
7334 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
7335 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
7336 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007337 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES, "TooManyAccessors");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007338 } else {
7339 pair = isolate->factory()->NewAccessorPair();
7340 }
7341
7342 pair->set(component, *accessor);
7343 TransitionFlag flag = INSERT_TRANSITION;
7344 CallbacksDescriptor new_desc(name, pair, attributes);
7345 return Map::CopyInsertDescriptor(map, &new_desc, flag);
7346}
7347
7348
7349Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
7350 Descriptor* descriptor,
7351 TransitionFlag flag) {
7352 Handle<DescriptorArray> descriptors(map->instance_descriptors());
7353
7354 // Ensure the key is unique.
7355 descriptor->KeyToUniqueName();
7356
7357 if (flag == INSERT_TRANSITION &&
7358 map->owns_descriptors() &&
7359 map->CanHaveMoreTransitions()) {
7360 return ShareDescriptor(map, descriptors, descriptor);
7361 }
7362
7363 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
7364 descriptors, map->NumberOfOwnDescriptors(), 1);
7365 new_descriptors->Append(descriptor);
7366
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007367 Handle<LayoutDescriptor> new_layout_descriptor =
7368 FLAG_unbox_double_fields
7369 ? LayoutDescriptor::Append(map, descriptor->GetDetails())
7370 : handle(LayoutDescriptor::FastPointerLayout(), map->GetIsolate());
7371
7372 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
7373 flag, descriptor->GetKey(), "CopyAddDescriptor",
7374 SIMPLE_PROPERTY_TRANSITION);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007375}
7376
7377
7378Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
7379 Descriptor* descriptor,
7380 TransitionFlag flag) {
7381 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
7382
7383 // Ensure the key is unique.
7384 descriptor->KeyToUniqueName();
7385
7386 // We replace the key if it is already present.
7387 int index = old_descriptors->SearchWithCache(*descriptor->GetKey(), *map);
7388 if (index != DescriptorArray::kNotFound) {
7389 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
7390 }
7391 return CopyAddDescriptor(map, descriptor, flag);
7392}
7393
7394
7395Handle<DescriptorArray> DescriptorArray::CopyUpTo(
7396 Handle<DescriptorArray> desc,
7397 int enumeration_index,
7398 int slack) {
7399 return DescriptorArray::CopyUpToAddAttributes(
7400 desc, enumeration_index, NONE, slack);
7401}
7402
7403
7404Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
7405 Handle<DescriptorArray> desc,
7406 int enumeration_index,
7407 PropertyAttributes attributes,
7408 int slack) {
7409 if (enumeration_index + slack == 0) {
7410 return desc->GetIsolate()->factory()->empty_descriptor_array();
7411 }
7412
7413 int size = enumeration_index;
7414
7415 Handle<DescriptorArray> descriptors =
7416 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
7417 DescriptorArray::WhitenessWitness witness(*descriptors);
7418
7419 if (attributes != NONE) {
7420 for (int i = 0; i < size; ++i) {
7421 Object* value = desc->GetValue(i);
7422 Name* key = desc->GetKey(i);
7423 PropertyDetails details = desc->GetDetails(i);
7424 // Bulk attribute changes never affect private properties.
7425 if (!key->IsSymbol() || !Symbol::cast(key)->is_private()) {
7426 int mask = DONT_DELETE | DONT_ENUM;
7427 // READ_ONLY is an invalid attribute for JS setters/getters.
7428 if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
7429 mask |= READ_ONLY;
7430 }
7431 details = details.CopyAddAttributes(
7432 static_cast<PropertyAttributes>(attributes & mask));
7433 }
7434 Descriptor inner_desc(
7435 handle(key), handle(value, desc->GetIsolate()), details);
7436 descriptors->Set(i, &inner_desc, witness);
7437 }
7438 } else {
7439 for (int i = 0; i < size; ++i) {
7440 descriptors->CopyFrom(i, *desc, witness);
7441 }
7442 }
7443
7444 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
7445
7446 return descriptors;
7447}
7448
7449
7450Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
7451 Handle<DescriptorArray> descriptors,
7452 Descriptor* descriptor,
7453 int insertion_index,
7454 TransitionFlag flag) {
7455 // Ensure the key is unique.
7456 descriptor->KeyToUniqueName();
7457
7458 Handle<Name> key = descriptor->GetKey();
7459 DCHECK(*key == descriptors->GetKey(insertion_index));
7460
7461 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
7462 descriptors, map->NumberOfOwnDescriptors());
7463
7464 new_descriptors->Replace(insertion_index, descriptor);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007465 Handle<LayoutDescriptor> new_layout_descriptor = LayoutDescriptor::New(
7466 map, new_descriptors, new_descriptors->number_of_descriptors());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007467
7468 SimpleTransitionFlag simple_flag =
7469 (insertion_index == descriptors->number_of_descriptors() - 1)
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007470 ? SIMPLE_PROPERTY_TRANSITION
7471 : PROPERTY_TRANSITION;
7472 return CopyReplaceDescriptors(map, new_descriptors, new_layout_descriptor,
7473 flag, key, "CopyReplaceDescriptor",
7474 simple_flag);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007475}
7476
7477
7478void Map::UpdateCodeCache(Handle<Map> map,
7479 Handle<Name> name,
7480 Handle<Code> code) {
7481 Isolate* isolate = map->GetIsolate();
7482 HandleScope scope(isolate);
7483 // Allocate the code cache if not present.
7484 if (map->code_cache()->IsFixedArray()) {
7485 Handle<Object> result = isolate->factory()->NewCodeCache();
7486 map->set_code_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +01007487 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007488
Steve Block6ded16b2010-05-10 14:33:55 +01007489 // Update the code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007490 Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
7491 CodeCache::Update(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007492}
7493
7494
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007495Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007496 // Do a lookup if a code cache exists.
7497 if (!code_cache()->IsFixedArray()) {
7498 return CodeCache::cast(code_cache())->Lookup(name, flags);
7499 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007500 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007501 }
7502}
7503
7504
7505int Map::IndexInCodeCache(Object* name, Code* code) {
7506 // Get the internal index if a code cache exists.
7507 if (!code_cache()->IsFixedArray()) {
7508 return CodeCache::cast(code_cache())->GetIndex(name, code);
7509 }
7510 return -1;
7511}
7512
7513
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007514void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
Steve Block6ded16b2010-05-10 14:33:55 +01007515 // No GC is supposed to happen between a call to IndexInCodeCache and
7516 // RemoveFromCodeCache so the code cache must be there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007517 DCHECK(!code_cache()->IsFixedArray());
Steve Block6ded16b2010-05-10 14:33:55 +01007518 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7519}
7520
7521
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007522// An iterator over all map transitions in an descriptor array, reusing the
7523// constructor field of the map while it is running. Negative values in
7524// the constructor field indicate an active map transition iteration. The
7525// original constructor is restored after iterating over all entries.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007526class IntrusiveMapTransitionIterator {
7527 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007528 IntrusiveMapTransitionIterator(
7529 Map* map, TransitionArray* transition_array, Object* constructor)
7530 : map_(map),
7531 transition_array_(transition_array),
7532 constructor_(constructor) { }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007533
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007534 void StartIfNotStarted() {
7535 DCHECK(!(*IteratorField())->IsSmi() || IsIterating());
7536 if (!(*IteratorField())->IsSmi()) {
7537 DCHECK(*IteratorField() == constructor_);
7538 *IteratorField() = Smi::FromInt(-1);
7539 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007540 }
7541
7542 bool IsIterating() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007543 return (*IteratorField())->IsSmi() &&
7544 Smi::cast(*IteratorField())->value() < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007545 }
7546
7547 Map* Next() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007548 DCHECK(IsIterating());
7549 int value = Smi::cast(*IteratorField())->value();
7550 int index = -value - 1;
7551 int number_of_transitions = transition_array_->number_of_transitions();
Emily Bernierd0a1eb72015-03-24 16:35:39 -04007552 if (index < number_of_transitions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007553 *IteratorField() = Smi::FromInt(value - 1);
7554 return transition_array_->GetTarget(index);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007555 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007556
7557 *IteratorField() = constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007558 return NULL;
7559 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00007560
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007561 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007562 Object** IteratorField() {
7563 return HeapObject::RawField(map_, Map::kConstructorOffset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007564 }
7565
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007566 Map* map_;
7567 TransitionArray* transition_array_;
7568 Object* constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007569};
7570
7571
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007572// An iterator over all prototype transitions, reusing the constructor field
7573// of the map while it is running. Positive values in the constructor field
7574// indicate an active prototype transition iteration. The original constructor
7575// is restored after iterating over all entries.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007576class IntrusivePrototypeTransitionIterator {
7577 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007578 IntrusivePrototypeTransitionIterator(
7579 Map* map, HeapObject* proto_trans, Object* constructor)
7580 : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007581
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007582 void StartIfNotStarted() {
7583 if (!(*IteratorField())->IsSmi()) {
7584 DCHECK(*IteratorField() == constructor_);
7585 *IteratorField() = Smi::FromInt(0);
7586 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007587 }
7588
7589 bool IsIterating() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007590 return (*IteratorField())->IsSmi() &&
7591 Smi::cast(*IteratorField())->value() >= 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007592 }
7593
7594 Map* Next() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007595 DCHECK(IsIterating());
7596 int transitionNumber = Smi::cast(*IteratorField())->value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007597 if (transitionNumber < NumberOfTransitions()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007598 *IteratorField() = Smi::FromInt(transitionNumber + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007599 return GetTransition(transitionNumber);
7600 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007601 *IteratorField() = constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007602 return NULL;
7603 }
7604
7605 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007606 Object** IteratorField() {
7607 return HeapObject::RawField(map_, Map::kConstructorOffset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007608 }
7609
7610 int NumberOfTransitions() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007611 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7612 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007613 return Smi::cast(num)->value();
7614 }
7615
7616 Map* GetTransition(int transitionNumber) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007617 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7618 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007619 }
7620
7621 int IndexFor(int transitionNumber) {
7622 return Map::kProtoTransitionHeaderSize +
7623 Map::kProtoTransitionMapOffset +
7624 transitionNumber * Map::kProtoTransitionElementsPerEntry;
7625 }
7626
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007627 Map* map_;
7628 HeapObject* proto_trans_;
7629 Object* constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007630};
7631
7632
7633// To traverse the transition tree iteratively, we have to store two kinds of
7634// information in a map: The parent map in the traversal and which children of a
7635// node have already been visited. To do this without additional memory, we
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007636// temporarily reuse two fields with known values:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007637//
7638// (1) The map of the map temporarily holds the parent, and is restored to the
7639// meta map afterwards.
7640//
7641// (2) The info which children have already been visited depends on which part
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007642// of the map we currently iterate. We use the constructor field of the
7643// map to store the current index. We can do that because the constructor
7644// is the same for all involved maps.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007645//
7646// (a) If we currently follow normal map transitions, we temporarily store
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007647// the current index in the constructor field, and restore it to the
7648// original constructor afterwards. Note that a single descriptor can
7649// have 0, 1, or 2 transitions.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007650//
7651// (b) If we currently follow prototype transitions, we temporarily store
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007652// the current index in the constructor field, and restore it to the
7653// original constructor afterwards.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007654//
7655// Note that the child iterator is just a concatenation of two iterators: One
7656// iterating over map transitions and one iterating over prototype transisitons.
7657class TraversableMap : public Map {
7658 public:
7659 // Record the parent in the traversal within this map. Note that this destroys
7660 // this map's map!
7661 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7662
7663 // Reset the current map's map, returning the parent previously stored in it.
7664 TraversableMap* GetAndResetParent() {
7665 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7666 set_map_no_write_barrier(GetHeap()->meta_map());
7667 return old_parent;
7668 }
7669
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007670 // If we have an unvisited child map, return that one and advance. If we have
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007671 // none, return NULL and restore the overwritten constructor field.
7672 TraversableMap* ChildIteratorNext(Object* constructor) {
7673 if (!HasTransitionArray()) return NULL;
7674
7675 TransitionArray* transition_array = transitions();
7676 if (transition_array->HasPrototypeTransitions()) {
7677 HeapObject* proto_transitions =
7678 transition_array->GetPrototypeTransitions();
7679 IntrusivePrototypeTransitionIterator proto_iterator(this,
7680 proto_transitions,
7681 constructor);
7682 proto_iterator.StartIfNotStarted();
7683 if (proto_iterator.IsIterating()) {
7684 Map* next = proto_iterator.Next();
7685 if (next != NULL) return static_cast<TraversableMap*>(next);
7686 }
7687 }
7688
7689 IntrusiveMapTransitionIterator transition_iterator(this,
7690 transition_array,
7691 constructor);
7692 transition_iterator.StartIfNotStarted();
7693 if (transition_iterator.IsIterating()) {
7694 Map* next = transition_iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007695 if (next != NULL) return static_cast<TraversableMap*>(next);
7696 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007697
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007698 return NULL;
7699 }
7700};
7701
7702
7703// Traverse the transition tree in postorder without using the C++ stack by
7704// doing pointer reversal.
7705void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007706 // Make sure that we do not allocate in the callback.
7707 DisallowHeapAllocation no_allocation;
7708
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007709 TraversableMap* current = static_cast<TraversableMap*>(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007710 // Get the root constructor here to restore it later when finished iterating
7711 // over maps.
7712 Object* root_constructor = constructor();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007713 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007714 TraversableMap* child = current->ChildIteratorNext(root_constructor);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007715 if (child != NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007716 child->SetParent(current);
7717 current = child;
7718 } else {
7719 TraversableMap* parent = current->GetAndResetParent();
7720 callback(current, data);
7721 if (current == this) break;
7722 current = parent;
7723 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007724 }
7725}
7726
7727
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007728void CodeCache::Update(
7729 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007730 // The number of monomorphic stubs for normal load/store/call IC's can grow to
7731 // a large number and therefore they need to go into a hash table. They are
7732 // used to load global properties from cells.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007733 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +01007734 // Make sure that a hash table is allocated for the normal load code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007735 if (code_cache->normal_type_cache()->IsUndefined()) {
7736 Handle<Object> result =
7737 CodeCacheHashTable::New(code_cache->GetIsolate(),
7738 CodeCacheHashTable::kInitialSize);
7739 code_cache->set_normal_type_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +01007740 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007741 UpdateNormalTypeCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007742 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007743 DCHECK(code_cache->default_cache()->IsFixedArray());
7744 UpdateDefaultCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007745 }
7746}
7747
7748
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007749void CodeCache::UpdateDefaultCache(
7750 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007751 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00007752 // flags. This allows call constant stubs to overwrite call field
7753 // stubs, etc.
7754 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
7755
7756 // First check whether we can update existing code cache without
7757 // extending it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007758 Handle<FixedArray> cache = handle(code_cache->default_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00007759 int length = cache->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007760 {
7761 DisallowHeapAllocation no_alloc;
7762 int deleted_index = -1;
7763 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7764 Object* key = cache->get(i);
7765 if (key->IsNull()) {
7766 if (deleted_index < 0) deleted_index = i;
7767 continue;
7768 }
7769 if (key->IsUndefined()) {
7770 if (deleted_index >= 0) i = deleted_index;
7771 cache->set(i + kCodeCacheEntryNameOffset, *name);
7772 cache->set(i + kCodeCacheEntryCodeOffset, *code);
7773 return;
7774 }
7775 if (name->Equals(Name::cast(key))) {
7776 Code::Flags found =
7777 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
7778 if (Code::RemoveTypeFromFlags(found) == flags) {
7779 cache->set(i + kCodeCacheEntryCodeOffset, *code);
7780 return;
7781 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007782 }
7783 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007784
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007785 // Reached the end of the code cache. If there were deleted
7786 // elements, reuse the space for the first of them.
7787 if (deleted_index >= 0) {
7788 cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
7789 cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
7790 return;
7791 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007792 }
7793
Steve Block6ded16b2010-05-10 14:33:55 +01007794 // Extend the code cache with some new entries (at least one). Must be a
7795 // multiple of the entry size.
7796 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
7797 new_length = new_length - new_length % kCodeCacheEntrySize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007798 DCHECK((new_length % kCodeCacheEntrySize) == 0);
7799 cache = FixedArray::CopySize(cache, new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +00007800
7801 // Add the (name, code) pair to the new cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007802 cache->set(length + kCodeCacheEntryNameOffset, *name);
7803 cache->set(length + kCodeCacheEntryCodeOffset, *code);
7804 code_cache->set_default_cache(*cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00007805}
7806
7807
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007808void CodeCache::UpdateNormalTypeCache(
7809 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007810 // Adding a new entry can cause a new cache to be allocated.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007811 Handle<CodeCacheHashTable> cache(
7812 CodeCacheHashTable::cast(code_cache->normal_type_cache()));
7813 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
7814 code_cache->set_normal_type_cache(*new_cache);
Steve Block6ded16b2010-05-10 14:33:55 +01007815}
7816
7817
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007818Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
7819 Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
7820 if (result->IsCode()) {
7821 if (Code::cast(result)->flags() == flags) return result;
7822 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007823 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007824 return LookupNormalTypeCache(name, flags);
Steve Block6ded16b2010-05-10 14:33:55 +01007825}
7826
7827
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007828Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007829 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007830 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01007831 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7832 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00007833 // Skip deleted elements.
7834 if (key->IsNull()) continue;
7835 if (key->IsUndefined()) return key;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007836 if (name->Equals(Name::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01007837 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007838 if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007839 return code;
7840 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007841 }
7842 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01007843 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007844}
7845
7846
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007847Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007848 if (!normal_type_cache()->IsUndefined()) {
7849 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7850 return cache->Lookup(name, flags);
7851 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007852 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007853 }
7854}
7855
7856
7857int CodeCache::GetIndex(Object* name, Code* code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007858 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +01007859 if (normal_type_cache()->IsUndefined()) return -1;
7860 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007861 return cache->GetIndex(Name::cast(name), code->flags());
Steve Block6ded16b2010-05-10 14:33:55 +01007862 }
7863
7864 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007865 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01007866 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
7867 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00007868 }
7869 return -1;
7870}
7871
7872
Steve Block6ded16b2010-05-10 14:33:55 +01007873void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007874 if (code->type() == Code::NORMAL) {
7875 DCHECK(!normal_type_cache()->IsUndefined());
Steve Block6ded16b2010-05-10 14:33:55 +01007876 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007877 DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
Steve Block6ded16b2010-05-10 14:33:55 +01007878 cache->RemoveByIndex(index);
7879 } else {
7880 FixedArray* array = default_cache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007881 DCHECK(array->length() >= index && array->get(index)->IsCode());
Steve Block6ded16b2010-05-10 14:33:55 +01007882 // Use null instead of undefined for deleted elements to distinguish
7883 // deleted elements from unused elements. This distinction is used
7884 // when looking up in the cache and when updating the cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007885 DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
Steve Block6ded16b2010-05-10 14:33:55 +01007886 array->set_null(index - 1); // Name.
7887 array->set_null(index); // Code.
7888 }
7889}
7890
7891
7892// The key in the code cache hash table consists of the property name and the
7893// code object. The actual match is on the name and the code flags. If a key
7894// is created using the flags and not a code object it can only be used for
7895// lookup not to create a new entry.
7896class CodeCacheHashTableKey : public HashTableKey {
7897 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007898 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
7899 : name_(name), flags_(flags), code_() { }
Steve Block6ded16b2010-05-10 14:33:55 +01007900
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007901 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
7902 : name_(name), flags_(code->flags()), code_(code) { }
Steve Block6ded16b2010-05-10 14:33:55 +01007903
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007904 bool IsMatch(Object* other) OVERRIDE {
Steve Block6ded16b2010-05-10 14:33:55 +01007905 if (!other->IsFixedArray()) return false;
7906 FixedArray* pair = FixedArray::cast(other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007907 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +01007908 Code::Flags flags = Code::cast(pair->get(1))->flags();
7909 if (flags != flags_) {
7910 return false;
7911 }
7912 return name_->Equals(name);
7913 }
7914
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007915 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007916 return name->Hash() ^ flags;
7917 }
7918
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007919 uint32_t Hash() OVERRIDE { return NameFlagsHashHelper(*name_, flags_); }
Steve Block6ded16b2010-05-10 14:33:55 +01007920
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007921 uint32_t HashForObject(Object* obj) OVERRIDE {
Steve Block6ded16b2010-05-10 14:33:55 +01007922 FixedArray* pair = FixedArray::cast(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007923 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +01007924 Code* code = Code::cast(pair->get(1));
7925 return NameFlagsHashHelper(name, code->flags());
7926 }
7927
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007928 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
7929 Handle<Code> code = code_.ToHandleChecked();
7930 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
7931 pair->set(0, *name_);
7932 pair->set(1, *code);
Steve Block6ded16b2010-05-10 14:33:55 +01007933 return pair;
7934 }
7935
7936 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007937 Handle<Name> name_;
Steve Block6ded16b2010-05-10 14:33:55 +01007938 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007939 // TODO(jkummerow): We should be able to get by without this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007940 MaybeHandle<Code> code_;
Steve Block6ded16b2010-05-10 14:33:55 +01007941};
7942
7943
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007944Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
7945 DisallowHeapAllocation no_alloc;
7946 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +01007947 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01007948 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007949 return get(EntryToIndex(entry) + 1);
7950}
7951
7952
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007953Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
7954 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007955 CodeCacheHashTableKey key(name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007956
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007957 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
Steve Block6ded16b2010-05-10 14:33:55 +01007958
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007959 int entry = new_cache->FindInsertionEntry(key.Hash());
7960 Handle<Object> k = key.AsHandle(cache->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +01007961
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007962 new_cache->set(EntryToIndex(entry), *k);
7963 new_cache->set(EntryToIndex(entry) + 1, *code);
7964 new_cache->ElementAdded();
7965 return new_cache;
Steve Block6ded16b2010-05-10 14:33:55 +01007966}
7967
7968
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007969int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
7970 DisallowHeapAllocation no_alloc;
7971 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +01007972 int entry = FindEntry(&key);
7973 return (entry == kNotFound) ? -1 : entry;
7974}
7975
7976
7977void CodeCacheHashTable::RemoveByIndex(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007978 DCHECK(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007979 Heap* heap = GetHeap();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007980 set(EntryToIndex(index), heap->the_hole_value());
7981 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01007982 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00007983}
7984
7985
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007986void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007987 MapHandleList* maps,
7988 Code::Flags flags,
7989 Handle<Code> code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007990 Isolate* isolate = code_cache->GetIsolate();
7991 if (code_cache->cache()->IsUndefined()) {
7992 Handle<PolymorphicCodeCacheHashTable> result =
7993 PolymorphicCodeCacheHashTable::New(
7994 isolate,
7995 PolymorphicCodeCacheHashTable::kInitialSize);
7996 code_cache->set_cache(*result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007997 } else {
7998 // This entry shouldn't be contained in the cache yet.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007999 DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008000 ->Lookup(maps, flags)->IsUndefined());
8001 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008002 Handle<PolymorphicCodeCacheHashTable> hash_table =
8003 handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
8004 Handle<PolymorphicCodeCacheHashTable> new_cache =
8005 PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
8006 code_cache->set_cache(*new_cache);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008007}
8008
8009
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008010Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
8011 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008012 if (!cache()->IsUndefined()) {
8013 PolymorphicCodeCacheHashTable* hash_table =
8014 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008015 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008016 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008017 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008018 }
8019}
8020
8021
8022// Despite their name, object of this class are not stored in the actual
8023// hash table; instead they're temporarily used for lookups. It is therefore
8024// safe to have a weak (non-owning) pointer to a MapList as a member field.
8025class PolymorphicCodeCacheHashTableKey : public HashTableKey {
8026 public:
8027 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008028 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008029 : maps_(maps),
8030 code_flags_(code_flags) {}
8031
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008032 bool IsMatch(Object* other) OVERRIDE {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008033 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008034 int other_flags;
8035 FromObject(other, &other_flags, &other_maps);
8036 if (code_flags_ != other_flags) return false;
8037 if (maps_->length() != other_maps.length()) return false;
8038 // Compare just the hashes first because it's faster.
8039 int this_hash = MapsHashHelper(maps_, code_flags_);
8040 int other_hash = MapsHashHelper(&other_maps, other_flags);
8041 if (this_hash != other_hash) return false;
8042
8043 // Full comparison: for each map in maps_, look for an equivalent map in
8044 // other_maps. This implementation is slow, but probably good enough for
8045 // now because the lists are short (<= 4 elements currently).
8046 for (int i = 0; i < maps_->length(); ++i) {
8047 bool match_found = false;
8048 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008049 if (*(maps_->at(i)) == *(other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008050 match_found = true;
8051 break;
8052 }
8053 }
8054 if (!match_found) return false;
8055 }
8056 return true;
8057 }
8058
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008059 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008060 uint32_t hash = code_flags;
8061 for (int i = 0; i < maps->length(); ++i) {
8062 hash ^= maps->at(i)->Hash();
8063 }
8064 return hash;
8065 }
8066
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008067 uint32_t Hash() OVERRIDE {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008068 return MapsHashHelper(maps_, code_flags_);
8069 }
8070
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008071 uint32_t HashForObject(Object* obj) OVERRIDE {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008072 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008073 int other_flags;
8074 FromObject(obj, &other_flags, &other_maps);
8075 return MapsHashHelper(&other_maps, other_flags);
8076 }
8077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008078 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008079 // The maps in |maps_| must be copied to a newly allocated FixedArray,
8080 // both because the referenced MapList is short-lived, and because C++
8081 // objects can't be stored in the heap anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008082 Handle<FixedArray> list =
8083 isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008084 list->set(0, Smi::FromInt(code_flags_));
8085 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008086 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008087 }
8088 return list;
8089 }
8090
8091 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008092 static MapHandleList* FromObject(Object* obj,
8093 int* code_flags,
8094 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008095 FixedArray* list = FixedArray::cast(obj);
8096 maps->Rewind(0);
8097 *code_flags = Smi::cast(list->get(0))->value();
8098 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008099 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008100 }
8101 return maps;
8102 }
8103
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008104 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008105 int code_flags_;
8106 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
8107};
8108
8109
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008110Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008111 int code_kind) {
8112 DisallowHeapAllocation no_alloc;
8113 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008114 int entry = FindEntry(&key);
8115 if (entry == kNotFound) return GetHeap()->undefined_value();
8116 return get(EntryToIndex(entry) + 1);
8117}
8118
8119
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008120Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
8121 Handle<PolymorphicCodeCacheHashTable> hash_table,
8122 MapHandleList* maps,
8123 int code_kind,
8124 Handle<Code> code) {
8125 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
8126 Handle<PolymorphicCodeCacheHashTable> cache =
8127 EnsureCapacity(hash_table, 1, &key);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008128 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008129
8130 Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
8131 cache->set(EntryToIndex(entry), *obj);
8132 cache->set(EntryToIndex(entry) + 1, *code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008133 cache->ElementAdded();
8134 return cache;
8135}
8136
8137
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008138void FixedArray::Shrink(int new_length) {
8139 DCHECK(0 <= new_length && new_length <= length());
8140 if (new_length < length()) {
8141 GetHeap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(
8142 this, length() - new_length);
8143 }
8144}
8145
8146
8147MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008148 Handle<FixedArray> content, Handle<JSObject> array, KeyFilter filter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008149 DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008150 ElementsAccessor* accessor = array->GetElementsAccessor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008151 Handle<FixedArray> result;
8152 ASSIGN_RETURN_ON_EXCEPTION(
8153 array->GetIsolate(), result,
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008154 accessor->AddElementsToFixedArray(array, array, content, filter),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008155 FixedArray);
8156
8157#ifdef ENABLE_SLOW_DCHECKS
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008158 if (FLAG_enable_slow_asserts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008159 DisallowHeapAllocation no_allocation;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008160 for (int i = 0; i < result->length(); i++) {
8161 Object* current = result->get(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008162 DCHECK(current->IsNumber() || current->IsName());
Steve Blocka7e24c12009-10-30 11:49:00 +00008163 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008164 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008165#endif
8166 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008167}
8168
8169
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008170MaybeHandle<FixedArray> FixedArray::UnionOfKeys(Handle<FixedArray> first,
8171 Handle<FixedArray> second) {
8172 ElementsAccessor* accessor = ElementsAccessor::ForArray(second);
8173 Handle<FixedArray> result;
8174 ASSIGN_RETURN_ON_EXCEPTION(
8175 first->GetIsolate(), result,
8176 accessor->AddElementsToFixedArray(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008177 Handle<Object>::null(), // receiver
8178 Handle<JSObject>::null(), // holder
8179 first, Handle<FixedArrayBase>::cast(second), ALL_KEYS),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008180 FixedArray);
8181
8182#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochf87a2032010-10-22 12:50:53 +01008183 if (FLAG_enable_slow_asserts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008184 DisallowHeapAllocation no_allocation;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008185 for (int i = 0; i < result->length(); i++) {
8186 Object* current = result->get(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008187 DCHECK(current->IsNumber() || current->IsName());
Ben Murdochf87a2032010-10-22 12:50:53 +01008188 }
8189 }
8190#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00008191 return result;
8192}
8193
8194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008195Handle<FixedArray> FixedArray::CopySize(
8196 Handle<FixedArray> array, int new_length, PretenureFlag pretenure) {
8197 Isolate* isolate = array->GetIsolate();
8198 if (new_length == 0) return isolate->factory()->empty_fixed_array();
8199 Handle<FixedArray> result =
8200 isolate->factory()->NewFixedArray(new_length, pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +00008201 // Copy the content
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008202 DisallowHeapAllocation no_gc;
8203 int len = array->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008204 if (new_length < len) len = new_length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008205 // We are taking the map from the old fixed array so the map is sure to
8206 // be an immortal immutable object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008207 result->set_map_no_write_barrier(array->map());
Leon Clarke4515c472010-02-03 11:58:03 +00008208 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008209 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008210 result->set(i, array->get(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00008211 }
8212 return result;
8213}
8214
8215
8216void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008217 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +00008218 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008219 for (int index = 0; index < len; index++) {
8220 dest->set(dest_pos+index, get(pos+index), mode);
8221 }
8222}
8223
8224
8225#ifdef DEBUG
8226bool FixedArray::IsEqualTo(FixedArray* other) {
8227 if (length() != other->length()) return false;
8228 for (int i = 0 ; i < length(); ++i) {
8229 if (get(i) != other->get(i)) return false;
8230 }
8231 return true;
8232}
8233#endif
8234
8235
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008236// static
8237void WeakFixedArray::Set(Handle<WeakFixedArray> array, int index,
8238 Handle<HeapObject> value) {
8239 DCHECK(array->IsEmptySlot(index)); // Don't overwrite anything.
8240 Handle<WeakCell> cell =
8241 value->IsMap() ? Map::WeakCellForMap(Handle<Map>::cast(value))
8242 : array->GetIsolate()->factory()->NewWeakCell(value);
8243 Handle<FixedArray>::cast(array)->set(index + kFirstIndex, *cell);
8244 if (FLAG_trace_weak_arrays) {
8245 PrintF("[WeakFixedArray: storing at index %d ]\n", index);
8246 }
8247 array->set_last_used_index(index);
8248}
8249
8250
8251// static
8252Handle<WeakFixedArray> WeakFixedArray::Add(
8253 Handle<Object> maybe_array, Handle<HeapObject> value,
8254 SearchForDuplicates search_for_duplicates) {
8255 Handle<WeakFixedArray> array =
8256 (maybe_array.is_null() || !maybe_array->IsWeakFixedArray())
8257 ? Allocate(value->GetIsolate(), 1, Handle<WeakFixedArray>::null())
8258 : Handle<WeakFixedArray>::cast(maybe_array);
8259
8260 if (search_for_duplicates == kAddIfNotFound) {
8261 for (int i = 0; i < array->Length(); ++i) {
8262 if (array->Get(i) == *value) return array;
8263 }
8264 } else {
8265#ifdef DEBUG
8266 for (int i = 0; i < array->Length(); ++i) {
8267 DCHECK_NE(*value, array->Get(i));
8268 }
8269#endif
8270 }
8271
8272 // Try to store the new entry if there's room. Optimize for consecutive
8273 // accesses.
8274 int first_index = array->last_used_index();
8275 for (int i = first_index;;) {
8276 if (array->IsEmptySlot((i))) {
8277 WeakFixedArray::Set(array, i, value);
8278 return array;
8279 }
8280 if (FLAG_trace_weak_arrays) {
8281 PrintF("[WeakFixedArray: searching for free slot]\n");
8282 }
8283 i = (i + 1) % array->Length();
8284 if (i == first_index) break;
8285 }
8286
8287 // No usable slot found, grow the array.
8288 int new_length = array->Length() + (array->Length() >> 1) + 4;
8289 Handle<WeakFixedArray> new_array =
8290 Allocate(array->GetIsolate(), new_length, array);
8291 if (FLAG_trace_weak_arrays) {
8292 PrintF("[WeakFixedArray: growing to size %d ]\n", new_length);
8293 }
8294 WeakFixedArray::Set(new_array, array->Length(), value);
8295 return new_array;
8296}
8297
8298
8299void WeakFixedArray::Remove(Handle<HeapObject> value) {
8300 // Optimize for the most recently added element to be removed again.
8301 int first_index = last_used_index();
8302 for (int i = first_index;;) {
8303 if (Get(i) == *value) {
8304 clear(i);
8305 // Users of WeakFixedArray should make sure that there are no duplicates,
8306 // they can use Add(..., kAddIfNotFound) if necessary.
8307 return;
8308 }
8309 i = (i + 1) % Length();
8310 if (i == first_index) break;
8311 }
8312}
8313
8314
8315// static
8316Handle<WeakFixedArray> WeakFixedArray::Allocate(
8317 Isolate* isolate, int size, Handle<WeakFixedArray> initialize_from) {
8318 DCHECK(0 <= size);
8319 Handle<FixedArray> result =
8320 isolate->factory()->NewUninitializedFixedArray(size + kFirstIndex);
8321 Handle<WeakFixedArray> casted_result = Handle<WeakFixedArray>::cast(result);
8322 if (initialize_from.is_null()) {
8323 for (int i = 0; i < result->length(); ++i) {
8324 result->set(i, Smi::FromInt(0));
8325 }
8326 } else {
8327 DCHECK(initialize_from->Length() <= size);
8328 Handle<FixedArray> raw_source = Handle<FixedArray>::cast(initialize_from);
8329 int target_index = kFirstIndex;
8330 for (int source_index = kFirstIndex; source_index < raw_source->length();
8331 ++source_index) {
8332 // The act of allocating might have caused entries in the source array
8333 // to be cleared. Copy only what's needed.
8334 if (initialize_from->IsEmptySlot(source_index - kFirstIndex)) continue;
8335 result->set(target_index++, raw_source->get(source_index));
8336 }
8337 casted_result->set_last_used_index(target_index - 1 - kFirstIndex);
8338 for (; target_index < result->length(); ++target_index) {
8339 result->set(target_index, Smi::FromInt(0));
8340 }
8341 }
8342 return casted_result;
8343}
8344
8345
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008346Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
8347 int number_of_descriptors,
8348 int slack) {
8349 DCHECK(0 <= number_of_descriptors);
8350 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +00008351 // Do not use DescriptorArray::cast on incomplete object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008352 int size = number_of_descriptors + slack;
8353 if (size == 0) return factory->empty_descriptor_array();
8354 // Allocate the array of keys.
8355 Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size));
Steve Blocka7e24c12009-10-30 11:49:00 +00008356
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008357 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
8358 result->set(kEnumCacheIndex, Smi::FromInt(0));
8359 return Handle<DescriptorArray>::cast(result);
8360}
8361
8362
8363void DescriptorArray::ClearEnumCache() {
8364 set(kEnumCacheIndex, Smi::FromInt(0));
8365}
8366
8367
8368void DescriptorArray::Replace(int index, Descriptor* descriptor) {
8369 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
8370 Set(index, descriptor);
Steve Blocka7e24c12009-10-30 11:49:00 +00008371}
8372
8373
8374void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008375 FixedArray* new_cache,
8376 Object* new_index_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008377 DCHECK(bridge_storage->length() >= kEnumCacheBridgeLength);
8378 DCHECK(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
8379 DCHECK(!IsEmpty());
8380 DCHECK(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
8381 FixedArray::cast(bridge_storage)->
8382 set(kEnumCacheBridgeCacheIndex, new_cache);
8383 FixedArray::cast(bridge_storage)->
8384 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
8385 set(kEnumCacheIndex, bridge_storage);
Steve Blocka7e24c12009-10-30 11:49:00 +00008386}
8387
8388
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008389void DescriptorArray::CopyFrom(int index, DescriptorArray* src,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008390 const WhitenessWitness& witness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008391 Object* value = src->GetValue(index);
8392 PropertyDetails details = src->GetDetails(index);
8393 Descriptor desc(handle(src->GetKey(index)),
8394 handle(value, src->GetIsolate()),
8395 details);
8396 Set(index, &desc, witness);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008397}
8398
8399
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008400// We need the whiteness witness since sort will reshuffle the entries in the
8401// descriptor array. If the descriptor array were to be black, the shuffling
8402// would move a slot that was already recorded as pointing into an evacuation
8403// candidate. This would result in missing updates upon evacuation.
8404void DescriptorArray::Sort() {
Steve Blocka7e24c12009-10-30 11:49:00 +00008405 // In-place heap sort.
8406 int len = number_of_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008407 // Reset sorting since the descriptor array might contain invalid pointers.
8408 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00008409 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01008410 // Index of the last node with children
8411 const int max_parent_index = (len / 2) - 1;
8412 for (int i = max_parent_index; i >= 0; --i) {
8413 int parent_index = i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008414 const uint32_t parent_hash = GetSortedKey(i)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01008415 while (parent_index <= max_parent_index) {
8416 int child_index = 2 * parent_index + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008417 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01008418 if (child_index + 1 < len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008419 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01008420 if (right_child_hash > child_hash) {
8421 child_index++;
8422 child_hash = right_child_hash;
8423 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008424 }
Steve Block6ded16b2010-05-10 14:33:55 +01008425 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008426 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01008427 // Now element at child_index could be < its children.
8428 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00008429 }
8430 }
8431
8432 // Extract elements and create sorted array.
8433 for (int i = len - 1; i > 0; --i) {
8434 // Put max element at the back of the array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008435 SwapSortedKeys(0, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008436 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00008437 int parent_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008438 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01008439 const int max_parent_index = (i / 2) - 1;
8440 while (parent_index <= max_parent_index) {
8441 int child_index = parent_index * 2 + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008442 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01008443 if (child_index + 1 < i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008444 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01008445 if (right_child_hash > child_hash) {
8446 child_index++;
8447 child_hash = right_child_hash;
8448 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008449 }
Steve Block6ded16b2010-05-10 14:33:55 +01008450 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008451 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01008452 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00008453 }
8454 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008455 DCHECK(IsSortedNoDuplicates());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008456}
Steve Blocka7e24c12009-10-30 11:49:00 +00008457
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008458
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008459Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
8460 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
8461 copy->set_getter(pair->getter());
8462 copy->set_setter(pair->setter());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008463 return copy;
8464}
8465
8466
8467Object* AccessorPair::GetComponent(AccessorComponent component) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008468 Object* accessor = get(component);
8469 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008470}
8471
8472
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008473Handle<DeoptimizationInputData> DeoptimizationInputData::New(
8474 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
8475 DCHECK(deopt_entry_count > 0);
8476 return Handle<DeoptimizationInputData>::cast(
8477 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
8478 pretenure));
Ben Murdochb0fe1622011-05-05 13:52:32 +01008479}
8480
8481
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008482Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
8483 Isolate* isolate,
8484 int number_of_deopt_points,
8485 PretenureFlag pretenure) {
8486 Handle<FixedArray> result;
8487 if (number_of_deopt_points == 0) {
8488 result = isolate->factory()->empty_fixed_array();
8489 } else {
8490 result = isolate->factory()->NewFixedArray(
8491 LengthOfFixedArray(number_of_deopt_points), pretenure);
8492 }
8493 return Handle<DeoptimizationOutputData>::cast(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +01008494}
8495
8496
Steve Blocka7e24c12009-10-30 11:49:00 +00008497#ifdef DEBUG
8498bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
8499 if (IsEmpty()) return other->IsEmpty();
8500 if (other->IsEmpty()) return false;
8501 if (length() != other->length()) return false;
8502 for (int i = 0; i < length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008503 if (get(i) != other->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008504 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008505 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008506}
8507#endif
8508
8509
Steve Blocka7e24c12009-10-30 11:49:00 +00008510bool String::LooksValid() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008511 if (!GetIsolate()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008512 return true;
8513}
8514
8515
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008516String::FlatContent String::GetFlatContent() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008517 DCHECK(!AllowHeapAllocation::IsAllowed());
Steve Blocka7e24c12009-10-30 11:49:00 +00008518 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008519 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008520 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00008521 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008522 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008523 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008524 if (cons->second()->length() != 0) {
8525 return FlatContent();
8526 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008527 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008528 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00008529 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008530 if (shape.representation_tag() == kSlicedStringTag) {
8531 SlicedString* slice = SlicedString::cast(string);
8532 offset = slice->offset();
8533 string = slice->parent();
8534 shape = StringShape(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008535 DCHECK(shape.representation_tag() != kConsStringTag &&
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008536 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00008537 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008538 if (shape.encoding_tag() == kOneByteStringTag) {
8539 const uint8_t* start;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008540 if (shape.representation_tag() == kSeqStringTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008541 start = SeqOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008542 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008543 start = ExternalOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008544 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008545 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008546 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008547 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008548 const uc16* start;
8549 if (shape.representation_tag() == kSeqStringTag) {
8550 start = SeqTwoByteString::cast(string)->GetChars();
8551 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008552 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008553 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008554 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008555 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008556}
8557
8558
Ben Murdoch589d6972011-11-30 16:04:58 +00008559SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8560 RobustnessFlag robust_flag,
8561 int offset,
8562 int length,
8563 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008564 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00008565 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008566 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008567 // Negative length means the to the end of the string.
8568 if (length < 0) length = kMaxInt - offset;
8569
8570 // Compute the size of the UTF-8 string. Start at the specified offset.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008571 StringCharacterStream stream(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00008572 int character_position = offset;
8573 int utf8_bytes = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008574 int last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008575 while (stream.HasMore() && character_position++ < offset + length) {
8576 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008577 utf8_bytes += unibrow::Utf8::Length(character, last);
8578 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +00008579 }
8580
8581 if (length_return) {
8582 *length_return = utf8_bytes;
8583 }
8584
8585 char* result = NewArray<char>(utf8_bytes + 1);
8586
8587 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008588 stream.Reset(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00008589 character_position = offset;
8590 int utf8_byte_position = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008591 last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008592 while (stream.HasMore() && character_position++ < offset + length) {
8593 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008594 if (allow_nulls == DISALLOW_NULLS && character == 0) {
8595 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +00008596 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008597 utf8_byte_position +=
8598 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8599 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +00008600 }
8601 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00008602 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00008603}
8604
8605
Ben Murdoch589d6972011-11-30 16:04:58 +00008606SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8607 RobustnessFlag robust_flag,
8608 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008609 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8610}
8611
8612
Steve Blocka7e24c12009-10-30 11:49:00 +00008613const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008614 DCHECK(!IsOneByteRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00008615 switch (StringShape(this).representation_tag()) {
8616 case kSeqStringTag:
8617 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
8618 case kExternalStringTag:
8619 return ExternalTwoByteString::cast(this)->
8620 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008621 case kSlicedStringTag: {
8622 SlicedString* slice = SlicedString::cast(this);
8623 return slice->parent()->GetTwoByteData(start + slice->offset());
8624 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008625 case kConsStringTag:
8626 UNREACHABLE();
8627 return NULL;
8628 }
8629 UNREACHABLE();
8630 return NULL;
8631}
8632
8633
Ben Murdoch589d6972011-11-30 16:04:58 +00008634SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008635 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00008636 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008637 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008638 StringCharacterStream stream(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008639
8640 uc16* result = NewArray<uc16>(length() + 1);
8641
8642 int i = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008643 while (stream.HasMore()) {
8644 uint16_t character = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00008645 result[i++] = character;
8646 }
8647 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00008648 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00008649}
8650
8651
8652const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
8653 return reinterpret_cast<uc16*>(
8654 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
8655}
8656
8657
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008658void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +01008659 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00008660 while (current != NULL) {
8661 current->PostGarbageCollection();
8662 current = current->prev_;
8663 }
8664}
8665
8666
8667// Reserve space for statics needing saving and restoring.
8668int Relocatable::ArchiveSpacePerThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008669 return sizeof(Relocatable*); // NOLINT
Steve Blocka7e24c12009-10-30 11:49:00 +00008670}
8671
8672
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008673// Archive statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +00008674char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01008675 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
8676 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008677 return to + ArchiveSpacePerThread();
8678}
8679
8680
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008681// Restore statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +00008682char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01008683 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00008684 return from + ArchiveSpacePerThread();
8685}
8686
8687
8688char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
8689 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
8690 Iterate(v, top);
8691 return thread_storage + ArchiveSpacePerThread();
8692}
8693
8694
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008695void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01008696 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00008697}
8698
8699
8700void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
8701 Relocatable* current = top;
8702 while (current != NULL) {
8703 current->IterateInstance(v);
8704 current = current->prev_;
8705 }
8706}
8707
8708
Steve Block44f0eee2011-05-26 01:26:41 +01008709FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
8710 : Relocatable(isolate),
8711 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00008712 length_(str->length()) {
8713 PostGarbageCollection();
8714}
8715
8716
Steve Block44f0eee2011-05-26 01:26:41 +01008717FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
8718 : Relocatable(isolate),
8719 str_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008720 is_one_byte_(true),
Steve Blocka7e24c12009-10-30 11:49:00 +00008721 length_(input.length()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008722 start_(input.start()) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00008723
8724
8725void FlatStringReader::PostGarbageCollection() {
8726 if (str_ == NULL) return;
8727 Handle<String> str(str_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008728 DCHECK(str->IsFlat());
8729 DisallowHeapAllocation no_gc;
8730 // This does not actually prevent the vector from being relocated later.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008731 String::FlatContent content = str->GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008732 DCHECK(content.IsFlat());
8733 is_one_byte_ = content.IsOneByte();
8734 if (is_one_byte_) {
8735 start_ = content.ToOneByteVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00008736 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008737 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00008738 }
8739}
8740
8741
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008742void ConsStringIterator::Initialize(ConsString* cons_string, int offset) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008743 DCHECK(cons_string != NULL);
8744 root_ = cons_string;
8745 consumed_ = offset;
8746 // Force stack blown condition to trigger restart.
8747 depth_ = 1;
8748 maximum_depth_ = kStackSize + depth_;
8749 DCHECK(StackBlown());
Steve Blocka7e24c12009-10-30 11:49:00 +00008750}
8751
8752
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008753String* ConsStringIterator::Continue(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008754 DCHECK(depth_ != 0);
8755 DCHECK_EQ(0, *offset_out);
8756 bool blew_stack = StackBlown();
8757 String* string = NULL;
8758 // Get the next leaf if there is one.
8759 if (!blew_stack) string = NextLeaf(&blew_stack);
8760 // Restart search from root.
8761 if (blew_stack) {
8762 DCHECK(string == NULL);
8763 string = Search(offset_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008764 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008765 // Ensure future calls return null immediately.
8766 if (string == NULL) Reset(NULL);
8767 return string;
Steve Blocka7e24c12009-10-30 11:49:00 +00008768}
8769
8770
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008771String* ConsStringIterator::Search(int* offset_out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008772 ConsString* cons_string = root_;
8773 // Reset the stack, pushing the root string.
8774 depth_ = 1;
8775 maximum_depth_ = 1;
8776 frames_[0] = cons_string;
8777 const int consumed = consumed_;
8778 int offset = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008779 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008780 // Loop until the string is found which contains the target offset.
8781 String* string = cons_string->first();
8782 int length = string->length();
8783 int32_t type;
8784 if (consumed < offset + length) {
8785 // Target offset is in the left branch.
8786 // Keep going if we're still in a ConString.
8787 type = string->map()->instance_type();
8788 if ((type & kStringRepresentationMask) == kConsStringTag) {
8789 cons_string = ConsString::cast(string);
8790 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00008791 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00008792 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008793 // Tell the stack we're done descending.
8794 AdjustMaximumDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +00008795 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008796 // Descend right.
8797 // Update progress through the string.
8798 offset += length;
8799 // Keep going if we're still in a ConString.
8800 string = cons_string->second();
8801 type = string->map()->instance_type();
8802 if ((type & kStringRepresentationMask) == kConsStringTag) {
8803 cons_string = ConsString::cast(string);
8804 PushRight(cons_string);
8805 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00008806 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008807 // Need this to be updated for the current string.
8808 length = string->length();
8809 // Account for the possibility of an empty right leaf.
8810 // This happens only if we have asked for an offset outside the string.
8811 if (length == 0) {
8812 // Reset so future operations will return null immediately.
8813 Reset(NULL);
8814 return NULL;
8815 }
8816 // Tell the stack we're done descending.
8817 AdjustMaximumDepth();
8818 // Pop stack so next iteration is in correct place.
8819 Pop();
8820 }
8821 DCHECK(length != 0);
8822 // Adjust return values and exit.
8823 consumed_ = offset + length;
8824 *offset_out = consumed - offset;
8825 return string;
8826 }
8827 UNREACHABLE();
8828 return NULL;
8829}
8830
8831
Emily Bernierd0a1eb72015-03-24 16:35:39 -04008832String* ConsStringIterator::NextLeaf(bool* blew_stack) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008833 while (true) {
8834 // Tree traversal complete.
8835 if (depth_ == 0) {
8836 *blew_stack = false;
8837 return NULL;
8838 }
8839 // We've lost track of higher nodes.
8840 if (StackBlown()) {
8841 *blew_stack = true;
8842 return NULL;
8843 }
8844 // Go right.
8845 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
8846 String* string = cons_string->second();
8847 int32_t type = string->map()->instance_type();
8848 if ((type & kStringRepresentationMask) != kConsStringTag) {
8849 // Pop stack so next iteration is in correct place.
8850 Pop();
8851 int length = string->length();
8852 // Could be a flattened ConsString.
8853 if (length == 0) continue;
8854 consumed_ += length;
8855 return string;
8856 }
8857 cons_string = ConsString::cast(string);
8858 PushRight(cons_string);
8859 // Need to traverse all the way left.
8860 while (true) {
8861 // Continue left.
8862 string = cons_string->first();
8863 type = string->map()->instance_type();
8864 if ((type & kStringRepresentationMask) != kConsStringTag) {
8865 AdjustMaximumDepth();
8866 int length = string->length();
8867 DCHECK(length != 0);
8868 consumed_ += length;
8869 return string;
8870 }
8871 cons_string = ConsString::cast(string);
8872 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00008873 }
8874 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008875 UNREACHABLE();
8876 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00008877}
8878
8879
Steve Blocka7e24c12009-10-30 11:49:00 +00008880uint16_t ConsString::ConsStringGet(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008881 DCHECK(index >= 0 && index < this->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008882
8883 // Check for a flattened cons string
8884 if (second()->length() == 0) {
8885 String* left = first();
8886 return left->Get(index);
8887 }
8888
8889 String* string = String::cast(this);
8890
8891 while (true) {
8892 if (StringShape(string).IsCons()) {
8893 ConsString* cons_string = ConsString::cast(string);
8894 String* left = cons_string->first();
8895 if (left->length() > index) {
8896 string = left;
8897 } else {
8898 index -= left->length();
8899 string = cons_string->second();
8900 }
8901 } else {
8902 return string->Get(index);
8903 }
8904 }
8905
8906 UNREACHABLE();
8907 return 0;
8908}
8909
8910
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008911uint16_t SlicedString::SlicedStringGet(int index) {
8912 return parent()->Get(offset() + index);
8913}
8914
8915
Steve Blocka7e24c12009-10-30 11:49:00 +00008916template <typename sinkchar>
8917void String::WriteToFlat(String* src,
8918 sinkchar* sink,
8919 int f,
8920 int t) {
8921 String* source = src;
8922 int from = f;
8923 int to = t;
8924 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008925 DCHECK(0 <= from && from <= to && to <= source->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008926 switch (StringShape(source).full_representation_tag()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008927 case kOneByteStringTag | kExternalStringTag: {
8928 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00008929 to - from);
8930 return;
8931 }
8932 case kTwoByteStringTag | kExternalStringTag: {
8933 const uc16* data =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008934 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00008935 CopyChars(sink,
8936 data + from,
8937 to - from);
8938 return;
8939 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008940 case kOneByteStringTag | kSeqStringTag: {
Steve Blocka7e24c12009-10-30 11:49:00 +00008941 CopyChars(sink,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008942 SeqOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00008943 to - from);
8944 return;
8945 }
8946 case kTwoByteStringTag | kSeqStringTag: {
8947 CopyChars(sink,
8948 SeqTwoByteString::cast(source)->GetChars() + from,
8949 to - from);
8950 return;
8951 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008952 case kOneByteStringTag | kConsStringTag:
Steve Blocka7e24c12009-10-30 11:49:00 +00008953 case kTwoByteStringTag | kConsStringTag: {
8954 ConsString* cons_string = ConsString::cast(source);
8955 String* first = cons_string->first();
8956 int boundary = first->length();
8957 if (to - boundary >= boundary - from) {
8958 // Right hand side is longer. Recurse over left.
8959 if (from < boundary) {
8960 WriteToFlat(first, sink, from, boundary);
8961 sink += boundary - from;
8962 from = 0;
8963 } else {
8964 from -= boundary;
8965 }
8966 to -= boundary;
8967 source = cons_string->second();
8968 } else {
8969 // Left hand side is longer. Recurse over right.
8970 if (to > boundary) {
8971 String* second = cons_string->second();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008972 // When repeatedly appending to a string, we get a cons string that
8973 // is unbalanced to the left, a list, essentially. We inline the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008974 // common case of sequential one-byte right child.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008975 if (to - boundary == 1) {
8976 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008977 } else if (second->IsSeqOneByteString()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008978 CopyChars(sink + boundary - from,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008979 SeqOneByteString::cast(second)->GetChars(),
Steve Blocka7e24c12009-10-30 11:49:00 +00008980 to - boundary);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008981 } else {
8982 WriteToFlat(second,
8983 sink + boundary - from,
8984 0,
8985 to - boundary);
8986 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008987 to = boundary;
8988 }
8989 source = first;
8990 }
8991 break;
8992 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008993 case kOneByteStringTag | kSlicedStringTag:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008994 case kTwoByteStringTag | kSlicedStringTag: {
8995 SlicedString* slice = SlicedString::cast(source);
8996 unsigned offset = slice->offset();
8997 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8998 return;
8999 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009000 }
9001 }
9002}
9003
9004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009005
9006template <typename SourceChar>
9007static void CalculateLineEndsImpl(Isolate* isolate,
9008 List<int>* line_ends,
9009 Vector<const SourceChar> src,
9010 bool include_ending_line) {
9011 const int src_len = src.length();
9012 StringSearch<uint8_t, SourceChar> search(isolate, STATIC_CHAR_VECTOR("\n"));
9013
9014 // Find and record line ends.
9015 int position = 0;
9016 while (position != -1 && position < src_len) {
9017 position = search.Search(src, position);
9018 if (position != -1) {
9019 line_ends->Add(position);
9020 position++;
9021 } else if (include_ending_line) {
9022 // Even if the last line misses a line end, it is counted.
9023 line_ends->Add(src_len);
9024 return;
9025 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009026 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009027}
9028
9029
9030Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
9031 bool include_ending_line) {
9032 src = Flatten(src);
9033 // Rough estimate of line count based on a roughly estimated average
9034 // length of (unpacked) code.
9035 int line_count_estimate = src->length() >> 4;
9036 List<int> line_ends(line_count_estimate);
9037 Isolate* isolate = src->GetIsolate();
9038 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
9039 // Dispatch on type of strings.
9040 String::FlatContent content = src->GetFlatContent();
9041 DCHECK(content.IsFlat());
9042 if (content.IsOneByte()) {
9043 CalculateLineEndsImpl(isolate,
9044 &line_ends,
9045 content.ToOneByteVector(),
9046 include_ending_line);
9047 } else {
9048 CalculateLineEndsImpl(isolate,
9049 &line_ends,
9050 content.ToUC16Vector(),
9051 include_ending_line);
9052 }
9053 }
9054 int line_count = line_ends.length();
9055 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
9056 for (int i = 0; i < line_count; i++) {
9057 array->set(i, Smi::FromInt(line_ends[i]));
9058 }
9059 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00009060}
9061
9062
9063// Compares the contents of two strings by reading and comparing
9064// int-sized blocks of characters.
9065template <typename Char>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009066static inline bool CompareRawStringContents(const Char* const a,
9067 const Char* const b,
9068 int length) {
9069 return CompareChars(a, b, length) == 0;
9070}
9071
9072
9073template<typename Chars1, typename Chars2>
9074class RawStringComparator : public AllStatic {
9075 public:
9076 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
9077 DCHECK(sizeof(Chars1) != sizeof(Chars2));
9078 for (int i = 0; i < len; i++) {
9079 if (a[i] != b[i]) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009080 return false;
9081 }
9082 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009083 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00009084 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009085};
Steve Blocka7e24c12009-10-30 11:49:00 +00009086
9087
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009088template<>
9089class RawStringComparator<uint16_t, uint16_t> {
9090 public:
9091 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
9092 return CompareRawStringContents(a, b, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00009093 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009094};
9095
9096
9097template<>
9098class RawStringComparator<uint8_t, uint8_t> {
9099 public:
9100 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
9101 return CompareRawStringContents(a, b, len);
9102 }
9103};
9104
9105
9106class StringComparator {
9107 class State {
9108 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009109 State() : is_one_byte_(true), length_(0), buffer8_(NULL) {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009110
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009111 void Init(String* string) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009112 ConsString* cons_string = String::VisitFlat(this, string);
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009113 iter_.Reset(cons_string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009114 if (cons_string != NULL) {
9115 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009116 string = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009117 String::VisitFlat(this, string, offset);
9118 }
9119 }
9120
9121 inline void VisitOneByteString(const uint8_t* chars, int length) {
9122 is_one_byte_ = true;
9123 buffer8_ = chars;
9124 length_ = length;
9125 }
9126
9127 inline void VisitTwoByteString(const uint16_t* chars, int length) {
9128 is_one_byte_ = false;
9129 buffer16_ = chars;
9130 length_ = length;
9131 }
9132
9133 void Advance(int consumed) {
9134 DCHECK(consumed <= length_);
9135 // Still in buffer.
9136 if (length_ != consumed) {
9137 if (is_one_byte_) {
9138 buffer8_ += consumed;
9139 } else {
9140 buffer16_ += consumed;
9141 }
9142 length_ -= consumed;
9143 return;
9144 }
9145 // Advance state.
9146 int offset;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009147 String* next = iter_.Next(&offset);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009148 DCHECK_EQ(0, offset);
9149 DCHECK(next != NULL);
9150 String::VisitFlat(this, next);
9151 }
9152
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009153 ConsStringIterator iter_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009154 bool is_one_byte_;
9155 int length_;
9156 union {
9157 const uint8_t* buffer8_;
9158 const uint16_t* buffer16_;
9159 };
9160
9161 private:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009162 DISALLOW_COPY_AND_ASSIGN(State);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009163 };
9164
9165 public:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009166 inline StringComparator() {}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009167
9168 template<typename Chars1, typename Chars2>
9169 static inline bool Equals(State* state_1, State* state_2, int to_check) {
9170 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
9171 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
9172 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
9173 }
9174
9175 bool Equals(String* string_1, String* string_2) {
9176 int length = string_1->length();
9177 state_1_.Init(string_1);
9178 state_2_.Init(string_2);
9179 while (true) {
9180 int to_check = Min(state_1_.length_, state_2_.length_);
9181 DCHECK(to_check > 0 && to_check <= length);
9182 bool is_equal;
9183 if (state_1_.is_one_byte_) {
9184 if (state_2_.is_one_byte_) {
9185 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
9186 } else {
9187 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
9188 }
9189 } else {
9190 if (state_2_.is_one_byte_) {
9191 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
9192 } else {
9193 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
9194 }
9195 }
9196 // Looping done.
9197 if (!is_equal) return false;
9198 length -= to_check;
9199 // Exit condition. Strings are equal.
9200 if (length == 0) return true;
9201 state_1_.Advance(to_check);
9202 state_2_.Advance(to_check);
9203 }
9204 }
9205
9206 private:
9207 State state_1_;
9208 State state_2_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009209
9210 DISALLOW_COPY_AND_ASSIGN(StringComparator);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009211};
Steve Blocka7e24c12009-10-30 11:49:00 +00009212
9213
Steve Blocka7e24c12009-10-30 11:49:00 +00009214bool String::SlowEquals(String* other) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009215 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00009216 // Fast check: negative check with lengths.
9217 int len = length();
9218 if (len != other->length()) return false;
9219 if (len == 0) return true;
9220
9221 // Fast check: if hash code is computed for both strings
9222 // a fast negative check can be performed.
9223 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009224#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochc7cc0282012-03-05 14:35:55 +00009225 if (FLAG_enable_slow_asserts) {
9226 if (Hash() != other->Hash()) {
9227 bool found_difference = false;
9228 for (int i = 0; i < len; i++) {
9229 if (Get(i) != other->Get(i)) {
9230 found_difference = true;
9231 break;
9232 }
9233 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009234 DCHECK(found_difference);
Ben Murdochc7cc0282012-03-05 14:35:55 +00009235 }
9236 }
9237#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00009238 if (Hash() != other->Hash()) return false;
9239 }
9240
Leon Clarkef7060e22010-06-03 12:02:55 +01009241 // We know the strings are both non-empty. Compare the first chars
9242 // before we try to flatten the strings.
9243 if (this->Get(0) != other->Get(0)) return false;
9244
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009245 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
9246 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
9247 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
9248 return CompareRawStringContents(str1, str2, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00009249 }
9250
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009251 StringComparator comparator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009252 return comparator.Equals(this, other);
9253}
9254
9255
9256bool String::SlowEquals(Handle<String> one, Handle<String> two) {
9257 // Fast check: negative check with lengths.
9258 int one_length = one->length();
9259 if (one_length != two->length()) return false;
9260 if (one_length == 0) return true;
9261
9262 // Fast check: if hash code is computed for both strings
9263 // a fast negative check can be performed.
9264 if (one->HasHashCode() && two->HasHashCode()) {
9265#ifdef ENABLE_SLOW_DCHECKS
9266 if (FLAG_enable_slow_asserts) {
9267 if (one->Hash() != two->Hash()) {
9268 bool found_difference = false;
9269 for (int i = 0; i < one_length; i++) {
9270 if (one->Get(i) != two->Get(i)) {
9271 found_difference = true;
9272 break;
9273 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009274 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009275 DCHECK(found_difference);
Steve Blocka7e24c12009-10-30 11:49:00 +00009276 }
9277 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009278#endif
9279 if (one->Hash() != two->Hash()) return false;
9280 }
9281
9282 // We know the strings are both non-empty. Compare the first chars
9283 // before we try to flatten the strings.
9284 if (one->Get(0) != two->Get(0)) return false;
9285
9286 one = String::Flatten(one);
9287 two = String::Flatten(two);
9288
9289 DisallowHeapAllocation no_gc;
9290 String::FlatContent flat1 = one->GetFlatContent();
9291 String::FlatContent flat2 = two->GetFlatContent();
9292
9293 if (flat1.IsOneByte() && flat2.IsOneByte()) {
9294 return CompareRawStringContents(flat1.ToOneByteVector().start(),
9295 flat2.ToOneByteVector().start(),
9296 one_length);
Steve Blocka7e24c12009-10-30 11:49:00 +00009297 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009298 for (int i = 0; i < one_length; i++) {
9299 if (flat1.Get(i) != flat2.Get(i)) return false;
9300 }
9301 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00009302 }
9303}
9304
9305
9306bool String::MarkAsUndetectable() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009307 if (StringShape(this).IsInternalized()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009308
9309 Map* map = this->map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009310 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01009311 if (map == heap->string_map()) {
9312 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009313 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009314 } else if (map == heap->one_byte_string_map()) {
9315 this->set_map(heap->undetectable_one_byte_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00009316 return true;
9317 }
9318 // Rest cannot be marked as undetectable
9319 return false;
9320}
9321
9322
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009323bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009324 int slen = length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009325 // Can't check exact length equality, but we can check bounds.
9326 int str_len = str.length();
9327 if (!allow_prefix_match &&
9328 (str_len < slen ||
9329 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
9330 return false;
9331 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009332 int i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009333 unsigned remaining_in_str = static_cast<unsigned>(str_len);
9334 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
9335 for (i = 0; i < slen && remaining_in_str > 0; i++) {
9336 unsigned cursor = 0;
9337 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
9338 DCHECK(cursor > 0 && cursor <= remaining_in_str);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009339 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
9340 if (i > slen - 1) return false;
9341 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
9342 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
9343 } else {
9344 if (Get(i) != r) return false;
9345 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009346 utf8_data += cursor;
9347 remaining_in_str -= cursor;
Steve Blocka7e24c12009-10-30 11:49:00 +00009348 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009349 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00009350}
9351
9352
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009353bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
Steve Block9fac8402011-05-12 15:51:54 +01009354 int slen = length();
9355 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009356 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009357 FlatContent content = GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009358 if (content.IsOneByte()) {
9359 return CompareChars(content.ToOneByteVector().start(),
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009360 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009361 }
9362 for (int i = 0; i < slen; i++) {
9363 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01009364 }
9365 return true;
9366}
9367
9368
9369bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
9370 int slen = length();
9371 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009372 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009373 FlatContent content = GetFlatContent();
9374 if (content.IsTwoByte()) {
9375 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009376 }
Steve Block9fac8402011-05-12 15:51:54 +01009377 for (int i = 0; i < slen; i++) {
9378 if (Get(i) != str[i]) return false;
9379 }
9380 return true;
9381}
9382
9383
Steve Blocka7e24c12009-10-30 11:49:00 +00009384uint32_t String::ComputeAndSetHash() {
9385 // Should only be called if hash code has not yet been computed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009386 DCHECK(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00009387
9388 // Store the hash code in the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009389 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +00009390 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00009391
9392 // Check the hash code is there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009393 DCHECK(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00009394 uint32_t result = field >> kHashShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009395 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
Steve Blocka7e24c12009-10-30 11:49:00 +00009396 return result;
9397}
9398
9399
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009400bool String::ComputeArrayIndex(uint32_t* index) {
9401 int length = this->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00009402 if (length == 0 || length > kMaxArrayIndexSize) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009403 StringCharacterStream stream(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009404 return StringToArrayIndex(&stream, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009405}
9406
9407
9408bool String::SlowAsArrayIndex(uint32_t* index) {
9409 if (length() <= kMaxCachedArrayIndexLength) {
9410 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00009411 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009412 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00009413 // Isolate the array index form the full hash field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009414 *index = ArrayIndexValueBits::decode(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00009415 return true;
9416 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009417 return ComputeArrayIndex(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00009418 }
9419}
9420
9421
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009422Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
9423 int new_size, old_size;
9424 int old_length = string->length();
9425 if (old_length <= new_length) return string;
9426
9427 if (string->IsSeqOneByteString()) {
9428 old_size = SeqOneByteString::SizeFor(old_length);
9429 new_size = SeqOneByteString::SizeFor(new_length);
9430 } else {
9431 DCHECK(string->IsSeqTwoByteString());
9432 old_size = SeqTwoByteString::SizeFor(old_length);
9433 new_size = SeqTwoByteString::SizeFor(new_length);
9434 }
9435
9436 int delta = old_size - new_size;
9437
9438 Address start_of_string = string->address();
9439 DCHECK_OBJECT_ALIGNED(start_of_string);
9440 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
9441
9442 Heap* heap = string->GetHeap();
9443 NewSpace* newspace = heap->new_space();
9444 if (newspace->Contains(start_of_string) &&
9445 newspace->top() == start_of_string + old_size) {
9446 // Last allocated object in new space. Simply lower allocation top.
9447 newspace->set_top(start_of_string + new_size);
9448 } else {
9449 // Sizes are pointer size aligned, so that we can use filler objects
9450 // that are a multiple of pointer size.
9451 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
9452 }
9453 heap->AdjustLiveBytes(start_of_string, -delta, Heap::FROM_MUTATOR);
9454
9455 // We are storing the new length using release store after creating a filler
9456 // for the left-over space to avoid races with the sweeper thread.
9457 string->synchronized_set_length(new_length);
9458
9459 if (new_length == 0) return heap->isolate()->factory()->empty_string();
9460 return string;
9461}
9462
9463
Iain Merrick9ac36c92010-09-13 15:29:50 +01009464uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009465 // For array indexes mix the length into the hash as an array index could
9466 // be zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009467 DCHECK(length > 0);
9468 DCHECK(length <= String::kMaxArrayIndexSize);
9469 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009470 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01009471
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009472 value <<= String::ArrayIndexValueBits::kShift;
9473 value |= length << String::ArrayIndexLengthBits::kShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01009474
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009475 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
9476 DCHECK((length > String::kMaxCachedArrayIndexLength) ||
Iain Merrick9ac36c92010-09-13 15:29:50 +01009477 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009478 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00009479}
9480
9481
9482uint32_t StringHasher::GetHashField() {
Steve Blockd0582a62009-12-15 09:54:21 +00009483 if (length_ <= String::kMaxHashCalcLength) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009484 if (is_array_index_) {
9485 return MakeArrayIndexHash(array_index_, length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009486 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009487 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
9488 String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00009489 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01009490 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00009491 }
9492}
9493
9494
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009495uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
9496 uint32_t seed,
9497 int* utf16_length_out) {
9498 int vector_length = chars.length();
9499 // Handle some edge cases
9500 if (vector_length <= 1) {
9501 DCHECK(vector_length == 0 ||
9502 static_cast<uint8_t>(chars.start()[0]) <=
9503 unibrow::Utf8::kMaxOneByteChar);
9504 *utf16_length_out = vector_length;
9505 return HashSequentialString(chars.start(), vector_length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +00009506 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009507 // Start with a fake length which won't affect computation.
9508 // It will be updated later.
9509 StringHasher hasher(String::kMaxArrayIndexSize, seed);
9510 unsigned remaining = static_cast<unsigned>(vector_length);
9511 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
9512 int utf16_length = 0;
9513 bool is_index = true;
9514 DCHECK(hasher.is_array_index_);
9515 while (remaining > 0) {
9516 unsigned consumed = 0;
9517 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
9518 DCHECK(consumed > 0 && consumed <= remaining);
9519 stream += consumed;
9520 remaining -= consumed;
9521 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
9522 utf16_length += is_two_characters ? 2 : 1;
9523 // No need to keep hashing. But we do need to calculate utf16_length.
9524 if (utf16_length > String::kMaxHashCalcLength) continue;
9525 if (is_two_characters) {
9526 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
9527 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
9528 hasher.AddCharacter(c1);
9529 hasher.AddCharacter(c2);
9530 if (is_index) is_index = hasher.UpdateIndex(c1);
9531 if (is_index) is_index = hasher.UpdateIndex(c2);
9532 } else {
9533 hasher.AddCharacter(c);
9534 if (is_index) is_index = hasher.UpdateIndex(c);
9535 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009536 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009537 *utf16_length_out = static_cast<int>(utf16_length);
9538 // Must set length here so that hash computation is correct.
9539 hasher.length_ = utf16_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00009540 return hasher.GetHashField();
9541}
9542
9543
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009544void IteratingStringHasher::VisitConsString(ConsString* cons_string) {
9545 // Run small ConsStrings through ConsStringIterator.
9546 if (cons_string->length() < 64) {
9547 ConsStringIterator iter(cons_string);
9548 int offset;
9549 String* string;
9550 while (nullptr != (string = iter.Next(&offset))) {
9551 DCHECK_EQ(0, offset);
9552 String::VisitFlat(this, string, 0);
9553 }
9554 return;
9555 }
9556 // Slow case.
9557 const int max_length = String::kMaxHashCalcLength;
9558 int length = std::min(cons_string->length(), max_length);
9559 if (cons_string->HasOnlyOneByteChars()) {
9560 uint8_t* buffer = new uint8_t[length];
9561 String::WriteToFlat(cons_string, buffer, 0, length);
9562 AddCharacters(buffer, length);
9563 delete[] buffer;
9564 } else {
9565 uint16_t* buffer = new uint16_t[length];
9566 String::WriteToFlat(cons_string, buffer, 0, length);
9567 AddCharacters(buffer, length);
9568 delete[] buffer;
9569 }
9570}
9571
9572
Steve Blocka7e24c12009-10-30 11:49:00 +00009573void String::PrintOn(FILE* file) {
9574 int length = this->length();
9575 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009576 PrintF(file, "%c", Get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009577 }
9578}
9579
9580
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009581inline static uint32_t ObjectAddressForHashing(Object* object) {
9582 uint32_t value = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(object));
9583 return value & MemoryChunk::kAlignmentMask;
9584}
9585
9586
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009587int Map::Hash() {
9588 // For performance reasons we only hash the 3 most variable fields of a map:
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009589 // constructor, prototype and bit_field2. For predictability reasons we
9590 // use objects' offsets in respective pages for hashing instead of raw
9591 // addresses.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009592
9593 // Shift away the tag.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009594 int hash = ObjectAddressForHashing(constructor()) >> 2;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009595
9596 // XOR-ing the prototype and constructor directly yields too many zero bits
9597 // when the two pointers are close (which is fairly common).
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009598 // To avoid this we shift the prototype bits relatively to the constructor.
9599 hash ^= ObjectAddressForHashing(prototype()) << (32 - kPageSizeBits);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009600
9601 return hash ^ (hash >> 16) ^ bit_field2();
9602}
9603
9604
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009605static bool CheckEquivalent(Map* first, Map* second) {
9606 return
9607 first->constructor() == second->constructor() &&
9608 first->prototype() == second->prototype() &&
9609 first->instance_type() == second->instance_type() &&
9610 first->bit_field() == second->bit_field() &&
9611 first->bit_field2() == second->bit_field2() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009612 first->has_instance_call_handler() == second->has_instance_call_handler();
9613}
9614
9615
9616bool Map::EquivalentToForTransition(Map* other) {
9617 return CheckEquivalent(this, other);
9618}
9619
9620
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009621bool Map::EquivalentToForNormalization(Map* other,
9622 PropertyNormalizationMode mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009623 int properties = mode == CLEAR_INOBJECT_PROPERTIES
9624 ? 0 : other->inobject_properties();
9625 return CheckEquivalent(this, other) && inobject_properties() == properties;
9626}
9627
9628
9629void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
9630 // Unfortunately the serializer relies on pointers within an object being
9631 // visited in-order, so we have to iterate both the code and heap pointers in
9632 // the small section before doing so in the extended section.
9633 for (int s = 0; s <= final_section(); ++s) {
9634 LayoutSection section = static_cast<LayoutSection>(s);
9635 ConstantPoolArray::Iterator code_iter(this, ConstantPoolArray::CODE_PTR,
9636 section);
9637 while (!code_iter.is_finished()) {
9638 v->VisitCodeEntry(reinterpret_cast<Address>(
9639 RawFieldOfElementAt(code_iter.next_index())));
9640 }
9641
9642 ConstantPoolArray::Iterator heap_iter(this, ConstantPoolArray::HEAP_PTR,
9643 section);
9644 while (!heap_iter.is_finished()) {
9645 v->VisitPointer(RawFieldOfElementAt(heap_iter.next_index()));
9646 }
9647 }
9648}
9649
9650
9651void ConstantPoolArray::ClearPtrEntries(Isolate* isolate) {
9652 Type type[] = { CODE_PTR, HEAP_PTR };
9653 Address default_value[] = {
9654 isolate->builtins()->builtin(Builtins::kIllegal)->entry(),
9655 reinterpret_cast<Address>(isolate->heap()->undefined_value()) };
9656
9657 for (int i = 0; i < 2; ++i) {
9658 for (int s = 0; s <= final_section(); ++s) {
9659 LayoutSection section = static_cast<LayoutSection>(s);
9660 if (number_of_entries(type[i], section) > 0) {
9661 int offset = OffsetOfElementAt(first_index(type[i], section));
9662 MemsetPointer(
9663 reinterpret_cast<Address*>(HeapObject::RawField(this, offset)),
9664 default_value[i],
9665 number_of_entries(type[i], section));
9666 }
9667 }
9668 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009669}
9670
9671
Steve Block791712a2010-08-27 10:21:07 +01009672void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
9673 // Iterate over all fields in the body but take care in dealing with
9674 // the code entry.
9675 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
9676 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
9677 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
9678}
9679
9680
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009681void JSFunction::MarkForOptimization() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009682 Isolate* isolate = GetIsolate();
9683 DCHECK(isolate->use_crankshaft());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009684 DCHECK(!IsOptimized());
9685 DCHECK(shared()->allows_lazy_compilation() ||
Ben Murdochb8e0da22011-05-16 14:20:40 +01009686 code()->optimizable());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009687 DCHECK(!shared()->is_generator());
9688 set_code_no_write_barrier(
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009689 isolate->builtins()->builtin(Builtins::kCompileOptimized));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009690 // No write barrier required, since the builtin is part of the root set.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009691}
9692
9693
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009694void JSFunction::AttemptConcurrentOptimization() {
9695 Isolate* isolate = GetIsolate();
9696 if (!isolate->concurrent_recompilation_enabled() ||
9697 isolate->bootstrapper()->IsActive()) {
9698 MarkForOptimization();
9699 return;
9700 }
9701 if (isolate->concurrent_osr_enabled() &&
9702 isolate->optimizing_compiler_thread()->IsQueuedForOSR(this)) {
9703 // Do not attempt regular recompilation if we already queued this for OSR.
9704 // TODO(yangguo): This is necessary so that we don't install optimized
9705 // code on a function that is already optimized, since OSR and regular
9706 // recompilation race. This goes away as soon as OSR becomes one-shot.
9707 return;
9708 }
9709 DCHECK(isolate->use_crankshaft());
9710 DCHECK(!IsInOptimizationQueue());
9711 DCHECK(is_compiled() || isolate->DebuggerHasBreakPoints());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009712 DCHECK(!IsOptimized());
9713 DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
9714 DCHECK(!shared()->is_generator());
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009715 DCHECK(isolate->concurrent_recompilation_enabled());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009716 if (FLAG_trace_concurrent_recompilation) {
9717 PrintF(" ** Marking ");
9718 ShortPrint();
9719 PrintF(" for concurrent recompilation.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009720 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009721 set_code_no_write_barrier(
9722 GetIsolate()->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
9723 // No write barrier required, since the builtin is part of the root set.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009724}
9725
9726
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009727Handle<JSFunction> JSFunction::CloneClosure(Handle<JSFunction> function) {
9728 Isolate* isolate = function->GetIsolate();
9729 Handle<Map> map(function->map());
9730 Handle<SharedFunctionInfo> shared(function->shared());
9731 Handle<Context> context(function->context());
9732 Handle<JSFunction> clone =
9733 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
9734
9735 if (shared->bound()) {
9736 clone->set_function_bindings(function->function_bindings());
9737 }
9738
9739 // In typical case, __proto__ of ``function`` is the default Function
9740 // prototype, which means that SetPrototype below is a no-op.
9741 // In rare cases when that is not true, we mutate the clone's __proto__.
9742 Handle<Object> original_prototype(map->prototype(), isolate);
9743 if (*original_prototype != clone->map()->prototype()) {
9744 JSObject::SetPrototype(clone, original_prototype, false).Assert();
9745 }
9746
9747 return clone;
9748}
9749
9750
9751void SharedFunctionInfo::AddToOptimizedCodeMap(
9752 Handle<SharedFunctionInfo> shared,
9753 Handle<Context> native_context,
9754 Handle<Code> code,
9755 Handle<FixedArray> literals,
9756 BailoutId osr_ast_id) {
9757 Isolate* isolate = shared->GetIsolate();
9758 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
9759 DCHECK(native_context->IsNativeContext());
9760 STATIC_ASSERT(kEntryLength == 4);
9761 Handle<FixedArray> new_code_map;
9762 Handle<Object> value(shared->optimized_code_map(), isolate);
9763 int old_length;
9764 if (value->IsSmi()) {
9765 // No optimized code map.
9766 DCHECK_EQ(0, Smi::cast(*value)->value());
9767 // Create 3 entries per context {context, code, literals}.
9768 new_code_map = isolate->factory()->NewFixedArray(kInitialLength);
9769 old_length = kEntriesStart;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009770 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009771 // Copy old map and append one new entry.
9772 Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
9773 DCHECK_EQ(-1, shared->SearchOptimizedCodeMap(*native_context, osr_ast_id));
9774 old_length = old_code_map->length();
9775 new_code_map = FixedArray::CopySize(
9776 old_code_map, old_length + kEntryLength);
9777 // Zap the old map for the sake of the heap verifier.
9778 if (Heap::ShouldZapGarbage()) {
9779 Object** data = old_code_map->data_start();
9780 MemsetPointer(data, isolate->heap()->the_hole_value(), old_length);
9781 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009782 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009783 new_code_map->set(old_length + kContextOffset, *native_context);
9784 new_code_map->set(old_length + kCachedCodeOffset, *code);
9785 new_code_map->set(old_length + kLiteralsOffset, *literals);
9786 new_code_map->set(old_length + kOsrAstIdOffset,
9787 Smi::FromInt(osr_ast_id.ToInt()));
9788
9789#ifdef DEBUG
9790 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
9791 DCHECK(new_code_map->get(i + kContextOffset)->IsNativeContext());
9792 DCHECK(new_code_map->get(i + kCachedCodeOffset)->IsCode());
9793 DCHECK(Code::cast(new_code_map->get(i + kCachedCodeOffset))->kind() ==
9794 Code::OPTIMIZED_FUNCTION);
9795 DCHECK(new_code_map->get(i + kLiteralsOffset)->IsFixedArray());
9796 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
9797 }
9798#endif
9799 shared->set_optimized_code_map(*new_code_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009800}
9801
9802
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009803FixedArray* SharedFunctionInfo::GetLiteralsFromOptimizedCodeMap(int index) {
9804 DCHECK(index > kEntriesStart);
9805 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9806 if (!bound()) {
9807 FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
9808 DCHECK_NE(NULL, cached_literals);
9809 return cached_literals;
9810 }
9811 return NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009812}
9813
9814
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009815Code* SharedFunctionInfo::GetCodeFromOptimizedCodeMap(int index) {
9816 DCHECK(index > kEntriesStart);
9817 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9818 Code* code = Code::cast(code_map->get(index));
9819 DCHECK_NE(NULL, code);
9820 return code;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009821}
9822
9823
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009824void SharedFunctionInfo::ClearOptimizedCodeMap() {
9825 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9826
9827 // If the next map link slot is already used then the function was
9828 // enqueued with code flushing and we remove it now.
9829 if (!code_map->get(kNextMapIndex)->IsUndefined()) {
9830 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
9831 flusher->EvictOptimizedCodeMap(this);
9832 }
9833
9834 DCHECK(code_map->get(kNextMapIndex)->IsUndefined());
9835 set_optimized_code_map(Smi::FromInt(0));
9836}
9837
9838
9839void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
9840 const char* reason) {
9841 DisallowHeapAllocation no_gc;
9842 if (optimized_code_map()->IsSmi()) return;
9843
9844 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9845 int dst = kEntriesStart;
9846 int length = code_map->length();
9847 for (int src = kEntriesStart; src < length; src += kEntryLength) {
9848 DCHECK(code_map->get(src)->IsNativeContext());
9849 if (Code::cast(code_map->get(src + kCachedCodeOffset)) == optimized_code) {
9850 // Evict the src entry by not copying it to the dst entry.
9851 if (FLAG_trace_opt) {
9852 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
9853 ShortPrint();
9854 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
9855 if (osr.IsNone()) {
9856 PrintF("]\n");
9857 } else {
9858 PrintF(" (osr ast id %d)]\n", osr.ToInt());
9859 }
9860 }
9861 } else {
9862 // Keep the src entry by copying it to the dst entry.
9863 if (dst != src) {
9864 code_map->set(dst + kContextOffset,
9865 code_map->get(src + kContextOffset));
9866 code_map->set(dst + kCachedCodeOffset,
9867 code_map->get(src + kCachedCodeOffset));
9868 code_map->set(dst + kLiteralsOffset,
9869 code_map->get(src + kLiteralsOffset));
9870 code_map->set(dst + kOsrAstIdOffset,
9871 code_map->get(src + kOsrAstIdOffset));
9872 }
9873 dst += kEntryLength;
9874 }
9875 }
9876 if (dst != length) {
9877 // Always trim even when array is cleared because of heap verifier.
9878 GetHeap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(code_map, length - dst);
9879 if (code_map->length() == kEntriesStart) ClearOptimizedCodeMap();
9880 }
9881}
9882
9883
9884void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
9885 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9886 DCHECK(shrink_by % kEntryLength == 0);
9887 DCHECK(shrink_by <= code_map->length() - kEntriesStart);
9888 // Always trim even when array is cleared because of heap verifier.
9889 GetHeap()->RightTrimFixedArray<Heap::FROM_GC>(code_map, shrink_by);
9890 if (code_map->length() == kEntriesStart) {
9891 ClearOptimizedCodeMap();
9892 }
9893}
9894
9895
9896void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
9897 PrototypeOptimizationMode mode) {
9898 if (object->IsGlobalObject()) return;
9899 if (object->IsJSGlobalProxy()) return;
9900 if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
9901 // First normalize to ensure all JSFunctions are CONSTANT.
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009902 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0,
9903 "NormalizeAsPrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009904 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009905 bool has_just_copied_map = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009906 if (!object->HasFastProperties()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009907 JSObject::MigrateSlowToFast(object, 0, "OptimizeAsPrototype");
9908 has_just_copied_map = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009909 }
9910 if (mode == FAST_PROTOTYPE && object->HasFastProperties() &&
9911 !object->map()->is_prototype_map()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009912 if (!has_just_copied_map) {
9913 Handle<Map> new_map = Map::Copy(handle(object->map()), "CopyAsPrototype");
9914 JSObject::MigrateToMap(object, new_map);
9915 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009916 object->map()->set_is_prototype_map(true);
9917 }
9918}
9919
9920
9921void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
9922 if (!object->map()->is_prototype_map()) return;
9923 OptimizeAsPrototype(object, FAST_PROTOTYPE);
9924}
9925
9926
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009927void JSObject::RegisterPrototypeUser(Handle<JSObject> prototype,
9928 Handle<HeapObject> user) {
9929 DCHECK(FLAG_track_prototype_users);
9930 Isolate* isolate = prototype->GetIsolate();
9931 Handle<Name> symbol = isolate->factory()->prototype_users_symbol();
9932
9933 // Get prototype users array, create it if it doesn't exist yet.
9934 Handle<Object> maybe_array =
9935 JSObject::GetProperty(prototype, symbol).ToHandleChecked();
9936
9937 Handle<WeakFixedArray> new_array = WeakFixedArray::Add(maybe_array, user);
9938 if (!maybe_array.is_identical_to(new_array)) {
9939 JSObject::SetOwnPropertyIgnoreAttributes(prototype, symbol, new_array,
9940 DONT_ENUM).Assert();
9941 }
9942}
9943
9944
9945void JSObject::UnregisterPrototypeUser(Handle<JSObject> prototype,
9946 Handle<HeapObject> user) {
9947 Isolate* isolate = prototype->GetIsolate();
9948 Handle<Name> symbol = isolate->factory()->prototype_users_symbol();
9949
9950 Handle<Object> maybe_array =
9951 JSObject::GetProperty(prototype, symbol).ToHandleChecked();
9952 if (!maybe_array->IsWeakFixedArray()) return;
9953 Handle<WeakFixedArray>::cast(maybe_array)->Remove(user);
9954}
9955
9956
9957void Map::SetPrototype(Handle<Object> prototype,
9958 PrototypeOptimizationMode proto_mode) {
9959 if (this->prototype()->IsJSObject() && FLAG_track_prototype_users) {
9960 Handle<JSObject> old_prototype(JSObject::cast(this->prototype()));
9961 JSObject::UnregisterPrototypeUser(old_prototype, handle(this));
9962 }
9963 if (prototype->IsJSObject()) {
9964 Handle<JSObject> prototype_jsobj = Handle<JSObject>::cast(prototype);
9965 if (ShouldRegisterAsPrototypeUser(prototype_jsobj)) {
9966 JSObject::RegisterPrototypeUser(prototype_jsobj, handle(this));
9967 }
9968 JSObject::OptimizeAsPrototype(prototype_jsobj, proto_mode);
9969 }
9970 WriteBarrierMode wb_mode =
9971 prototype->IsNull() ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
9972 set_prototype(*prototype, wb_mode);
9973}
9974
9975
9976bool Map::ShouldRegisterAsPrototypeUser(Handle<JSObject> prototype) {
9977 if (!FLAG_track_prototype_users) return false;
9978 if (this->is_prototype_map()) return true;
9979 if (this->is_dictionary_map()) return false;
9980 Object* back = GetBackPointer();
9981 if (!back->IsMap()) return true;
9982 if (Map::cast(back)->prototype() != *prototype) return true;
9983 return false;
9984}
9985
9986
9987bool Map::CanUseOptimizationsBasedOnPrototypeRegistry() {
9988 if (!FLAG_track_prototype_users) return false;
9989 if (this->is_prototype_map()) return true;
9990 if (GetBackPointer()->IsMap()) return true;
9991 return false;
9992}
9993
9994
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009995Handle<Object> CacheInitialJSArrayMaps(
9996 Handle<Context> native_context, Handle<Map> initial_map) {
9997 // Replace all of the cached initial array maps in the native context with
9998 // the appropriate transitioned elements kind maps.
9999 Factory* factory = native_context->GetIsolate()->factory();
10000 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles(
10001 kElementsKindCount, TENURED);
10002
10003 Handle<Map> current_map = initial_map;
10004 ElementsKind kind = current_map->elements_kind();
10005 DCHECK(kind == GetInitialFastElementsKind());
10006 maps->set(kind, *current_map);
10007 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
10008 i < kFastElementsKindCount; ++i) {
10009 Handle<Map> new_map;
10010 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
10011 if (current_map->HasElementsTransition()) {
10012 new_map = handle(current_map->elements_transition_map());
10013 DCHECK(new_map->elements_kind() == next_kind);
10014 } else {
10015 new_map = Map::CopyAsElementsKind(
10016 current_map, next_kind, INSERT_TRANSITION);
10017 }
10018 maps->set(next_kind, *new_map);
10019 current_map = new_map;
10020 }
10021 native_context->set_js_array_maps(*maps);
10022 return initial_map;
10023}
10024
10025
10026void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
10027 Handle<Object> value) {
10028 Isolate* isolate = function->GetIsolate();
10029
10030 DCHECK(value->IsJSReceiver());
10031
10032 // Now some logic for the maps of the objects that are created by using this
10033 // function as a constructor.
10034 if (function->has_initial_map()) {
10035 // If the function has allocated the initial map replace it with a
10036 // copy containing the new prototype. Also complete any in-object
10037 // slack tracking that is in progress at this point because it is
10038 // still tracking the old copy.
10039 if (function->IsInobjectSlackTrackingInProgress()) {
10040 function->CompleteInobjectSlackTracking();
10041 }
10042
10043 Handle<Map> initial_map(function->initial_map(), isolate);
10044
10045 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
10046 initial_map->instance_type() == JS_OBJECT_TYPE) {
10047 // Put the value in the initial map field until an initial map is needed.
10048 // At that point, a new initial map is created and the prototype is put
10049 // into the initial map where it belongs.
10050 function->set_prototype_or_initial_map(*value);
10051 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010052 Handle<Map> new_map = Map::Copy(initial_map, "SetInstancePrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010053 JSFunction::SetInitialMap(function, new_map, value);
10054
10055 // If the function is used as the global Array function, cache the
10056 // initial map (and transitioned versions) in the native context.
10057 Context* native_context = function->context()->native_context();
10058 Object* array_function =
10059 native_context->get(Context::ARRAY_FUNCTION_INDEX);
10060 if (array_function->IsJSFunction() &&
10061 *function == JSFunction::cast(array_function)) {
10062 CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
10063 }
10064 }
10065
10066 // Deoptimize all code that embeds the previous initial map.
10067 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
10068 isolate, DependentCode::kInitialMapChangedGroup);
Steve Blocka7e24c12009-10-30 11:49:00 +000010069 } else {
10070 // Put the value in the initial map field until an initial map is
10071 // needed. At that point, a new initial map is created and the
10072 // prototype is put into the initial map where it belongs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010073 function->set_prototype_or_initial_map(*value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010074 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010075 isolate->heap()->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +000010076}
10077
10078
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010079void JSFunction::SetPrototype(Handle<JSFunction> function,
10080 Handle<Object> value) {
10081 DCHECK(function->should_have_prototype());
10082 Handle<Object> construct_prototype = value;
Steve Blocka7e24c12009-10-30 11:49:00 +000010083
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010084 // If the value is not a JSReceiver, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +000010085 // constructor field so it can be accessed. Also, set the prototype
10086 // used for constructing objects to the original object prototype.
10087 // See ECMA-262 13.2.2.
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010088 if (!value->IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010089 // Copy the map so this does not affect unrelated functions.
10090 // Remove map transitions because they point to maps with a
10091 // different prototype.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010092 Handle<Map> new_map = Map::Copy(handle(function->map()), "SetPrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010093
10094 JSObject::MigrateToMap(function, new_map);
10095 new_map->set_constructor(*value);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010096 new_map->set_non_instance_prototype(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010097 Isolate* isolate = new_map->GetIsolate();
10098 construct_prototype = handle(
10099 isolate->context()->native_context()->initial_object_prototype(),
10100 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000010101 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010102 function->map()->set_non_instance_prototype(false);
Steve Blocka7e24c12009-10-30 11:49:00 +000010103 }
10104
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010105 return SetInstancePrototype(function, construct_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +000010106}
10107
10108
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010109bool JSFunction::RemovePrototype() {
10110 Context* native_context = context()->native_context();
10111 Map* no_prototype_map = shared()->strict_mode() == SLOPPY
10112 ? native_context->sloppy_function_without_prototype_map()
10113 : native_context->strict_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +010010114
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010115 if (map() == no_prototype_map) return true;
10116
10117#ifdef DEBUG
10118 if (map() != (shared()->strict_mode() == SLOPPY
10119 ? native_context->sloppy_function_map()
10120 : native_context->strict_function_map())) {
10121 return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010122 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010123#endif
Steve Block44f0eee2011-05-26 01:26:41 +010010124
10125 set_map(no_prototype_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010126 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010127 return true;
Steve Block6ded16b2010-05-10 14:33:55 +010010128}
10129
10130
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010131void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
10132 Handle<Object> prototype) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010133 if (map->prototype() != *prototype) {
10134 map->SetPrototype(prototype, FAST_PROTOTYPE);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010135 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010136 function->set_prototype_or_initial_map(*map);
10137 map->set_constructor(*function);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010138#if TRACE_MAPS
10139 if (FLAG_trace_maps) {
10140 PrintF("[TraceMaps: InitialMap map= %p SFI= %d_%s ]\n",
10141 reinterpret_cast<void*>(*map), function->shared()->unique_id(),
10142 function->shared()->DebugName()->ToCString().get());
10143 }
10144#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010145}
10146
10147
10148void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
10149 if (function->has_initial_map()) return;
10150 Isolate* isolate = function->GetIsolate();
10151
10152 // First create a new map with the size and number of in-object properties
10153 // suggested by the function.
10154 InstanceType instance_type;
10155 int instance_size;
10156 int in_object_properties;
10157 if (function->shared()->is_generator()) {
10158 instance_type = JS_GENERATOR_OBJECT_TYPE;
10159 instance_size = JSGeneratorObject::kSize;
10160 in_object_properties = 0;
10161 } else {
10162 instance_type = JS_OBJECT_TYPE;
10163 instance_size = function->shared()->CalculateInstanceSize();
10164 in_object_properties = function->shared()->CalculateInObjectProperties();
10165 }
10166 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
10167
10168 // Fetch or allocate prototype.
10169 Handle<Object> prototype;
10170 if (function->has_instance_prototype()) {
10171 prototype = handle(function->instance_prototype(), isolate);
10172 } else {
10173 prototype = isolate->factory()->NewFunctionPrototype(function);
10174 }
10175 map->set_inobject_properties(in_object_properties);
10176 map->set_unused_property_fields(in_object_properties);
10177 DCHECK(map->has_fast_object_elements());
10178
10179 // Finally link initial map and constructor function.
10180 JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype));
10181
10182 if (!function->shared()->is_generator()) {
10183 function->StartInobjectSlackTracking();
10184 }
10185}
10186
10187
10188void JSFunction::SetInstanceClassName(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010189 shared()->set_instance_class_name(name);
Steve Blocka7e24c12009-10-30 11:49:00 +000010190}
10191
10192
Ben Murdochb0fe1622011-05-05 13:52:32 +010010193void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +000010194 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010195 PrintF(out, "%s", name.get());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010196}
10197
10198
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010199Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
10200 return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +000010201}
10202
10203
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010204// The filter is a pattern that matches function names in this way:
10205// "*" all; the default
10206// "-" all but the top-level function
10207// "-name" all but the function "name"
10208// "" only the top-level function
10209// "name" only the function "name"
10210// "name*" only functions starting with "name"
10211// "~" none; the tilde is not an identifier
10212bool JSFunction::PassesFilter(const char* raw_filter) {
10213 if (*raw_filter == '*') return true;
10214 String* name = shared()->DebugName();
10215 Vector<const char> filter = CStrVector(raw_filter);
10216 if (filter.length() == 0) return name->length() == 0;
10217 if (filter[0] == '-') {
10218 // Negative filter.
10219 if (filter.length() == 1) {
10220 return (name->length() != 0);
10221 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
10222 return false;
10223 }
10224 if (filter[filter.length() - 1] == '*' &&
10225 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
10226 return false;
10227 }
10228 return true;
10229
10230 } else if (name->IsUtf8EqualTo(filter)) {
10231 return true;
John Reck59135872010-11-02 12:39:01 -070010232 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010233 if (filter[filter.length() - 1] == '*' &&
10234 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
10235 return true;
10236 }
10237 return false;
10238}
10239
10240
10241void Oddball::Initialize(Isolate* isolate,
10242 Handle<Oddball> oddball,
10243 const char* to_string,
10244 Handle<Object> to_number,
10245 byte kind) {
10246 Handle<String> internalized_to_string =
10247 isolate->factory()->InternalizeUtf8String(to_string);
10248 oddball->set_to_string(*internalized_to_string);
10249 oddball->set_to_number(*to_number);
10250 oddball->set_kind(kind);
10251}
10252
10253
10254void Script::InitLineEnds(Handle<Script> script) {
10255 if (!script->line_ends()->IsUndefined()) return;
10256
10257 Isolate* isolate = script->GetIsolate();
10258
10259 if (!script->source()->IsString()) {
10260 DCHECK(script->source()->IsUndefined());
10261 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
10262 script->set_line_ends(*empty);
10263 DCHECK(script->line_ends()->IsFixedArray());
10264 return;
10265 }
10266
10267 Handle<String> src(String::cast(script->source()), isolate);
10268
10269 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
10270
10271 if (*array != isolate->heap()->empty_fixed_array()) {
10272 array->set_map(isolate->heap()->fixed_cow_array_map());
10273 }
10274
10275 script->set_line_ends(*array);
10276 DCHECK(script->line_ends()->IsFixedArray());
10277}
10278
10279
10280int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
10281 int line_number = GetLineNumber(script, code_pos);
10282 if (line_number == -1) return -1;
10283
10284 DisallowHeapAllocation no_allocation;
10285 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
10286 line_number = line_number - script->line_offset()->value();
10287 if (line_number == 0) return code_pos + script->column_offset()->value();
10288 int prev_line_end_pos =
10289 Smi::cast(line_ends_array->get(line_number - 1))->value();
10290 return code_pos - (prev_line_end_pos + 1);
10291}
10292
10293
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010294int Script::GetLineNumberWithArray(int position) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010295 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010296 FixedArray* line_ends = FixedArray::cast(this->line_ends());
10297 int upper = line_ends->length() - 1;
10298 if (upper < 0) return -1;
10299 int offset = line_offset()->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010300
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010301 if (position > Smi::cast(line_ends->get(upper))->value()) {
10302 return upper + 1 + offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010303 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010304 if (position <= Smi::cast(line_ends->get(0))->value()) return offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010305
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010306 int lower = 1;
10307 // Binary search.
10308 while (true) {
10309 int mid = (lower + upper) / 2;
10310 if (position <= Smi::cast(line_ends->get(mid - 1))->value()) {
10311 upper = mid - 1;
10312 } else if (position > Smi::cast(line_ends->get(mid))->value()) {
10313 lower = mid + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010314 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010315 return mid + offset;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010316 }
10317 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010318 return -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010319}
10320
10321
10322int Script::GetLineNumber(Handle<Script> script, int code_pos) {
10323 InitLineEnds(script);
10324 return script->GetLineNumberWithArray(code_pos);
10325}
10326
10327
10328int Script::GetLineNumber(int code_pos) {
10329 DisallowHeapAllocation no_allocation;
10330 if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
10331
10332 // Slow mode: we do not have line_ends. We have to iterate through source.
10333 if (!source()->IsString()) return -1;
10334
10335 String* source_string = String::cast(source());
10336 int line = 0;
10337 int len = source_string->length();
10338 for (int pos = 0; pos < len; pos++) {
10339 if (pos == code_pos) break;
10340 if (source_string->Get(pos) == '\n') line++;
10341 }
10342 return line;
10343}
10344
10345
10346Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
10347 Isolate* isolate = script->GetIsolate();
10348 Handle<String> name_or_source_url_key =
10349 isolate->factory()->InternalizeOneByteString(
10350 STATIC_CHAR_VECTOR("nameOrSourceURL"));
10351 Handle<JSObject> script_wrapper = Script::GetWrapper(script);
10352 Handle<Object> property = Object::GetProperty(
10353 script_wrapper, name_or_source_url_key).ToHandleChecked();
10354 DCHECK(property->IsJSFunction());
10355 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
10356 Handle<Object> result;
10357 // Do not check against pending exception, since this function may be called
10358 // when an exception has already been pending.
10359 if (!Execution::TryCall(method, script_wrapper, 0, NULL).ToHandle(&result)) {
10360 return isolate->factory()->undefined_value();
10361 }
10362 return result;
10363}
10364
10365
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010366Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010367 Isolate* isolate = script->GetIsolate();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010368 if (!script->wrapper()->IsUndefined()) {
10369 Handle<WeakCell> cell(WeakCell::cast(script->wrapper()));
10370 if (!cell->cleared()) {
10371 // Return a handle for the existing script wrapper from the cache.
10372 return handle(JSObject::cast(cell->value()));
10373 }
10374 // If we found an empty WeakCell, that means the script wrapper was
10375 // GCed. We are not notified directly of that, so we decrement here
10376 // so that we at least don't count double for any given script.
10377 isolate->counters()->script_wrappers()->Decrement();
10378 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010379 // Construct a new script wrapper.
10380 isolate->counters()->script_wrappers()->Increment();
10381 Handle<JSFunction> constructor = isolate->script_function();
10382 Handle<JSValue> result =
10383 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010384 result->set_value(*script);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010385 Handle<WeakCell> cell = isolate->factory()->NewWeakCell(result);
10386 script->set_wrapper(*cell);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010387 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000010388}
10389
10390
Ben Murdochf87a2032010-10-22 12:50:53 +010010391String* SharedFunctionInfo::DebugName() {
10392 Object* n = name();
10393 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
10394 return String::cast(n);
10395}
10396
10397
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010398bool SharedFunctionInfo::HasSourceCode() const {
Steve Blocka7e24c12009-10-30 11:49:00 +000010399 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +010010400 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +000010401}
10402
10403
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010404Handle<Object> SharedFunctionInfo::GetSourceCode() {
10405 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
10406 Handle<String> source(String::cast(Script::cast(script())->source()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010407 return GetIsolate()->factory()->NewSubString(
10408 source, start_position(), end_position());
10409}
10410
10411
10412bool SharedFunctionInfo::IsInlineable() {
10413 // Check that the function has a script associated with it.
10414 if (!script()->IsScript()) return false;
10415 if (optimization_disabled()) return false;
10416 // If we never ran this (unlikely) then lets try to optimize it.
10417 if (code()->kind() != Code::FUNCTION) return true;
10418 return code()->optimizable();
Steve Blocka7e24c12009-10-30 11:49:00 +000010419}
10420
10421
Ben Murdochb0fe1622011-05-05 13:52:32 +010010422int SharedFunctionInfo::SourceSize() {
10423 return end_position() - start_position();
10424}
10425
10426
Steve Blocka7e24c12009-10-30 11:49:00 +000010427int SharedFunctionInfo::CalculateInstanceSize() {
10428 int instance_size =
10429 JSObject::kHeaderSize +
10430 expected_nof_properties() * kPointerSize;
10431 if (instance_size > JSObject::kMaxInstanceSize) {
10432 instance_size = JSObject::kMaxInstanceSize;
10433 }
10434 return instance_size;
10435}
10436
10437
10438int SharedFunctionInfo::CalculateInObjectProperties() {
10439 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
10440}
10441
10442
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010443// Output the source code without any allocation in the heap.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010444std::ostream& operator<<(std::ostream& os, const SourceCodeOf& v) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010445 const SharedFunctionInfo* s = v.value;
Steve Blocka7e24c12009-10-30 11:49:00 +000010446 // For some native functions there is no source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010447 if (!s->HasSourceCode()) return os << "<No Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000010448
Steve Blockd0582a62009-12-15 09:54:21 +000010449 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +000010450 // Don't use String::cast because we don't want more assertion errors while
10451 // we are already creating a stack dump.
10452 String* script_source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010453 reinterpret_cast<String*>(Script::cast(s->script())->source());
Steve Blocka7e24c12009-10-30 11:49:00 +000010454
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010455 if (!script_source->LooksValid()) return os << "<Invalid Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +000010456
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010457 if (!s->is_toplevel()) {
10458 os << "function ";
10459 Object* name = s->name();
Steve Blocka7e24c12009-10-30 11:49:00 +000010460 if (name->IsString() && String::cast(name)->length() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010461 String::cast(name)->PrintUC16(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000010462 }
10463 }
10464
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010465 int len = s->end_position() - s->start_position();
10466 if (len <= v.max_length || v.max_length < 0) {
10467 script_source->PrintUC16(os, s->start_position(), s->end_position());
10468 return os;
Ben Murdochb0fe1622011-05-05 13:52:32 +010010469 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010470 script_source->PrintUC16(os, s->start_position(),
10471 s->start_position() + v.max_length);
10472 return os << "...\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000010473 }
10474}
10475
10476
Ben Murdochb0fe1622011-05-05 13:52:32 +010010477static bool IsCodeEquivalent(Code* code, Code* recompiled) {
10478 if (code->instruction_size() != recompiled->instruction_size()) return false;
10479 ByteArray* code_relocation = code->relocation_info();
10480 ByteArray* recompiled_relocation = recompiled->relocation_info();
10481 int length = code_relocation->length();
10482 if (length != recompiled_relocation->length()) return false;
10483 int compare = memcmp(code_relocation->GetDataStartAddress(),
10484 recompiled_relocation->GetDataStartAddress(),
10485 length);
10486 return compare == 0;
10487}
10488
10489
10490void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010491 DCHECK(!has_deoptimization_support());
10492 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010010493 Code* code = this->code();
10494 if (IsCodeEquivalent(code, recompiled)) {
10495 // Copy the deoptimization data from the recompiled code.
10496 code->set_deoptimization_data(recompiled->deoptimization_data());
10497 code->set_has_deoptimization_support(true);
10498 } else {
10499 // TODO(3025757): In case the recompiled isn't equivalent to the
10500 // old code, we have to replace it. We should try to avoid this
10501 // altogether because it flushes valuable type feedback by
10502 // effectively resetting all IC state.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010503 ReplaceCode(recompiled);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010504 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010505 DCHECK(has_deoptimization_support());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010506}
10507
10508
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010509void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
Ben Murdoch257744e2011-11-30 15:57:28 +000010510 // Disable optimization for the shared function info and mark the
10511 // code as non-optimizable. The marker on the shared function info
10512 // is there because we flush non-optimized code thereby loosing the
10513 // non-optimizable information for the code. When the code is
10514 // regenerated and set on the shared function info it is marked as
10515 // non-optimizable if optimization is disabled for the shared
10516 // function info.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010517 DCHECK(reason != kNoReason);
Ben Murdoch257744e2011-11-30 15:57:28 +000010518 set_optimization_disabled(true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010519 set_disable_optimization_reason(reason);
Ben Murdoch257744e2011-11-30 15:57:28 +000010520 // Code should be the lazy compilation stub or else unoptimized. If the
10521 // latter, disable optimization for the code too.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010522 DCHECK(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
Ben Murdoch257744e2011-11-30 15:57:28 +000010523 if (code()->kind() == Code::FUNCTION) {
10524 code()->set_optimizable(false);
10525 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010526 PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
Ben Murdoch257744e2011-11-30 15:57:28 +000010527 if (FLAG_trace_opt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010528 PrintF("[disabled optimization for ");
10529 ShortPrint();
10530 PrintF(", reason: %s]\n", GetBailoutReason(reason));
Ben Murdoch257744e2011-11-30 15:57:28 +000010531 }
10532}
10533
10534
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010535bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
10536 DCHECK(!id.IsNone());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010537 Code* unoptimized = code();
10538 DeoptimizationOutputData* data =
10539 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
10540 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
10541 USE(ignore);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010542 return true; // Return true if there was no DCHECK.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010543}
10544
10545
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010546void JSFunction::StartInobjectSlackTracking() {
10547 DCHECK(has_initial_map() && !IsInobjectSlackTrackingInProgress());
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010548
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010549 Map* map = initial_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010550
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010551 // No tracking during the snapshot construction phase.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010552 Isolate* isolate = GetIsolate();
10553 if (isolate->serializer_enabled()) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010554
10555 if (map->unused_property_fields() == 0) return;
10556
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010557 map->set_counter(Map::kSlackTrackingCounterStart);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010558}
10559
10560
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010561void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
10562 code()->ClearInlineCaches();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010563 // If we clear ICs, we need to clear the type feedback vector too, since
10564 // CallICs are synced with a feedback vector slot.
10565 ClearTypeFeedbackInfo();
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010566 set_ic_age(new_ic_age);
10567 if (code()->kind() == Code::FUNCTION) {
10568 code()->set_profiler_ticks(0);
10569 if (optimization_disabled() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010570 opt_count() >= FLAG_max_opt_count) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010571 // Re-enable optimizations if they were disabled due to opt_count limit.
10572 set_optimization_disabled(false);
10573 code()->set_optimizable(true);
10574 }
10575 set_opt_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010576 set_deopt_count(0);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010577 }
10578}
10579
10580
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010581static void GetMinInobjectSlack(Map* map, void* data) {
10582 int slack = map->unused_property_fields();
10583 if (*reinterpret_cast<int*>(data) > slack) {
10584 *reinterpret_cast<int*>(data) = slack;
10585 }
10586}
10587
10588
10589static void ShrinkInstanceSize(Map* map, void* data) {
10590 int slack = *reinterpret_cast<int*>(data);
10591 map->set_inobject_properties(map->inobject_properties() - slack);
10592 map->set_unused_property_fields(map->unused_property_fields() - slack);
10593 map->set_instance_size(map->instance_size() - slack * kPointerSize);
10594
10595 // Visitor id might depend on the instance size, recalculate it.
10596 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
10597}
10598
10599
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010600void JSFunction::CompleteInobjectSlackTracking() {
10601 DCHECK(has_initial_map());
10602 Map* map = initial_map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010603
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010604 DCHECK(map->counter() >= Map::kSlackTrackingCounterEnd - 1);
10605 map->set_counter(Map::kRetainingCounterStart);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010606
10607 int slack = map->unused_property_fields();
10608 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
10609 if (slack != 0) {
10610 // Resize the initial map and all maps in its transition tree.
10611 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010612 }
10613}
10614
10615
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010616int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
10617 BailoutId osr_ast_id) {
10618 DisallowHeapAllocation no_gc;
10619 DCHECK(native_context->IsNativeContext());
10620 if (!FLAG_cache_optimized_code) return -1;
10621 Object* value = optimized_code_map();
10622 if (!value->IsSmi()) {
10623 FixedArray* optimized_code_map = FixedArray::cast(value);
10624 int length = optimized_code_map->length();
10625 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
10626 for (int i = kEntriesStart; i < length; i += kEntryLength) {
10627 if (optimized_code_map->get(i + kContextOffset) == native_context &&
10628 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
10629 return i + kCachedCodeOffset;
10630 }
10631 }
10632 if (FLAG_trace_opt) {
10633 PrintF("[didn't find optimized code in optimized code map for ");
10634 ShortPrint();
10635 PrintF("]\n");
10636 }
10637 }
10638 return -1;
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010639}
10640
10641
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010642#define DECLARE_TAG(ignore1, name, ignore2) name,
10643const char* const VisitorSynchronization::kTags[
10644 VisitorSynchronization::kNumberOfSyncTags] = {
10645 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10646};
10647#undef DECLARE_TAG
10648
10649
10650#define DECLARE_TAG(ignore1, ignore2, name) name,
10651const char* const VisitorSynchronization::kTagNames[
10652 VisitorSynchronization::kNumberOfSyncTags] = {
10653 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10654};
10655#undef DECLARE_TAG
10656
10657
Steve Blocka7e24c12009-10-30 11:49:00 +000010658void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010659 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010660 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
10661 Object* old_target = target;
10662 VisitPointer(&target);
10663 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
10664}
10665
10666
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010667void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
10668 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
10669 Object* stub = rinfo->code_age_stub();
10670 if (stub) {
10671 VisitPointer(&stub);
10672 }
10673}
10674
10675
Steve Block791712a2010-08-27 10:21:07 +010010676void ObjectVisitor::VisitCodeEntry(Address entry_address) {
10677 Object* code = Code::GetObjectFromEntryAddress(entry_address);
10678 Object* old_code = code;
10679 VisitPointer(&code);
10680 if (code != old_code) {
10681 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
10682 }
10683}
10684
10685
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010686void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
10687 DCHECK(rinfo->rmode() == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010688 Object* cell = rinfo->target_cell();
10689 Object* old_cell = cell;
10690 VisitPointer(&cell);
10691 if (cell != old_cell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010692 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010693 }
10694}
10695
10696
Steve Blocka7e24c12009-10-30 11:49:00 +000010697void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010698 DCHECK((RelocInfo::IsJSReturn(rinfo->rmode()) &&
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010699 rinfo->IsPatchedReturnSequence()) ||
10700 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
10701 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010702 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
10703 Object* old_target = target;
10704 VisitPointer(&target);
10705 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
10706}
10707
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010708
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010709void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010710 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
10711 Object* p = rinfo->target_object();
10712 VisitPointer(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010713}
10714
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010715
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010716void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010717 Address p = rinfo->target_reference();
10718 VisitExternalReference(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010719}
10720
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010721
Ben Murdochb0fe1622011-05-05 13:52:32 +010010722void Code::InvalidateRelocation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010723 InvalidateEmbeddedObjects();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010724 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010725}
10726
10727
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010728void Code::InvalidateEmbeddedObjects() {
10729 Object* undefined = GetHeap()->undefined_value();
10730 Cell* undefined_cell = GetHeap()->undefined_cell();
10731 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
10732 RelocInfo::ModeMask(RelocInfo::CELL);
10733 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10734 RelocInfo::Mode mode = it.rinfo()->rmode();
10735 if (mode == RelocInfo::EMBEDDED_OBJECT) {
10736 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
10737 } else if (mode == RelocInfo::CELL) {
10738 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
10739 }
10740 }
10741}
10742
10743
Steve Blockd0582a62009-12-15 09:54:21 +000010744void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010745 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010746 it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010747 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010748 CpuFeatures::FlushICache(instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000010749}
10750
10751
10752void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010753 DCHECK(Marking::Color(this) == Marking::WHITE_OBJECT);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010754
Steve Blocka7e24c12009-10-30 11:49:00 +000010755 // copy code
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010756 CopyBytes(instruction_start(), desc.buffer,
10757 static_cast<size_t>(desc.instr_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000010758
Steve Blocka7e24c12009-10-30 11:49:00 +000010759 // copy reloc info
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010760 CopyBytes(relocation_start(),
10761 desc.buffer + desc.buffer_size - desc.reloc_size,
10762 static_cast<size_t>(desc.reloc_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000010763
10764 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +000010765 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +000010766 int mode_mask = RelocInfo::kCodeTargetMask |
10767 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010768 RelocInfo::ModeMask(RelocInfo::CELL) |
10769 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
Steve Blocka7e24c12009-10-30 11:49:00 +000010770 RelocInfo::kApplyMask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010771 // Needed to find target_object and runtime_entry on X64
10772 Assembler* origin = desc.origin;
10773 AllowDeferredHandleDereference embedding_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +000010774 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10775 RelocInfo::Mode mode = it.rinfo()->rmode();
10776 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +000010777 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010778 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
10779 } else if (mode == RelocInfo::CELL) {
10780 Handle<Cell> cell = it.rinfo()->target_cell_handle();
10781 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010782 } else if (RelocInfo::IsCodeTarget(mode)) {
10783 // rewrite code handles in inline cache targets to direct
10784 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +000010785 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +000010786 Code* code = Code::cast(*p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010787 it.rinfo()->set_target_address(code->instruction_start(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010788 SKIP_WRITE_BARRIER,
10789 SKIP_ICACHE_FLUSH);
10790 } else if (RelocInfo::IsRuntimeEntry(mode)) {
10791 Address p = it.rinfo()->target_runtime_entry(origin);
10792 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
10793 SKIP_ICACHE_FLUSH);
10794 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
10795 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
10796 Code* code = Code::cast(*p);
10797 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010798 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010799 it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010800 }
10801 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010802 CpuFeatures::FlushICache(instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000010803}
10804
10805
10806// Locate the source position which is closest to the address in the code. This
10807// is using the source position information embedded in the relocation info.
10808// The position returned is relative to the beginning of the script where the
10809// source for this function is found.
10810int Code::SourcePosition(Address pc) {
10811 int distance = kMaxInt;
10812 int position = RelocInfo::kNoPosition; // Initially no position found.
10813 // Run through all the relocation info to find the best matching source
10814 // position. All the code needs to be considered as the sequence of the
10815 // instructions in the code does not necessarily follow the same order as the
10816 // source.
10817 RelocIterator it(this, RelocInfo::kPositionMask);
10818 while (!it.done()) {
10819 // Only look at positions after the current pc.
10820 if (it.rinfo()->pc() < pc) {
10821 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +000010822
10823 int dist = static_cast<int>(pc - it.rinfo()->pc());
10824 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000010825 // If this position is closer than the current candidate or if it has the
10826 // same distance as the current candidate and the position is higher then
10827 // this position is the new candidate.
10828 if ((dist < distance) ||
10829 (dist == distance && pos > position)) {
10830 position = pos;
10831 distance = dist;
10832 }
10833 }
10834 it.next();
10835 }
10836 return position;
10837}
10838
10839
10840// Same as Code::SourcePosition above except it only looks for statement
10841// positions.
10842int Code::SourceStatementPosition(Address pc) {
10843 // First find the position as close as possible using all position
10844 // information.
10845 int position = SourcePosition(pc);
10846 // Now find the closest statement position before the position.
10847 int statement_position = 0;
10848 RelocIterator it(this, RelocInfo::kPositionMask);
10849 while (!it.done()) {
10850 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +000010851 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000010852 if (statement_position < p && p <= position) {
10853 statement_position = p;
10854 }
10855 }
10856 it.next();
10857 }
10858 return statement_position;
10859}
10860
10861
Ben Murdochb8e0da22011-05-16 14:20:40 +010010862SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010863 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +010010864 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010865}
10866
10867
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010868Object* Code::FindNthObject(int n, Map* match_map) {
10869 DCHECK(is_inline_cache_stub());
10870 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010010871 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10872 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10873 RelocInfo* info = it.rinfo();
10874 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010875 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010876 if (object->IsHeapObject()) {
10877 if (HeapObject::cast(object)->map() == match_map) {
10878 if (--n == 0) return object;
10879 }
10880 }
10881 }
10882 return NULL;
10883}
10884
10885
10886AllocationSite* Code::FindFirstAllocationSite() {
10887 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
10888 return (result != NULL) ? AllocationSite::cast(result) : NULL;
10889}
10890
10891
10892Map* Code::FindFirstMap() {
10893 Object* result = FindNthObject(1, GetHeap()->meta_map());
10894 return (result != NULL) ? Map::cast(result) : NULL;
10895}
10896
10897
10898void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
10899 DCHECK(is_inline_cache_stub() || is_handler());
10900 DisallowHeapAllocation no_allocation;
10901 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10902 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
10903 int current_pattern = 0;
10904 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10905 RelocInfo* info = it.rinfo();
10906 Object* object = info->target_object();
10907 if (object->IsHeapObject()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010908 if (object->IsWeakCell()) {
10909 object = HeapObject::cast(WeakCell::cast(object)->value());
10910 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010911 Map* map = HeapObject::cast(object)->map();
10912 if (map == *pattern.find_[current_pattern]) {
10913 info->set_target_object(*pattern.replace_[current_pattern]);
10914 if (++current_pattern == pattern.count_) return;
10915 }
10916 }
10917 }
10918 UNREACHABLE();
10919}
10920
10921
10922void Code::FindAllMaps(MapHandleList* maps) {
10923 DCHECK(is_inline_cache_stub());
10924 DisallowHeapAllocation no_allocation;
10925 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10926 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10927 RelocInfo* info = it.rinfo();
10928 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010929 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010930 if (object->IsMap()) maps->Add(handle(Map::cast(object)));
10931 }
10932}
10933
10934
10935Code* Code::FindFirstHandler() {
10936 DCHECK(is_inline_cache_stub());
10937 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010938 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10939 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10940 bool skip_next_handler = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010941 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10942 RelocInfo* info = it.rinfo();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010943 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
10944 Object* obj = info->target_object();
10945 skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
10946 } else {
10947 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10948 if (code->kind() == Code::HANDLER) {
10949 if (!skip_next_handler) return code;
10950 skip_next_handler = false;
10951 }
10952 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010953 }
10954 return NULL;
10955}
10956
10957
10958bool Code::FindHandlers(CodeHandleList* code_list, int length) {
10959 DCHECK(is_inline_cache_stub());
10960 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010961 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10962 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10963 bool skip_next_handler = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010964 int i = 0;
10965 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10966 if (i == length) return true;
10967 RelocInfo* info = it.rinfo();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010968 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
10969 Object* obj = info->target_object();
10970 skip_next_handler |= obj->IsWeakCell() && WeakCell::cast(obj)->cleared();
10971 } else {
10972 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10973 // IC stubs with handlers never contain non-handler code objects before
10974 // handler targets.
10975 if (code->kind() != Code::HANDLER) break;
10976 if (!skip_next_handler) {
10977 code_list->Add(Handle<Code>(code));
10978 i++;
10979 }
10980 skip_next_handler = false;
10981 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010982 }
10983 return i == length;
10984}
10985
10986
10987MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
10988 DCHECK(is_inline_cache_stub());
10989 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10990 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10991 bool return_next = false;
10992 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10993 RelocInfo* info = it.rinfo();
10994 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
10995 Object* object = info->target_object();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040010996 if (object->IsWeakCell()) object = WeakCell::cast(object)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010997 if (object == map) return_next = true;
10998 } else if (return_next) {
10999 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
11000 DCHECK(code->kind() == Code::HANDLER);
11001 return handle(code);
11002 }
11003 }
11004 return MaybeHandle<Code>();
11005}
11006
11007
11008Name* Code::FindFirstName() {
11009 DCHECK(is_inline_cache_stub());
11010 DisallowHeapAllocation no_allocation;
11011 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
11012 for (RelocIterator it(this, mask); !it.done(); it.next()) {
11013 RelocInfo* info = it.rinfo();
11014 Object* object = info->target_object();
11015 if (object->IsName()) return Name::cast(object);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011016 }
11017 return NULL;
11018}
11019
11020
Ben Murdoch8f9999f2012-04-23 10:39:17 +010011021void Code::ClearInlineCaches() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011022 ClearInlineCaches(NULL);
11023}
11024
11025
11026void Code::ClearInlineCaches(Code::Kind kind) {
11027 ClearInlineCaches(&kind);
11028}
11029
11030
11031void Code::ClearInlineCaches(Code::Kind* kind) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010011032 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
11033 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011034 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010011035 for (RelocIterator it(this, mask); !it.done(); it.next()) {
11036 RelocInfo* info = it.rinfo();
11037 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
11038 if (target->is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011039 if (kind == NULL || *kind == target->kind()) {
11040 IC::Clear(this->GetIsolate(), info->pc(),
11041 info->host()->constant_pool());
11042 }
Ben Murdoch8f9999f2012-04-23 10:39:17 +010011043 }
11044 }
11045}
11046
11047
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011048void SharedFunctionInfo::ClearTypeFeedbackInfo() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011049 feedback_vector()->ClearSlots(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011050}
11051
11052
11053BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
11054 DisallowHeapAllocation no_gc;
11055 DCHECK(kind() == FUNCTION);
11056 BackEdgeTable back_edges(this, &no_gc);
11057 for (uint32_t i = 0; i < back_edges.length(); i++) {
11058 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
11059 }
11060 return BailoutId::None();
11061}
11062
11063
11064uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
11065 DisallowHeapAllocation no_gc;
11066 DCHECK(kind() == FUNCTION);
11067 BackEdgeTable back_edges(this, &no_gc);
11068 for (uint32_t i = 0; i < back_edges.length(); i++) {
11069 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
11070 }
11071 UNREACHABLE(); // We expect to find the back edge.
11072 return 0;
11073}
11074
11075
11076void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
11077 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
11078}
11079
11080
11081void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
11082 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
11083 NO_MARKING_PARITY);
11084}
11085
11086
11087static Code::Age EffectiveAge(Code::Age age) {
11088 if (age == Code::kNotExecutedCodeAge) {
11089 // Treat that's never been executed as old immediately.
11090 age = Code::kIsOldCodeAge;
11091 } else if (age == Code::kExecutedOnceCodeAge) {
11092 // Pre-age code that has only been executed once.
11093 age = Code::kPreAgedCodeAge;
11094 }
11095 return age;
11096}
11097
11098
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011099void Code::MakeYoung(Isolate* isolate) {
11100 byte* sequence = FindCodeAgeSequence();
11101 if (sequence != NULL) MakeCodeAgeSequenceYoung(sequence, isolate);
11102}
11103
11104
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011105void Code::MakeOlder(MarkingParity current_parity) {
11106 byte* sequence = FindCodeAgeSequence();
11107 if (sequence != NULL) {
11108 Age age;
11109 MarkingParity code_parity;
11110 Isolate* isolate = GetIsolate();
11111 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
11112 age = EffectiveAge(age);
11113 if (age != kLastCodeAge && code_parity != current_parity) {
11114 PatchPlatformCodeAge(isolate,
11115 sequence,
11116 static_cast<Age>(age + 1),
11117 current_parity);
11118 }
11119 }
11120}
11121
11122
11123bool Code::IsOld() {
11124 return GetAge() >= kIsOldCodeAge;
11125}
11126
11127
11128byte* Code::FindCodeAgeSequence() {
11129 return FLAG_age_code &&
11130 prologue_offset() != Code::kPrologueOffsetNotSet &&
11131 (kind() == OPTIMIZED_FUNCTION ||
11132 (kind() == FUNCTION && !has_debug_break_slots()))
11133 ? instruction_start() + prologue_offset()
11134 : NULL;
11135}
11136
11137
11138Code::Age Code::GetAge() {
11139 return EffectiveAge(GetRawAge());
11140}
11141
11142
11143Code::Age Code::GetRawAge() {
11144 byte* sequence = FindCodeAgeSequence();
11145 if (sequence == NULL) {
11146 return kNoAgeCodeAge;
11147 }
11148 Age age;
11149 MarkingParity parity;
11150 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
11151 return age;
11152}
11153
11154
11155void Code::GetCodeAgeAndParity(Code* code, Age* age,
11156 MarkingParity* parity) {
11157 Isolate* isolate = code->GetIsolate();
11158 Builtins* builtins = isolate->builtins();
11159 Code* stub = NULL;
11160#define HANDLE_CODE_AGE(AGE) \
11161 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
11162 if (code == stub) { \
11163 *age = k##AGE##CodeAge; \
11164 *parity = EVEN_MARKING_PARITY; \
11165 return; \
11166 } \
11167 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
11168 if (code == stub) { \
11169 *age = k##AGE##CodeAge; \
11170 *parity = ODD_MARKING_PARITY; \
11171 return; \
11172 }
11173 CODE_AGE_LIST(HANDLE_CODE_AGE)
11174#undef HANDLE_CODE_AGE
11175 stub = *builtins->MarkCodeAsExecutedOnce();
11176 if (code == stub) {
11177 *age = kNotExecutedCodeAge;
11178 *parity = NO_MARKING_PARITY;
11179 return;
11180 }
11181 stub = *builtins->MarkCodeAsExecutedTwice();
11182 if (code == stub) {
11183 *age = kExecutedOnceCodeAge;
11184 *parity = NO_MARKING_PARITY;
11185 return;
11186 }
11187 UNREACHABLE();
11188}
11189
11190
11191Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
11192 Builtins* builtins = isolate->builtins();
11193 switch (age) {
11194#define HANDLE_CODE_AGE(AGE) \
11195 case k##AGE##CodeAge: { \
11196 Code* stub = parity == EVEN_MARKING_PARITY \
11197 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
11198 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
11199 return stub; \
11200 }
11201 CODE_AGE_LIST(HANDLE_CODE_AGE)
11202#undef HANDLE_CODE_AGE
11203 case kNotExecutedCodeAge: {
11204 DCHECK(parity == NO_MARKING_PARITY);
11205 return *builtins->MarkCodeAsExecutedOnce();
11206 }
11207 case kExecutedOnceCodeAge: {
11208 DCHECK(parity == NO_MARKING_PARITY);
11209 return *builtins->MarkCodeAsExecutedTwice();
11210 }
11211 default:
11212 UNREACHABLE();
11213 break;
11214 }
11215 return NULL;
11216}
11217
11218
11219void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
11220 const char* last_comment = NULL;
11221 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
11222 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
11223 for (RelocIterator it(this, mask); !it.done(); it.next()) {
11224 RelocInfo* info = it.rinfo();
11225 if (info->rmode() == RelocInfo::COMMENT) {
11226 last_comment = reinterpret_cast<const char*>(info->data());
11227 } else if (last_comment != NULL) {
11228 if ((bailout_id == Deoptimizer::GetDeoptimizationId(
11229 GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
11230 (bailout_id == Deoptimizer::GetDeoptimizationId(
11231 GetIsolate(), info->target_address(), Deoptimizer::SOFT)) ||
11232 (bailout_id == Deoptimizer::GetDeoptimizationId(
11233 GetIsolate(), info->target_address(), Deoptimizer::LAZY))) {
11234 CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
11235 PrintF(out, " %s\n", last_comment);
11236 return;
11237 }
11238 }
11239 }
11240}
11241
11242
11243bool Code::CanDeoptAt(Address pc) {
11244 DeoptimizationInputData* deopt_data =
11245 DeoptimizationInputData::cast(deoptimization_data());
11246 Address code_start_address = instruction_start();
11247 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
11248 if (deopt_data->Pc(i)->value() == -1) continue;
11249 Address address = code_start_address + deopt_data->Pc(i)->value();
11250 if (address == pc) return true;
11251 }
11252 return false;
11253}
11254
11255
11256// Identify kind of code.
11257const char* Code::Kind2String(Kind kind) {
11258 switch (kind) {
11259#define CASE(name) case name: return #name;
11260 CODE_KIND_LIST(CASE)
11261#undef CASE
11262 case NUMBER_OF_KINDS: break;
11263 }
11264 UNREACHABLE();
11265 return NULL;
11266}
11267
11268
Steve Blocka7e24c12009-10-30 11:49:00 +000011269#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010011270
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011271void DeoptimizationInputData::DeoptimizationInputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011272 std::ostream& os) { // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010011273 disasm::NameConverter converter;
11274 int deopt_count = DeoptCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011275 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
11276 if (0 != deopt_count) {
11277 os << " index ast id argc pc";
11278 if (FLAG_print_code_verbose) os << " commands";
11279 os << "\n";
11280 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010011281 for (int i = 0; i < deopt_count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011282 // TODO(svenpanne) Add some basic formatting to our streams.
11283 Vector<char> buf1 = Vector<char>::New(128);
11284 SNPrintF(buf1, "%6d %6d %6d %6d", i, AstId(i).ToInt(),
11285 ArgumentsStackHeight(i)->value(), Pc(i)->value());
11286 os << buf1.start();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011287
11288 if (!FLAG_print_code_verbose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011289 os << "\n";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011290 continue;
11291 }
11292 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +010011293 int translation_index = TranslationIndex(i)->value();
11294 TranslationIterator iterator(TranslationByteArray(), translation_index);
11295 Translation::Opcode opcode =
11296 static_cast<Translation::Opcode>(iterator.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011297 DCHECK(Translation::BEGIN == opcode);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011298 int frame_count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011299 int jsframe_count = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011300 os << " " << Translation::StringFor(opcode)
11301 << " {frame count=" << frame_count
11302 << ", js frame count=" << jsframe_count << "}\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011303
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011304 while (iterator.HasNext() &&
11305 Translation::BEGIN !=
11306 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011307 Vector<char> buf2 = Vector<char>::New(128);
11308 SNPrintF(buf2, "%27s %s ", "", Translation::StringFor(opcode));
11309 os << buf2.start();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011310
11311 switch (opcode) {
11312 case Translation::BEGIN:
11313 UNREACHABLE();
11314 break;
11315
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011316 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011317 int ast_id = iterator.Next();
11318 int function_id = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011319 unsigned height = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011320 os << "{ast_id=" << ast_id << ", function=";
11321 if (function_id != Translation::kSelfLiteralId) {
11322 Object* function = LiteralArray()->get(function_id);
11323 os << Brief(JSFunction::cast(function)->shared()->DebugName());
11324 } else {
11325 os << "<self>";
11326 }
11327 os << ", height=" << height << "}";
11328 break;
11329 }
11330
11331 case Translation::COMPILED_STUB_FRAME: {
11332 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
11333 os << "{kind=" << stub_kind << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011334 break;
11335 }
11336
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011337 case Translation::ARGUMENTS_ADAPTOR_FRAME:
11338 case Translation::CONSTRUCT_STUB_FRAME: {
11339 int function_id = iterator.Next();
11340 JSFunction* function =
11341 JSFunction::cast(LiteralArray()->get(function_id));
11342 unsigned height = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011343 os << "{function=" << Brief(function->shared()->DebugName())
11344 << ", height=" << height << "}";
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011345 break;
11346 }
11347
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011348 case Translation::GETTER_STUB_FRAME:
11349 case Translation::SETTER_STUB_FRAME: {
11350 int function_id = iterator.Next();
11351 JSFunction* function =
11352 JSFunction::cast(LiteralArray()->get(function_id));
11353 os << "{function=" << Brief(function->shared()->DebugName()) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011354 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011355 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011356
11357 case Translation::REGISTER: {
11358 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011359 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011360 break;
11361 }
11362
11363 case Translation::INT32_REGISTER: {
11364 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011365 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
11366 break;
11367 }
11368
11369 case Translation::UINT32_REGISTER: {
11370 int reg_code = iterator.Next();
11371 os << "{input=" << converter.NameOfCPURegister(reg_code)
11372 << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011373 break;
11374 }
11375
11376 case Translation::DOUBLE_REGISTER: {
11377 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011378 os << "{input=" << DoubleRegister::AllocationIndexToString(reg_code)
11379 << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011380 break;
11381 }
11382
11383 case Translation::STACK_SLOT: {
11384 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011385 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011386 break;
11387 }
11388
11389 case Translation::INT32_STACK_SLOT: {
11390 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011391 os << "{input=" << input_slot_index << "}";
11392 break;
11393 }
11394
11395 case Translation::UINT32_STACK_SLOT: {
11396 int input_slot_index = iterator.Next();
11397 os << "{input=" << input_slot_index << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011398 break;
11399 }
11400
11401 case Translation::DOUBLE_STACK_SLOT: {
11402 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011403 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011404 break;
11405 }
11406
11407 case Translation::LITERAL: {
11408 unsigned literal_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011409 os << "{literal_id=" << literal_index << "}";
11410 break;
11411 }
11412
11413 case Translation::DUPLICATED_OBJECT: {
11414 int object_index = iterator.Next();
11415 os << "{object_index=" << object_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011416 break;
11417 }
11418
11419 case Translation::ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011420 case Translation::CAPTURED_OBJECT: {
11421 int args_length = iterator.Next();
11422 os << "{length=" << args_length << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011423 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011424 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010011425 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011426 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011427 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010011428 }
11429}
11430
11431
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011432void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011433 std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011434 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
11435 << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011436 if (this->DeoptPoints() == 0) return;
11437
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011438 os << "ast id pc state\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011439 for (int i = 0; i < this->DeoptPoints(); i++) {
11440 int pc_and_state = this->PcAndState(i)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011441 // TODO(svenpanne) Add some basic formatting to our streams.
11442 Vector<char> buf = Vector<char>::New(100);
11443 SNPrintF(buf, "%6d %8d %s\n", this->AstId(i).ToInt(),
11444 FullCodeGenerator::PcField::decode(pc_and_state),
11445 FullCodeGenerator::State2String(
11446 FullCodeGenerator::StateField::decode(pc_and_state)));
11447 os << buf.start();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011448 }
11449}
11450
Ben Murdochb0fe1622011-05-05 13:52:32 +010011451
Steve Blocka7e24c12009-10-30 11:49:00 +000011452const char* Code::ICState2String(InlineCacheState state) {
11453 switch (state) {
11454 case UNINITIALIZED: return "UNINITIALIZED";
11455 case PREMONOMORPHIC: return "PREMONOMORPHIC";
11456 case MONOMORPHIC: return "MONOMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011457 case PROTOTYPE_FAILURE:
11458 return "PROTOTYPE_FAILURE";
11459 case POLYMORPHIC: return "POLYMORPHIC";
Steve Blocka7e24c12009-10-30 11:49:00 +000011460 case MEGAMORPHIC: return "MEGAMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011461 case GENERIC: return "GENERIC";
11462 case DEBUG_STUB: return "DEBUG_STUB";
11463 case DEFAULT:
11464 return "DEFAULT";
Steve Blocka7e24c12009-10-30 11:49:00 +000011465 }
11466 UNREACHABLE();
11467 return NULL;
11468}
11469
11470
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011471const char* Code::StubType2String(StubType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011472 switch (type) {
11473 case NORMAL: return "NORMAL";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011474 case FAST: return "FAST";
Steve Blocka7e24c12009-10-30 11:49:00 +000011475 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011476 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +000011477 return NULL;
11478}
11479
Ben Murdochb0fe1622011-05-05 13:52:32 +010011480
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011481void Code::PrintExtraICState(std::ostream& os, // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011482 Kind kind, ExtraICState extra) {
11483 os << "extra_ic_state = ";
11484 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && (extra == STRICT)) {
11485 os << "STRICT\n";
Steve Block1e0659c2011-05-24 12:43:12 +010011486 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011487 os << extra << "\n";
Steve Block1e0659c2011-05-24 12:43:12 +010011488 }
11489}
11490
11491
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011492void Code::Disassemble(const char* name, std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011493 os << "kind = " << Kind2String(kind()) << "\n";
11494 if (IsCodeStubOrIC()) {
11495 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
11496 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
11497 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011498 if (is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011499 os << "ic_state = " << ICState2String(ic_state()) << "\n";
11500 PrintExtraICState(os, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +000011501 if (ic_state() == MONOMORPHIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011502 os << "type = " << StubType2String(type()) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000011503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011504 if (is_compare_ic_stub()) {
11505 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
11506 CompareICStub stub(stub_key(), GetIsolate());
11507 os << "compare_state = " << CompareICState::GetStateName(stub.left())
11508 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
11509 << CompareICState::GetStateName(stub.state()) << "\n";
11510 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011511 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011512 }
11513 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011514 os << "name = " << name << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011515 }
11516 if (kind() == OPTIMIZED_FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011517 os << "stack_slots = " << stack_slots() << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000011518 }
11519
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011520 os << "Instructions (size = " << instruction_size() << ")\n";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011521 {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011522 Isolate* isolate = GetIsolate();
11523 int decode_size = is_crankshafted()
11524 ? static_cast<int>(safepoint_table_offset())
11525 : instruction_size();
11526 // If there might be a back edge table, stop before reaching it.
11527 if (kind() == Code::FUNCTION) {
11528 decode_size =
11529 Min(decode_size, static_cast<int>(back_edge_table_offset()));
11530 }
11531 byte* begin = instruction_start();
11532 byte* end = begin + decode_size;
11533 Disassembler::Decode(isolate, &os, begin, end, this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011534 }
11535 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011536
Ben Murdochb0fe1622011-05-05 13:52:32 +010011537 if (kind() == FUNCTION) {
11538 DeoptimizationOutputData* data =
11539 DeoptimizationOutputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011540 data->DeoptimizationOutputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011541 } else if (kind() == OPTIMIZED_FUNCTION) {
11542 DeoptimizationInputData* data =
11543 DeoptimizationInputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011544 data->DeoptimizationInputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011545 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011546 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011547
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011548 if (is_crankshafted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010011549 SafepointTable table(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011550 os << "Safepoints (size = " << table.size() << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011551 for (unsigned i = 0; i < table.length(); i++) {
11552 unsigned pc_offset = table.GetPcOffset(i);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011553 os << static_cast<const void*>(instruction_start() + pc_offset) << " ";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011554 // TODO(svenpanne) Add some basic formatting to our streams.
11555 Vector<char> buf1 = Vector<char>::New(30);
11556 SNPrintF(buf1, "%4d", pc_offset);
11557 os << buf1.start() << " ";
11558 table.PrintEntry(i, os);
11559 os << " (sp -> fp) ";
Ben Murdochb8e0da22011-05-16 14:20:40 +010011560 SafepointEntry entry = table.GetEntry(i);
11561 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011562 Vector<char> buf2 = Vector<char>::New(30);
11563 SNPrintF(buf2, "%6d", entry.deoptimization_index());
11564 os << buf2.start();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011565 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011566 os << "<none>";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011567 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010011568 if (entry.argument_count() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011569 os << " argc: " << entry.argument_count();
Ben Murdochb8e0da22011-05-16 14:20:40 +010011570 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011571 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011572 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011573 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011574 } else if (kind() == FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011575 unsigned offset = back_edge_table_offset();
11576 // If there is no back edge table, the "table start" will be at or after
Ben Murdochb0fe1622011-05-05 13:52:32 +010011577 // (due to alignment) the end of the instruction stream.
11578 if (static_cast<int>(offset) < instruction_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011579 DisallowHeapAllocation no_gc;
11580 BackEdgeTable back_edges(this, &no_gc);
11581
11582 os << "Back edges (size = " << back_edges.length() << ")\n";
11583 os << "ast_id pc_offset loop_depth\n";
11584
11585 for (uint32_t i = 0; i < back_edges.length(); i++) {
11586 Vector<char> buf = Vector<char>::New(100);
11587 SNPrintF(buf, "%6d %9u %10u\n", back_edges.ast_id(i).ToInt(),
11588 back_edges.pc_offset(i), back_edges.loop_depth(i));
11589 os << buf.start();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011590 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011591
11592 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010011593 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011594#ifdef OBJECT_PRINT
11595 if (!type_feedback_info()->IsUndefined()) {
11596 OFStream os(stdout);
11597 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
11598 os << "\n";
11599 }
11600#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +010011601 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011602
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011603 os << "RelocInfo (size = " << relocation_size() << ")\n";
11604 for (RelocIterator it(this); !it.done(); it.next()) {
11605 it.rinfo()->Print(GetIsolate(), os);
11606 }
11607 os << "\n";
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011608
11609#ifdef OBJECT_PRINT
11610 if (FLAG_enable_ool_constant_pool) {
11611 ConstantPoolArray* pool = constant_pool();
11612 if (pool->length()) {
11613 os << "Constant Pool\n";
11614 pool->Print(os);
11615 os << "\n";
11616 }
11617 }
11618#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000011619}
11620#endif // ENABLE_DISASSEMBLER
11621
11622
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011623Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength(
11624 Handle<JSObject> object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011625 int capacity,
11626 int length,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011627 SetFastElementsCapacitySmiMode smi_mode) {
Steve Block3ce2e202009-11-05 08:53:23 +000011628 // We should never end in here with a pixel or external array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011629 DCHECK(!object->HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +010011630
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011631 // Allocate a new fast elements backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011632 Handle<FixedArray> new_elements =
11633 object->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011634
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011635 ElementsKind elements_kind = object->GetElementsKind();
11636 ElementsKind new_elements_kind;
11637 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
11638 // or if it's allowed and the old elements array contained only SMIs.
11639 bool has_fast_smi_elements =
11640 (smi_mode == kForceSmiElements) ||
11641 ((smi_mode == kAllowSmiElements) && object->HasFastSmiElements());
11642 if (has_fast_smi_elements) {
11643 if (IsHoleyElementsKind(elements_kind)) {
11644 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
11645 } else {
11646 new_elements_kind = FAST_SMI_ELEMENTS;
11647 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011648 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011649 if (IsHoleyElementsKind(elements_kind)) {
11650 new_elements_kind = FAST_HOLEY_ELEMENTS;
11651 } else {
11652 new_elements_kind = FAST_ELEMENTS;
11653 }
11654 }
11655 Handle<FixedArrayBase> old_elements(object->elements());
11656 ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
11657 accessor->CopyElements(object, new_elements, elements_kind);
11658
11659 if (elements_kind != SLOPPY_ARGUMENTS_ELEMENTS) {
11660 Handle<Map> new_map = (new_elements_kind != elements_kind)
11661 ? GetElementsTransitionMap(object, new_elements_kind)
11662 : handle(object->map());
11663 JSObject::ValidateElements(object);
11664 JSObject::SetMapAndElements(object, new_map, new_elements);
11665
11666 // Transition through the allocation site as well if present.
11667 JSObject::UpdateAllocationSite(object, new_elements_kind);
11668 } else {
11669 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements);
11670 parameter_map->set(1, *new_elements);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011671 }
11672
11673 if (FLAG_trace_elements_transitions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011674 PrintElementsTransition(stdout, object, elements_kind, old_elements,
11675 object->GetElementsKind(), new_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011676 }
11677
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011678 if (object->IsJSArray()) {
11679 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011680 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011681 return new_elements;
11682}
11683
11684
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011685void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,
11686 int capacity,
11687 int length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011688 // We should never end in here with a pixel or external array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011689 DCHECK(!object->HasExternalArrayElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011690
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011691 Handle<FixedArrayBase> elems =
11692 object->GetIsolate()->factory()->NewFixedDoubleArray(capacity);
Steve Block8defd9f2010-07-08 12:39:36 +010011693
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011694 ElementsKind elements_kind = object->GetElementsKind();
11695 CHECK(elements_kind != SLOPPY_ARGUMENTS_ELEMENTS);
11696 ElementsKind new_elements_kind = elements_kind;
11697 if (IsHoleyElementsKind(elements_kind)) {
11698 new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011699 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011700 new_elements_kind = FAST_DOUBLE_ELEMENTS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011701 }
11702
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011703 Handle<Map> new_map = GetElementsTransitionMap(object, new_elements_kind);
11704
11705 Handle<FixedArrayBase> old_elements(object->elements());
11706 ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
11707 accessor->CopyElements(object, elems, elements_kind);
11708
11709 JSObject::ValidateElements(object);
11710 JSObject::SetMapAndElements(object, new_map, elems);
11711
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011712 if (FLAG_trace_elements_transitions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011713 PrintElementsTransition(stdout, object, elements_kind, old_elements,
11714 object->GetElementsKind(), elems);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011715 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011716
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011717 if (object->IsJSArray()) {
11718 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
Steve Block8defd9f2010-07-08 12:39:36 +010011719 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011720}
11721
11722
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011723// static
11724void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
11725 DCHECK(capacity >= 0);
11726 array->GetIsolate()->factory()->NewJSArrayStorage(
11727 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
11728}
11729
11730
11731void JSArray::Expand(Handle<JSArray> array, int required_size) {
11732 ElementsAccessor* accessor = array->GetElementsAccessor();
11733 accessor->SetCapacityAndLength(array, required_size, required_size);
11734}
11735
11736
11737// Returns false if the passed-in index is marked non-configurable,
11738// which will cause the ES5 truncation operation to halt, and thus
11739// no further old values need be collected.
11740static bool GetOldValue(Isolate* isolate,
11741 Handle<JSObject> object,
11742 uint32_t index,
11743 List<Handle<Object> >* old_values,
11744 List<uint32_t>* indices) {
11745 Maybe<PropertyAttributes> maybe =
11746 JSReceiver::GetOwnElementAttribute(object, index);
11747 DCHECK(maybe.has_value);
11748 DCHECK(maybe.value != ABSENT);
11749 if (maybe.value == DONT_DELETE) return false;
11750 Handle<Object> value;
11751 if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) {
11752 value = Handle<Object>::cast(isolate->factory()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011753 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011754 value = Object::GetElement(isolate, object, index).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011755 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011756 old_values->Add(value);
11757 indices->Add(index);
11758 return true;
11759}
11760
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011761MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord(
11762 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted,
11763 uint32_t add_count) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011764 Isolate* isolate = object->GetIsolate();
11765 HandleScope scope(isolate);
11766 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
11767 Handle<Object> add_count_object =
11768 isolate->factory()->NewNumberFromUint(add_count);
11769
11770 Handle<Object> args[] =
11771 { object, index_object, deleted, add_count_object };
11772
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011773 return Execution::Call(
11774 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()),
11775 isolate->factory()->undefined_value(), arraysize(args), args);
Steve Blocka7e24c12009-10-30 11:49:00 +000011776}
11777
11778
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011779MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice(
11780 Handle<JSArray> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011781 Isolate* isolate = object->GetIsolate();
11782 HandleScope scope(isolate);
11783 Handle<Object> args[] = { object };
11784
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011785 return Execution::Call(
11786 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()),
11787 isolate->factory()->undefined_value(), arraysize(args), args);
Steve Blocka7e24c12009-10-30 11:49:00 +000011788}
11789
11790
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011791MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice(
11792 Handle<JSArray> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011793 Isolate* isolate = object->GetIsolate();
11794 HandleScope scope(isolate);
11795 Handle<Object> args[] = { object };
11796
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011797 return Execution::Call(
11798 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()),
11799 isolate->factory()->undefined_value(), arraysize(args), args);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011800}
11801
11802
11803MaybeHandle<Object> JSArray::SetElementsLength(
11804 Handle<JSArray> array,
11805 Handle<Object> new_length_handle) {
11806 if (array->HasFastElements()) {
11807 // If the new array won't fit in a some non-trivial fraction of the max old
11808 // space size, then force it to go dictionary mode.
11809 int max_fast_array_size = static_cast<int>(
11810 (array->GetHeap()->MaxOldGenerationSize() / kDoubleSize) / 4);
11811 if (new_length_handle->IsNumber() &&
11812 NumberToInt32(*new_length_handle) >= max_fast_array_size) {
11813 NormalizeElements(array);
11814 }
11815 }
11816
Steve Block3ce2e202009-11-05 08:53:23 +000011817 // We should never end in here with a pixel or external array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011818 DCHECK(array->AllowsSetElementsLength());
11819 if (!array->map()->is_observed()) {
11820 return array->GetElementsAccessor()->SetLength(array, new_length_handle);
11821 }
11822
11823 Isolate* isolate = array->GetIsolate();
11824 List<uint32_t> indices;
11825 List<Handle<Object> > old_values;
11826 Handle<Object> old_length_handle(array->length(), isolate);
11827 uint32_t old_length = 0;
11828 CHECK(old_length_handle->ToArrayIndex(&old_length));
11829 uint32_t new_length = 0;
11830 CHECK(new_length_handle->ToArrayIndex(&new_length));
11831
11832 static const PropertyAttributes kNoAttrFilter = NONE;
11833 int num_elements = array->NumberOfOwnElements(kNoAttrFilter);
11834 if (num_elements > 0) {
11835 if (old_length == static_cast<uint32_t>(num_elements)) {
11836 // Simple case for arrays without holes.
11837 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
11838 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
11839 }
11840 } else {
11841 // For sparse arrays, only iterate over existing elements.
11842 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
11843 // the to-be-removed indices twice.
11844 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
11845 array->GetOwnElementKeys(*keys, kNoAttrFilter);
11846 while (num_elements-- > 0) {
11847 uint32_t index = NumberToUint32(keys->get(num_elements));
11848 if (index < new_length) break;
11849 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
11850 }
11851 }
11852 }
11853
11854 Handle<Object> hresult;
11855 ASSIGN_RETURN_ON_EXCEPTION(
11856 isolate, hresult,
11857 array->GetElementsAccessor()->SetLength(array, new_length_handle),
11858 Object);
11859
11860 CHECK(array->length()->ToArrayIndex(&new_length));
11861 if (old_length == new_length) return hresult;
11862
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011863 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011864
11865 for (int i = 0; i < indices.length(); ++i) {
11866 // For deletions where the property was an accessor, old_values[i]
11867 // will be the hole, which instructs EnqueueChangeRecord to elide
11868 // the "oldValue" property.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011869 RETURN_ON_EXCEPTION(
11870 isolate,
11871 JSObject::EnqueueChangeRecord(
11872 array, "delete", isolate->factory()->Uint32ToString(indices[i]),
11873 old_values[i]),
11874 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011875 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011876 RETURN_ON_EXCEPTION(isolate,
11877 JSObject::EnqueueChangeRecord(
11878 array, "update", isolate->factory()->length_string(),
11879 old_length_handle),
11880 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011881
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011882 RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011883
11884 uint32_t index = Min(old_length, new_length);
11885 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
11886 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
11887 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
11888 if (delete_count > 0) {
11889 for (int i = indices.length() - 1; i >= 0; i--) {
11890 // Skip deletions where the property was an accessor, leaving holes
11891 // in the array of old values.
11892 if (old_values[i]->IsTheHole()) continue;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011893 JSObject::SetOwnElement(deleted, indices[i] - index, old_values[i],
11894 SLOPPY).Assert();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011895 }
11896
11897 SetProperty(deleted, isolate->factory()->length_string(),
11898 isolate->factory()->NewNumberFromUint(delete_count),
11899 STRICT).Assert();
11900 }
11901
Emily Bernierd0a1eb72015-03-24 16:35:39 -040011902 RETURN_ON_EXCEPTION(
11903 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011904
11905 return hresult;
Steve Blocka7e24c12009-10-30 11:49:00 +000011906}
11907
11908
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011909Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
11910 Handle<Object> prototype) {
11911 FixedArray* cache = map->GetPrototypeTransitions();
11912 int number_of_transitions = map->NumberOfProtoTransitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011913 const int proto_offset =
11914 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
11915 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
11916 const int step = kProtoTransitionElementsPerEntry;
11917 for (int i = 0; i < number_of_transitions; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011918 if (cache->get(proto_offset + i * step) == *prototype) {
11919 Object* result = cache->get(map_offset + i * step);
11920 return Handle<Map>(Map::cast(result));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011921 }
Steve Block053d10c2011-06-13 19:13:29 +010011922 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011923 return Handle<Map>();
Steve Block053d10c2011-06-13 19:13:29 +010011924}
11925
11926
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011927Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
11928 Handle<Object> prototype,
11929 Handle<Map> target_map) {
11930 DCHECK(target_map->IsMap());
11931 DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
11932 // Don't cache prototype transition if this map is either shared, or a map of
11933 // a prototype.
11934 if (map->is_prototype_map()) return map;
11935 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
Steve Block053d10c2011-06-13 19:13:29 +010011936
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011937 const int step = kProtoTransitionElementsPerEntry;
11938 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +010011939
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011940 Handle<FixedArray> cache(map->GetPrototypeTransitions());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011941 int capacity = (cache->length() - header) / step;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011942 int transitions = map->NumberOfProtoTransitions() + 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011943
11944 if (transitions > capacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011945 if (capacity > kMaxCachedPrototypeTransitions) return map;
Steve Block053d10c2011-06-13 19:13:29 +010011946
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011947 // Grow array by factor 2 over and above what we need.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011948 cache = FixedArray::CopySize(cache, transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +010011949
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011950 SetPrototypeTransitions(map, cache);
Steve Block053d10c2011-06-13 19:13:29 +010011951 }
11952
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011953 // Reload number of transitions as GC might shrink them.
11954 int last = map->NumberOfProtoTransitions();
11955 int entry = header + last * step;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011956
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011957 cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
11958 cache->set(entry + kProtoTransitionMapOffset, *target_map);
11959 map->SetNumberOfProtoTransitions(last + 1);
Steve Block053d10c2011-06-13 19:13:29 +010011960
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011961 return map;
Steve Block053d10c2011-06-13 19:13:29 +010011962}
11963
11964
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011965void Map::ZapTransitions() {
11966 TransitionArray* transition_array = transitions();
11967 // TODO(mstarzinger): Temporarily use a slower version instead of the faster
11968 // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
11969 Object** data = transition_array->data_start();
11970 Object* the_hole = GetHeap()->the_hole_value();
11971 int length = transition_array->length();
11972 for (int i = 0; i < length; i++) {
11973 data[i] = the_hole;
11974 }
11975}
11976
11977
11978void Map::ZapPrototypeTransitions() {
11979 FixedArray* proto_transitions = GetPrototypeTransitions();
11980 MemsetPointer(proto_transitions->data_start(),
11981 GetHeap()->the_hole_value(),
11982 proto_transitions->length());
11983}
11984
11985
11986// static
11987void Map::AddDependentCompilationInfo(Handle<Map> map,
11988 DependentCode::DependencyGroup group,
11989 CompilationInfo* info) {
11990 Handle<DependentCode> codes =
11991 DependentCode::Insert(handle(map->dependent_code(), info->isolate()),
11992 group, info->object_wrapper());
11993 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11994 info->dependencies(group)->Add(map, info->zone());
11995}
11996
11997
11998// static
11999void Map::AddDependentCode(Handle<Map> map,
12000 DependentCode::DependencyGroup group,
12001 Handle<Code> code) {
12002 Handle<DependentCode> codes = DependentCode::Insert(
12003 Handle<DependentCode>(map->dependent_code()), group, code);
12004 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
12005}
12006
12007
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012008DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
12009 Recompute(entries);
12010}
12011
12012
12013void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
12014 start_indexes_[0] = 0;
12015 for (int g = 1; g <= kGroupCount; g++) {
12016 int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
12017 start_indexes_[g] = start_indexes_[g - 1] + count;
12018 }
12019}
12020
12021
12022DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
12023 DependencyGroup group) {
12024 AllowDeferredHandleDereference dependencies_are_safe;
12025 if (group == DependentCode::kPropertyCellChangedGroup) {
12026 return Handle<PropertyCell>::cast(object)->dependent_code();
12027 } else if (group == DependentCode::kAllocationSiteTenuringChangedGroup ||
12028 group == DependentCode::kAllocationSiteTransitionChangedGroup) {
12029 return Handle<AllocationSite>::cast(object)->dependent_code();
12030 }
12031 return Handle<Map>::cast(object)->dependent_code();
12032}
12033
12034
12035Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
12036 DependencyGroup group,
12037 Handle<Object> object) {
12038 GroupStartIndexes starts(*entries);
12039 int start = starts.at(group);
12040 int end = starts.at(group + 1);
12041 int number_of_entries = starts.number_of_entries();
12042 // Check for existing entry to avoid duplicates.
12043 for (int i = start; i < end; i++) {
12044 if (entries->object_at(i) == *object) return entries;
12045 }
12046 if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
12047 int capacity = kCodesStartIndex + number_of_entries + 1;
12048 if (capacity > 5) capacity = capacity * 5 / 4;
12049 Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
12050 FixedArray::CopySize(entries, capacity, TENURED));
12051 // The number of codes can change after GC.
12052 starts.Recompute(*entries);
12053 start = starts.at(group);
12054 end = starts.at(group + 1);
12055 number_of_entries = starts.number_of_entries();
12056 for (int i = 0; i < number_of_entries; i++) {
12057 entries->clear_at(i);
12058 }
12059 // If the old fixed array was empty, we need to reset counters of the
12060 // new array.
12061 if (number_of_entries == 0) {
12062 for (int g = 0; g < kGroupCount; g++) {
12063 new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
12064 }
12065 }
12066 entries = new_entries;
12067 }
12068 entries->ExtendGroup(group);
12069 entries->set_object_at(end, *object);
12070 entries->set_number_of_entries(group, end + 1 - start);
12071 return entries;
12072}
12073
12074
12075void DependentCode::UpdateToFinishedCode(DependencyGroup group,
12076 CompilationInfo* info,
12077 Code* code) {
12078 DisallowHeapAllocation no_gc;
12079 AllowDeferredHandleDereference get_object_wrapper;
12080 Foreign* info_wrapper = *info->object_wrapper();
12081 GroupStartIndexes starts(this);
12082 int start = starts.at(group);
12083 int end = starts.at(group + 1);
12084 for (int i = start; i < end; i++) {
12085 if (object_at(i) == info_wrapper) {
12086 set_object_at(i, code);
12087 break;
12088 }
12089 }
12090
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012091#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012092 for (int i = start; i < end; i++) {
12093 DCHECK(is_code_at(i) || compilation_info_at(i) != info);
12094 }
12095#endif
12096}
12097
12098
12099void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
12100 CompilationInfo* info) {
12101 DisallowHeapAllocation no_allocation;
12102 AllowDeferredHandleDereference get_object_wrapper;
12103 Foreign* info_wrapper = *info->object_wrapper();
12104 GroupStartIndexes starts(this);
12105 int start = starts.at(group);
12106 int end = starts.at(group + 1);
12107 // Find compilation info wrapper.
12108 int info_pos = -1;
12109 for (int i = start; i < end; i++) {
12110 if (object_at(i) == info_wrapper) {
12111 info_pos = i;
12112 break;
12113 }
12114 }
12115 if (info_pos == -1) return; // Not found.
12116 int gap = info_pos;
12117 // Use the last of each group to fill the gap in the previous group.
12118 for (int i = group; i < kGroupCount; i++) {
12119 int last_of_group = starts.at(i + 1) - 1;
12120 DCHECK(last_of_group >= gap);
12121 if (last_of_group == gap) continue;
12122 copy(last_of_group, gap);
12123 gap = last_of_group;
12124 }
12125 DCHECK(gap == starts.number_of_entries() - 1);
12126 clear_at(gap); // Clear last gap.
12127 set_number_of_entries(group, end - start - 1);
12128
12129#ifdef DEBUG
12130 for (int i = start; i < end - 1; i++) {
12131 DCHECK(is_code_at(i) || compilation_info_at(i) != info);
12132 }
12133#endif
12134}
12135
12136
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012137bool DependentCode::Contains(DependencyGroup group, Code* code) {
12138 GroupStartIndexes starts(this);
12139 int start = starts.at(group);
12140 int end = starts.at(group + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012141 for (int i = start; i < end; i++) {
12142 if (object_at(i) == code) return true;
12143 }
12144 return false;
12145}
12146
12147
12148bool DependentCode::MarkCodeForDeoptimization(
12149 Isolate* isolate,
12150 DependentCode::DependencyGroup group) {
12151 DisallowHeapAllocation no_allocation_scope;
12152 DependentCode::GroupStartIndexes starts(this);
12153 int start = starts.at(group);
12154 int end = starts.at(group + 1);
12155 int code_entries = starts.number_of_entries();
12156 if (start == end) return false;
12157
12158 // Mark all the code that needs to be deoptimized.
12159 bool marked = false;
12160 for (int i = start; i < end; i++) {
12161 if (is_code_at(i)) {
12162 Code* code = code_at(i);
12163 if (!code->marked_for_deoptimization()) {
12164 SetMarkedForDeoptimization(code, group);
12165 marked = true;
12166 }
12167 } else {
12168 CompilationInfo* info = compilation_info_at(i);
12169 info->AbortDueToDependencyChange();
12170 }
12171 }
12172 // Compact the array by moving all subsequent groups to fill in the new holes.
12173 for (int src = end, dst = start; src < code_entries; src++, dst++) {
12174 copy(src, dst);
12175 }
12176 // Now the holes are at the end of the array, zap them for heap-verifier.
12177 int removed = end - start;
12178 for (int i = code_entries - removed; i < code_entries; i++) {
12179 clear_at(i);
12180 }
12181 set_number_of_entries(group, 0);
12182 return marked;
12183}
12184
12185
12186void DependentCode::DeoptimizeDependentCodeGroup(
12187 Isolate* isolate,
12188 DependentCode::DependencyGroup group) {
12189 DCHECK(AllowCodeDependencyChange::IsAllowed());
12190 DisallowHeapAllocation no_allocation_scope;
12191 bool marked = MarkCodeForDeoptimization(isolate, group);
12192
12193 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
12194}
12195
12196
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012197void DependentCode::SetMarkedForDeoptimization(Code* code,
12198 DependencyGroup group) {
12199 code->set_marked_for_deoptimization(true);
12200 if (FLAG_trace_deopt &&
12201 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
12202 DeoptimizationInputData* deopt_data =
12203 DeoptimizationInputData::cast(code->deoptimization_data());
12204 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
12205 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
12206 " (opt #%d) for deoptimization, reason: %s]\n",
12207 reinterpret_cast<intptr_t>(code),
12208 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
12209 }
12210}
12211
12212
12213const char* DependentCode::DependencyGroupName(DependencyGroup group) {
12214 switch (group) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012215 case kWeakCodeGroup:
12216 return "weak-code";
12217 case kTransitionGroup:
12218 return "transition";
12219 case kPrototypeCheckGroup:
12220 return "prototype-check";
12221 case kElementsCantBeAddedGroup:
12222 return "elements-cant-be-added";
12223 case kPropertyCellChangedGroup:
12224 return "property-cell-changed";
12225 case kFieldTypeGroup:
12226 return "field-type";
12227 case kInitialMapChangedGroup:
12228 return "initial-map-changed";
12229 case kAllocationSiteTenuringChangedGroup:
12230 return "allocation-site-tenuring-changed";
12231 case kAllocationSiteTransitionChangedGroup:
12232 return "allocation-site-transition-changed";
12233 }
12234 UNREACHABLE();
12235 return "?";
12236}
12237
12238
12239Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012240 Handle<Object> prototype,
12241 PrototypeOptimizationMode mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012242 Handle<Map> new_map = GetPrototypeTransition(map, prototype);
12243 if (new_map.is_null()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012244 new_map = Copy(map, "TransitionToPrototype");
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012245 PutPrototypeTransition(map, prototype, new_map);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012246 new_map->SetPrototype(prototype, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012247 }
12248 return new_map;
12249}
12250
12251
12252MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
12253 Handle<Object> value,
12254 bool from_javascript) {
12255#ifdef DEBUG
12256 int size = object->Size();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012257#endif
12258
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012259 Isolate* isolate = object->GetIsolate();
12260 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +000012261 // Silently ignore the change if value is not a JSObject or null.
12262 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012263 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +000012264
Ben Murdoch8b112d22011-06-08 16:22:53 +010012265 // From 8.6.2 Object Internal Methods
12266 // ...
12267 // In addition, if [[Extensible]] is false the value of the [[Class]] and
12268 // [[Prototype]] internal properties of the object may not be modified.
12269 // ...
12270 // Implementation specific extensions that modify [[Class]], [[Prototype]]
12271 // or [[Extensible]] must not violate the invariants defined in the preceding
12272 // paragraph.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012273 if (!object->map()->is_extensible()) {
12274 Handle<Object> args[] = { object };
12275 THROW_NEW_ERROR(isolate, NewTypeError("non_extensible_proto",
12276 HandleVector(args, arraysize(args))),
12277 Object);
Ben Murdoch8b112d22011-06-08 16:22:53 +010012278 }
12279
Andrei Popescu402d9372010-02-26 13:31:12 +000012280 // Before we can set the prototype we need to be sure
12281 // prototype cycles are prevented.
12282 // It is sufficient to validate that the receiver is not in the new prototype
12283 // chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012284 for (PrototypeIterator iter(isolate, *value,
12285 PrototypeIterator::START_AT_RECEIVER);
12286 !iter.IsAtEnd(); iter.Advance()) {
12287 if (JSReceiver::cast(iter.GetCurrent()) == *object) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012288 // Cycle detected.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012289 THROW_NEW_ERROR(isolate,
12290 NewError("cyclic_proto", HandleVector<Object>(NULL, 0)),
12291 Object);
Andrei Popescu402d9372010-02-26 13:31:12 +000012292 }
12293 }
12294
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012295 bool dictionary_elements_in_chain =
12296 object->map()->DictionaryElementsInPrototypeChainOnly();
12297 Handle<JSObject> real_receiver = object;
Andrei Popescu402d9372010-02-26 13:31:12 +000012298
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012299 if (from_javascript) {
Andrei Popescu402d9372010-02-26 13:31:12 +000012300 // Find the first object in the chain whose prototype object is not
12301 // hidden and set the new prototype on that object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012302 PrototypeIterator iter(isolate, real_receiver);
12303 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
12304 real_receiver =
12305 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
12306 iter.Advance();
Andrei Popescu402d9372010-02-26 13:31:12 +000012307 }
12308 }
12309
12310 // Set the new prototype of the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012311 Handle<Map> map(real_receiver->map());
Steve Block053d10c2011-06-13 19:13:29 +010012312
12313 // Nothing to do if prototype is already set.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012314 if (map->prototype() == *value) return value;
Steve Block053d10c2011-06-13 19:13:29 +010012315
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012316 PrototypeOptimizationMode mode =
12317 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
12318 Handle<Map> new_map = Map::TransitionToPrototype(map, value, mode);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012319 DCHECK(new_map->prototype() == *value);
12320 JSObject::MigrateToMap(real_receiver, new_map);
12321
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012322 if (from_javascript && !dictionary_elements_in_chain &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012323 new_map->DictionaryElementsInPrototypeChainOnly()) {
12324 // If the prototype chain didn't previously have element callbacks, then
12325 // KeyedStoreICs need to be cleared to ensure any that involve this
12326 // map go generic.
12327 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
12328 }
Andrei Popescu402d9372010-02-26 13:31:12 +000012329
Steve Block44f0eee2011-05-26 01:26:41 +010012330 heap->ClearInstanceofCache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012331 DCHECK(size == object->Size());
Andrei Popescu402d9372010-02-26 13:31:12 +000012332 return value;
12333}
12334
12335
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012336void JSObject::EnsureCanContainElements(Handle<JSObject> object,
12337 Arguments* args,
12338 uint32_t first_arg,
12339 uint32_t arg_count,
12340 EnsureElementsMode mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012341 // Elements in |Arguments| are ordered backwards (because they're on the
12342 // stack), but the method that's called here iterates over them in forward
12343 // direction.
12344 return EnsureCanContainElements(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012345 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012346}
12347
12348
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012349MaybeHandle<AccessorPair> JSObject::GetOwnElementAccessorPair(
12350 Handle<JSObject> object,
12351 uint32_t index) {
12352 if (object->IsJSGlobalProxy()) {
12353 PrototypeIterator iter(object->GetIsolate(), object);
12354 if (iter.IsAtEnd()) return MaybeHandle<AccessorPair>();
12355 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
12356 return GetOwnElementAccessorPair(
12357 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
12358 }
12359
12360 // Check for lookup interceptor.
12361 if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>();
12362
12363 return object->GetElementsAccessor()->GetAccessorPair(object, object, index);
12364}
12365
12366
12367MaybeHandle<Object> JSObject::SetElementWithInterceptor(
12368 Handle<JSObject> object,
12369 uint32_t index,
12370 Handle<Object> value,
12371 PropertyAttributes attributes,
12372 StrictMode strict_mode,
12373 bool check_prototype,
12374 SetPropertyMode set_mode) {
12375 Isolate* isolate = object->GetIsolate();
12376
Steve Blocka7e24c12009-10-30 11:49:00 +000012377 // Make sure that the top context does not change when doing
12378 // callbacks or interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012379 AssertNoContextChange ncc(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012380
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012381 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +000012382 if (!interceptor->setter()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012383 v8::IndexedPropertySetterCallback setter =
12384 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +010012385 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012386 ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index));
12387 PropertyCallbackArguments args(isolate, interceptor->data(), *object,
12388 *object);
12389 v8::Handle<v8::Value> result =
12390 args.Call(setter, index, v8::Utils::ToLocal(value));
12391 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12392 if (!result.IsEmpty()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +000012393 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012394
12395 return SetElementWithoutInterceptor(object, index, value, attributes,
12396 strict_mode,
12397 check_prototype,
12398 set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000012399}
12400
12401
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012402MaybeHandle<Object> JSObject::GetElementWithCallback(
12403 Handle<JSObject> object,
12404 Handle<Object> receiver,
12405 Handle<Object> structure,
12406 uint32_t index,
12407 Handle<Object> holder) {
12408 Isolate* isolate = object->GetIsolate();
12409 DCHECK(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +010012410 // api style callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012411 if (structure->IsExecutableAccessorInfo()) {
12412 Handle<ExecutableAccessorInfo> data =
12413 Handle<ExecutableAccessorInfo>::cast(structure);
Leon Clarkef7060e22010-06-03 12:02:55 +010012414 Object* fun_obj = data->getter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012415 v8::AccessorNameGetterCallback call_fun =
12416 v8::ToCData<v8::AccessorNameGetterCallback>(fun_obj);
12417 if (call_fun == NULL) return isolate->factory()->undefined_value();
12418 Handle<JSObject> holder_handle = Handle<JSObject>::cast(holder);
Steve Block44f0eee2011-05-26 01:26:41 +010012419 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012420 Handle<String> key = isolate->factory()->NumberToString(number);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012421 LOG(isolate, ApiNamedPropertyAccess("load", *holder_handle, *key));
12422 PropertyCallbackArguments
12423 args(isolate, data->data(), *receiver, *holder_handle);
12424 v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key));
12425 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12426 if (result.IsEmpty()) return isolate->factory()->undefined_value();
12427 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12428 result_internal->VerifyApiCallResultType();
12429 // Rebox handle before return.
12430 return handle(*result_internal, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +010012431 }
12432
12433 // __defineGetter__ callback
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012434 if (structure->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012435 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
12436 isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012437 if (getter->IsSpecFunction()) {
12438 // TODO(rossberg): nicer would be to cast to some JSCallable here...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012439 return GetPropertyWithDefinedGetter(
12440 receiver, Handle<JSReceiver>::cast(getter));
Leon Clarkef7060e22010-06-03 12:02:55 +010012441 }
12442 // Getter is not a function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012443 return isolate->factory()->undefined_value();
12444 }
12445
12446 if (structure->IsDeclaredAccessorInfo()) {
12447 return GetDeclaredAccessorProperty(
12448 receiver, Handle<DeclaredAccessorInfo>::cast(structure), isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +010012449 }
12450
12451 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012452 return MaybeHandle<Object>();
Leon Clarkef7060e22010-06-03 12:02:55 +010012453}
12454
12455
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012456MaybeHandle<Object> JSObject::SetElementWithCallback(
12457 Handle<Object> object, Handle<Object> structure, uint32_t index,
12458 Handle<Object> value, Handle<JSObject> holder, StrictMode strict_mode) {
12459 Isolate* isolate = holder->GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +010012460
12461 // We should never get here to initialize a const with the hole
12462 // value since a const declaration would conflict with the setter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012463 DCHECK(!value->IsTheHole());
12464 DCHECK(!structure->IsForeign());
12465 if (structure->IsExecutableAccessorInfo()) {
Leon Clarkef7060e22010-06-03 12:02:55 +010012466 // api style callbacks
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012467 Handle<ExecutableAccessorInfo> data =
12468 Handle<ExecutableAccessorInfo>::cast(structure);
Leon Clarkef7060e22010-06-03 12:02:55 +010012469 Object* call_obj = data->setter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012470 v8::AccessorNameSetterCallback call_fun =
12471 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj);
Leon Clarkef7060e22010-06-03 12:02:55 +010012472 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +010012473 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12474 Handle<String> key(isolate->factory()->NumberToString(number));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012475 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *key));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012476 PropertyCallbackArguments
12477 args(isolate, data->data(), *object, *holder);
12478 args.Call(call_fun,
12479 v8::Utils::ToLocal(key),
12480 v8::Utils::ToLocal(value));
12481 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12482 return value;
Leon Clarkef7060e22010-06-03 12:02:55 +010012483 }
12484
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012485 if (structure->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012486 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012487 if (setter->IsSpecFunction()) {
12488 // TODO(rossberg): nicer would be to cast to some JSCallable here...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012489 return SetPropertyWithDefinedSetter(
12490 object, Handle<JSReceiver>::cast(setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +010012491 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012492 if (strict_mode == SLOPPY) return value;
Steve Block44f0eee2011-05-26 01:26:41 +010012493 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012494 Handle<Object> args[2] = { key, holder };
12495 THROW_NEW_ERROR(
12496 isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
12497 Object);
Leon Clarkef7060e22010-06-03 12:02:55 +010012498 }
12499 }
12500
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012501 // TODO(dcarney): Handle correctly.
12502 if (structure->IsDeclaredAccessorInfo()) return value;
12503
Leon Clarkef7060e22010-06-03 12:02:55 +010012504 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012505 return MaybeHandle<Object>();
Leon Clarkef7060e22010-06-03 12:02:55 +010012506}
12507
12508
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012509bool JSObject::HasFastArgumentsElements() {
12510 Heap* heap = GetHeap();
12511 if (!elements()->IsFixedArray()) return false;
12512 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012513 if (elements->map() != heap->sloppy_arguments_elements_map()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012514 return false;
12515 }
12516 FixedArray* arguments = FixedArray::cast(elements->get(1));
12517 return !arguments->IsDictionary();
12518}
12519
12520
12521bool JSObject::HasDictionaryArgumentsElements() {
12522 Heap* heap = GetHeap();
12523 if (!elements()->IsFixedArray()) return false;
12524 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012525 if (elements->map() != heap->sloppy_arguments_elements_map()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012526 return false;
12527 }
12528 FixedArray* arguments = FixedArray::cast(elements->get(1));
12529 return arguments->IsDictionary();
12530}
12531
12532
Steve Blocka7e24c12009-10-30 11:49:00 +000012533// Adding n elements in fast case is O(n*n).
12534// Note: revisit design to have dual undefined values to capture absent
12535// elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012536MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
12537 uint32_t index,
12538 Handle<Object> value,
12539 StrictMode strict_mode,
12540 bool check_prototype) {
12541 DCHECK(object->HasFastSmiOrObjectElements() ||
12542 object->HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000012543
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012544 Isolate* isolate = object->GetIsolate();
12545
12546 // Array optimizations rely on the prototype lookups of Array objects always
12547 // returning undefined. If there is a store to the initial prototype object,
12548 // make sure all of these optimizations are invalidated.
12549 if (isolate->is_initial_object_prototype(*object) ||
12550 isolate->is_initial_array_prototype(*object)) {
12551 object->map()->dependent_code()->DeoptimizeDependentCodeGroup(isolate,
12552 DependentCode::kElementsCantBeAddedGroup);
12553 }
12554
12555 Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
12556 if (backing_store->map() ==
12557 isolate->heap()->sloppy_arguments_elements_map()) {
12558 backing_store = handle(FixedArray::cast(backing_store->get(1)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012559 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012560 backing_store = EnsureWritableFastElements(object);
John Reck59135872010-11-02 12:39:01 -070012561 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012562 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000012563
Steve Block9fac8402011-05-12 15:51:54 +010012564 if (check_prototype &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012565 (index >= capacity || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +010012566 bool found;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012567 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12568 object, index, value, &found, strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +010012569 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000012570 }
12571
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012572 uint32_t new_capacity = capacity;
12573 // Check if the length property of this object needs to be updated.
12574 uint32_t array_length = 0;
12575 bool must_update_array_length = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012576 bool introduces_holes = true;
12577 if (object->IsJSArray()) {
12578 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
12579 introduces_holes = index > array_length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012580 if (index >= array_length) {
12581 must_update_array_length = true;
12582 array_length = index + 1;
12583 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012584 } else {
12585 introduces_holes = index >= capacity;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012586 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012587
12588 // If the array is growing, and it's not growth by a single element at the
12589 // end, make sure that the ElementsKind is HOLEY.
12590 ElementsKind elements_kind = object->GetElementsKind();
12591 if (introduces_holes &&
12592 IsFastElementsKind(elements_kind) &&
12593 !IsFastHoleyElementsKind(elements_kind)) {
12594 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12595 TransitionElementsKind(object, transitioned_kind);
12596 }
12597
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012598 // Check if the capacity of the backing store needs to be increased, or if
12599 // a transition to slow elements is necessary.
12600 if (index >= capacity) {
12601 bool convert_to_slow = true;
12602 if ((index - capacity) < kMaxGap) {
12603 new_capacity = NewElementsCapacity(index + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012604 DCHECK(new_capacity > index);
12605 if (!object->ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012606 convert_to_slow = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012607 }
12608 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012609 if (convert_to_slow) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012610 NormalizeElements(object);
12611 return SetDictionaryElement(object, index, value, NONE, strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012612 check_prototype);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012613 }
12614 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012615 // Convert to fast double elements if appropriate.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012616 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
12617 // Consider fixing the boilerplate as well if we have one.
12618 ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
12619 ? FAST_HOLEY_DOUBLE_ELEMENTS
12620 : FAST_DOUBLE_ELEMENTS;
12621
12622 UpdateAllocationSite(object, to_kind);
12623
12624 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length);
12625 FixedDoubleArray::cast(object->elements())->set(index, value->Number());
12626 JSObject::ValidateElements(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012627 return value;
12628 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012629 // Change elements kind from Smi-only to generic FAST if necessary.
12630 if (object->HasFastSmiElements() && !value->IsSmi()) {
12631 ElementsKind kind = object->HasFastHoleyElements()
12632 ? FAST_HOLEY_ELEMENTS
12633 : FAST_ELEMENTS;
12634
12635 UpdateAllocationSite(object, kind);
12636 Handle<Map> new_map = GetElementsTransitionMap(object, kind);
12637 JSObject::MigrateToMap(object, new_map);
12638 DCHECK(IsFastObjectElementsKind(object->GetElementsKind()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012639 }
12640 // Increase backing store capacity if that's been decided previously.
12641 if (new_capacity != capacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012642 SetFastElementsCapacitySmiMode smi_mode =
12643 value->IsSmi() && object->HasFastSmiElements()
12644 ? kAllowSmiElements
12645 : kDontAllowSmiElements;
12646 Handle<FixedArray> new_elements =
12647 SetFastElementsCapacityAndLength(object, new_capacity, array_length,
12648 smi_mode);
12649 new_elements->set(index, *value);
12650 JSObject::ValidateElements(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012651 return value;
12652 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012653
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012654 // Finally, set the new element and length.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012655 DCHECK(object->elements()->IsFixedArray());
12656 backing_store->set(index, *value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012657 if (must_update_array_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012658 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012659 }
12660 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012661}
12662
12663
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012664MaybeHandle<Object> JSObject::SetDictionaryElement(
12665 Handle<JSObject> object,
12666 uint32_t index,
12667 Handle<Object> value,
12668 PropertyAttributes attributes,
12669 StrictMode strict_mode,
12670 bool check_prototype,
12671 SetPropertyMode set_mode) {
12672 DCHECK(object->HasDictionaryElements() ||
12673 object->HasDictionaryArgumentsElements());
12674 Isolate* isolate = object->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012675
12676 // Insert element in the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012677 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012678 bool is_arguments =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012679 (elements->map() == isolate->heap()->sloppy_arguments_elements_map());
12680 Handle<SeededNumberDictionary> dictionary(is_arguments
12681 ? SeededNumberDictionary::cast(elements->get(1))
12682 : SeededNumberDictionary::cast(*elements));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012683
12684 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012685 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012686 Handle<Object> element(dictionary->ValueAt(entry), isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012687 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012688 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012689 return SetElementWithCallback(object, element, index, value, object,
12690 strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012691 } else {
12692 dictionary->UpdateMaxNumberKey(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012693 // If a value has not been initialized we allow writing to it even if it
12694 // is read-only (a declared const that has not been initialized). If a
12695 // value is being defined we skip attribute checks completely.
12696 if (set_mode == DEFINE_PROPERTY) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012697 details =
12698 PropertyDetails(attributes, FIELD, details.dictionary_index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012699 dictionary->DetailsAtPut(entry, details);
12700 } else if (details.IsReadOnly() && !element->IsTheHole()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012701 if (strict_mode == SLOPPY) {
12702 return isolate->factory()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012703 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012704 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012705 Handle<Object> args[2] = { number, object };
12706 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
12707 HandleVector(args, 2)),
12708 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012709 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012710 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012711 // Elements of the arguments object in slow mode might be slow aliases.
12712 if (is_arguments && element->IsAliasedArgumentsEntry()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012713 Handle<AliasedArgumentsEntry> entry =
12714 Handle<AliasedArgumentsEntry>::cast(element);
12715 Handle<Context> context(Context::cast(elements->get(0)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012716 int context_index = entry->aliased_context_slot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012717 DCHECK(!context->get(context_index)->IsTheHole());
12718 context->set(context_index, *value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012719 // For elements that are still writable we keep slow aliasing.
12720 if (!details.IsReadOnly()) value = element;
12721 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012722 dictionary->ValueAtPut(entry, *value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012723 }
12724 } else {
12725 // Index not already used. Look for an accessor in the prototype chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012726 // Can cause GC!
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012727 if (check_prototype) {
12728 bool found;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012729 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12730 object, index, value, &found, strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012731 if (found) return result;
12732 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012733
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012734 // When we set the is_extensible flag to false we always force the
12735 // element into dictionary mode (and force them to stay there).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012736 if (!object->map()->is_extensible()) {
12737 if (strict_mode == SLOPPY) {
12738 return isolate->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012739 } else {
12740 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12741 Handle<String> name = isolate->factory()->NumberToString(number);
12742 Handle<Object> args[1] = { name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012743 THROW_NEW_ERROR(isolate, NewTypeError("object_not_extensible",
12744 HandleVector(args, 1)),
12745 Object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012746 }
12747 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012748
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012749 PropertyDetails details(attributes, FIELD, 0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012750 Handle<SeededNumberDictionary> new_dictionary =
12751 SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
12752 details);
12753 if (*dictionary != *new_dictionary) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012754 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012755 elements->set(1, *new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012756 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012757 object->set_elements(*new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012758 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012759 dictionary = new_dictionary;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012760 }
12761 }
12762
12763 // Update the array length if this JSObject is an array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012764 if (object->IsJSArray()) {
12765 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index,
12766 value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012767 }
12768
12769 // Attempt to put this object back in fast case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012770 if (object->ShouldConvertToFastElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012771 uint32_t new_length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012772 if (object->IsJSArray()) {
12773 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012774 } else {
12775 new_length = dictionary->max_number_key() + 1;
12776 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012777 bool has_smi_only_elements = false;
12778 bool should_convert_to_fast_double_elements =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012779 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
12780 SetFastElementsCapacitySmiMode smi_mode =
12781 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements;
12782
12783 if (should_convert_to_fast_double_elements) {
12784 SetFastDoubleElementsCapacityAndLength(object, new_length, new_length);
12785 } else {
12786 SetFastElementsCapacityAndLength(object, new_length, new_length,
12787 smi_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012788 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012789 JSObject::ValidateElements(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012790#ifdef DEBUG
12791 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012792 OFStream os(stdout);
12793 os << "Object elements are fast case again:\n";
12794 object->Print(os);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012795 }
12796#endif
12797 }
12798 return value;
12799}
12800
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012801MaybeHandle<Object> JSObject::SetFastDoubleElement(
12802 Handle<JSObject> object,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012803 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012804 Handle<Object> value,
12805 StrictMode strict_mode,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012806 bool check_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012807 DCHECK(object->HasFastDoubleElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012808
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012809 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012810 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012811
12812 // If storing to an element that isn't in the array, pass the store request
12813 // up the prototype chain before storing in the receiver's elements.
12814 if (check_prototype &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012815 (index >= elms_length ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012816 Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012817 bool found;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012818 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12819 object, index, value, &found, strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012820 if (found) return result;
12821 }
12822
12823 // If the value object is not a heap number, switch to fast elements and try
12824 // again.
12825 bool value_is_smi = value->IsSmi();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012826 bool introduces_holes = true;
12827 uint32_t length = elms_length;
12828 if (object->IsJSArray()) {
12829 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length));
12830 introduces_holes = index > length;
12831 } else {
12832 introduces_holes = index >= elms_length;
12833 }
12834
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012835 if (!value->IsNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012836 SetFastElementsCapacityAndLength(object, elms_length, length,
12837 kDontAllowSmiElements);
12838 Handle<Object> result;
12839 ASSIGN_RETURN_ON_EXCEPTION(
12840 object->GetIsolate(), result,
12841 SetFastElement(object, index, value, strict_mode, check_prototype),
12842 Object);
12843 JSObject::ValidateElements(object);
12844 return result;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012845 }
12846
12847 double double_value = value_is_smi
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012848 ? static_cast<double>(Handle<Smi>::cast(value)->value())
12849 : Handle<HeapNumber>::cast(value)->value();
12850
12851 // If the array is growing, and it's not growth by a single element at the
12852 // end, make sure that the ElementsKind is HOLEY.
12853 ElementsKind elements_kind = object->GetElementsKind();
12854 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
12855 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12856 TransitionElementsKind(object, transitioned_kind);
12857 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012858
12859 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +000012860 if (index < elms_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012861 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012862 elms->set(index, double_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012863 if (object->IsJSArray()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012864 // Update the length of the array if needed.
12865 uint32_t array_length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012866 CHECK(
12867 Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +000012868 if (index >= array_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012869 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +000012870 }
12871 }
12872 return value;
12873 }
12874
12875 // Allow gap in fast case.
12876 if ((index - elms_length) < kMaxGap) {
12877 // Try allocating extra space.
12878 int new_capacity = NewElementsCapacity(index+1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012879 if (!object->ShouldConvertToSlowElements(new_capacity)) {
12880 DCHECK(static_cast<uint32_t>(new_capacity) > index);
12881 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1);
12882 FixedDoubleArray::cast(object->elements())->set(index, double_value);
12883 JSObject::ValidateElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000012884 return value;
12885 }
12886 }
12887
12888 // Otherwise default to slow case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012889 DCHECK(object->HasFastDoubleElements());
12890 DCHECK(object->map()->has_fast_double_elements());
12891 DCHECK(object->elements()->IsFixedDoubleArray() ||
12892 object->elements()->length() == 0);
12893
12894 NormalizeElements(object);
12895 DCHECK(object->HasDictionaryElements());
12896 return SetElement(object, index, value, NONE, strict_mode, check_prototype);
12897}
12898
12899
12900MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
12901 uint32_t index,
12902 Handle<Object> value,
12903 PropertyAttributes attributes,
12904 StrictMode strict_mode) {
12905 if (object->IsJSProxy()) {
12906 return JSProxy::SetElementWithHandler(
12907 Handle<JSProxy>::cast(object), object, index, value, strict_mode);
John Reck59135872010-11-02 12:39:01 -070012908 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012909 return JSObject::SetElement(
12910 Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012911}
12912
12913
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012914MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
12915 uint32_t index,
12916 Handle<Object> value,
12917 StrictMode strict_mode) {
12918 DCHECK(!object->HasExternalArrayElements());
12919 return JSObject::SetElement(object, index, value, NONE, strict_mode, false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012920}
12921
12922
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012923MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
12924 uint32_t index,
12925 Handle<Object> value,
12926 PropertyAttributes attributes,
12927 StrictMode strict_mode,
12928 bool check_prototype,
12929 SetPropertyMode set_mode) {
12930 Isolate* isolate = object->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012931
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012932 if (object->HasExternalArrayElements() ||
12933 object->HasFixedTypedArrayElements()) {
12934 if (!value->IsNumber() && !value->IsUndefined()) {
12935 ASSIGN_RETURN_ON_EXCEPTION(
12936 isolate, value,
12937 Execution::ToNumber(isolate, value), Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012938 }
12939 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000012940
Steve Blocka7e24c12009-10-30 11:49:00 +000012941 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012942 if (object->IsAccessCheckNeeded()) {
12943 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_SET)) {
12944 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
12945 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12946 return value;
Ben Murdoch8b112d22011-06-08 16:22:53 +010012947 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012948 }
12949
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012950 if (object->IsJSGlobalProxy()) {
12951 PrototypeIterator iter(isolate, object);
12952 if (iter.IsAtEnd()) return value;
12953 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
12954 return SetElement(
12955 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
12956 value, attributes, strict_mode, check_prototype, set_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012957 }
12958
12959 // Don't allow element properties to be redefined for external arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012960 if ((object->HasExternalArrayElements() ||
12961 object->HasFixedTypedArrayElements()) &&
12962 set_mode == DEFINE_PROPERTY) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012963 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012964 Handle<Object> args[] = { object, number };
12965 THROW_NEW_ERROR(isolate, NewTypeError("redef_external_array_element",
12966 HandleVector(args, arraysize(args))),
12967 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012968 }
12969
12970 // Normalize the elements to enable attributes on the property.
12971 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012972 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012973 // Make sure that we never go back to fast case.
12974 dictionary->set_requires_slow_elements();
Steve Blocka7e24c12009-10-30 11:49:00 +000012975 }
12976
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012977 if (!object->map()->is_observed()) {
12978 return object->HasIndexedInterceptor()
12979 ? SetElementWithInterceptor(object, index, value, attributes,
12980 strict_mode, check_prototype, set_mode)
12981 : SetElementWithoutInterceptor(object, index, value, attributes,
12982 strict_mode, check_prototype, set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000012983 }
12984
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012985 Maybe<PropertyAttributes> maybe =
12986 JSReceiver::GetOwnElementAttribute(object, index);
12987 if (!maybe.has_value) return MaybeHandle<Object>();
12988 PropertyAttributes old_attributes = maybe.value;
12989
12990 Handle<Object> old_value = isolate->factory()->the_hole_value();
12991 Handle<Object> old_length_handle;
12992 Handle<Object> new_length_handle;
12993
12994 if (old_attributes != ABSENT) {
12995 if (GetOwnElementAccessorPair(object, index).is_null()) {
12996 old_value = Object::GetElement(isolate, object, index).ToHandleChecked();
12997 }
12998 } else if (object->IsJSArray()) {
12999 // Store old array length in case adding an element grows the array.
13000 old_length_handle = handle(Handle<JSArray>::cast(object)->length(),
13001 isolate);
13002 }
13003
13004 // Check for lookup interceptor
13005 Handle<Object> result;
13006 ASSIGN_RETURN_ON_EXCEPTION(
13007 isolate, result,
13008 object->HasIndexedInterceptor()
13009 ? SetElementWithInterceptor(
13010 object, index, value, attributes,
13011 strict_mode, check_prototype, set_mode)
13012 : SetElementWithoutInterceptor(
13013 object, index, value, attributes,
13014 strict_mode, check_prototype, set_mode),
13015 Object);
13016
13017 Handle<String> name = isolate->factory()->Uint32ToString(index);
13018 maybe = GetOwnElementAttribute(object, index);
13019 if (!maybe.has_value) return MaybeHandle<Object>();
13020 PropertyAttributes new_attributes = maybe.value;
13021
13022 if (old_attributes == ABSENT) {
13023 if (object->IsJSArray() &&
13024 !old_length_handle->SameValue(
13025 Handle<JSArray>::cast(object)->length())) {
13026 new_length_handle = handle(Handle<JSArray>::cast(object)->length(),
13027 isolate);
13028 uint32_t old_length = 0;
13029 uint32_t new_length = 0;
13030 CHECK(old_length_handle->ToArrayIndex(&old_length));
13031 CHECK(new_length_handle->ToArrayIndex(&new_length));
13032
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013033 RETURN_ON_EXCEPTION(
13034 isolate, BeginPerformSplice(Handle<JSArray>::cast(object)), Object);
13035 RETURN_ON_EXCEPTION(
13036 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
13037 RETURN_ON_EXCEPTION(
13038 isolate, EnqueueChangeRecord(object, "update",
13039 isolate->factory()->length_string(),
13040 old_length_handle),
13041 Object);
13042 RETURN_ON_EXCEPTION(
13043 isolate, EndPerformSplice(Handle<JSArray>::cast(object)), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013044 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013045 RETURN_ON_EXCEPTION(
13046 isolate,
13047 EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length,
13048 deleted, new_length - old_length),
13049 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013050 } else {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013051 RETURN_ON_EXCEPTION(
13052 isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013053 }
13054 } else if (old_value->IsTheHole()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013055 RETURN_ON_EXCEPTION(
13056 isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
13057 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013058 } else {
13059 Handle<Object> new_value =
13060 Object::GetElement(isolate, object, index).ToHandleChecked();
13061 bool value_changed = !old_value->SameValue(*new_value);
13062 if (old_attributes != new_attributes) {
13063 if (!value_changed) old_value = isolate->factory()->the_hole_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013064 RETURN_ON_EXCEPTION(
13065 isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
13066 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013067 } else if (value_changed) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013068 RETURN_ON_EXCEPTION(
13069 isolate, EnqueueChangeRecord(object, "update", name, old_value),
13070 Object);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013071 }
13072 }
13073
13074 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000013075}
13076
13077
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013078MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
13079 Handle<JSObject> object,
13080 uint32_t index,
13081 Handle<Object> value,
13082 PropertyAttributes attributes,
13083 StrictMode strict_mode,
13084 bool check_prototype,
13085 SetPropertyMode set_mode) {
13086 DCHECK(object->HasDictionaryElements() ||
13087 object->HasDictionaryArgumentsElements() ||
13088 (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
13089 Isolate* isolate = object->GetIsolate();
13090 if (FLAG_trace_external_array_abuse &&
13091 IsExternalArrayElementsKind(object->GetElementsKind())) {
13092 CheckArrayAbuse(object, "external elements write", index);
13093 }
13094 if (FLAG_trace_js_array_abuse &&
13095 !IsExternalArrayElementsKind(object->GetElementsKind())) {
13096 if (object->IsJSArray()) {
13097 CheckArrayAbuse(object, "elements write", index, true);
13098 }
13099 }
13100 if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength(
13101 Handle<JSArray>::cast(object), index)) {
13102 if (strict_mode == SLOPPY) {
13103 return value;
13104 } else {
13105 return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object));
13106 }
13107 }
13108 switch (object->GetElementsKind()) {
13109 case FAST_SMI_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000013110 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013111 case FAST_HOLEY_SMI_ELEMENTS:
13112 case FAST_HOLEY_ELEMENTS:
13113 return SetFastElement(object, index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013114 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013115 case FAST_HOLEY_DOUBLE_ELEMENTS:
13116 return SetFastDoubleElement(object, index, value, strict_mode,
13117 check_prototype);
13118
13119#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13120 case EXTERNAL_##TYPE##_ELEMENTS: { \
13121 Handle<External##Type##Array> array( \
13122 External##Type##Array::cast(object->elements())); \
13123 return External##Type##Array::SetValue(array, index, value); \
13124 } \
13125 case TYPE##_ELEMENTS: { \
13126 Handle<Fixed##Type##Array> array( \
13127 Fixed##Type##Array::cast(object->elements())); \
13128 return Fixed##Type##Array::SetValue(array, index, value); \
Steve Blocka7e24c12009-10-30 11:49:00 +000013129 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013130
13131 TYPED_ARRAYS(TYPED_ARRAY_CASE)
13132
13133#undef TYPED_ARRAY_CASE
13134
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013135 case DICTIONARY_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013136 return SetDictionaryElement(object, index, value, attributes, strict_mode,
13137 check_prototype,
13138 set_mode);
13139 case SLOPPY_ARGUMENTS_ELEMENTS: {
13140 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013141 uint32_t length = parameter_map->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013142 Handle<Object> probe = index < length - 2 ?
13143 Handle<Object>(parameter_map->get(index + 2), isolate) :
13144 Handle<Object>();
13145 if (!probe.is_null() && !probe->IsTheHole()) {
13146 Handle<Context> context(Context::cast(parameter_map->get(0)));
13147 int context_index = Handle<Smi>::cast(probe)->value();
13148 DCHECK(!context->get(context_index)->IsTheHole());
13149 context->set(context_index, *value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013150 // Redefining attributes of an aliased element destroys fast aliasing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013151 if (set_mode == SET_PROPERTY || attributes == NONE) return value;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013152 parameter_map->set_the_hole(index + 2);
13153 // For elements that are still writable we re-establish slow aliasing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013154 if ((attributes & READ_ONLY) == 0) {
13155 value = Handle<Object>::cast(
13156 isolate->factory()->NewAliasedArgumentsEntry(context_index));
Ben Murdoch85b71792012-04-11 18:30:58 +010013157 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010013158 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013159 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013160 if (arguments->IsDictionary()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013161 return SetDictionaryElement(object, index, value, attributes,
13162 strict_mode,
13163 check_prototype,
13164 set_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013165 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013166 return SetFastElement(object, index, value, strict_mode,
13167 check_prototype);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013168 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013169 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013170 }
13171 // All possible cases have been handled above. Add a return to avoid the
13172 // complaints from the compiler.
13173 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013174 return isolate->factory()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000013175}
13176
13177
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013178const double AllocationSite::kPretenureRatio = 0.85;
13179
13180
13181void AllocationSite::ResetPretenureDecision() {
13182 set_pretenure_decision(kUndecided);
13183 set_memento_found_count(0);
13184 set_memento_create_count(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013185}
13186
13187
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013188PretenureFlag AllocationSite::GetPretenureMode() {
13189 PretenureDecision mode = pretenure_decision();
13190 // Zombie objects "decide" to be untenured.
13191 return mode == kTenure ? TENURED : NOT_TENURED;
13192}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013193
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013194
13195bool AllocationSite::IsNestedSite() {
13196 DCHECK(FLAG_trace_track_allocation_sites);
13197 Object* current = GetHeap()->allocation_sites_list();
13198 while (current->IsAllocationSite()) {
13199 AllocationSite* current_site = AllocationSite::cast(current);
13200 if (current_site->nested_site() == this) {
13201 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013202 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013203 current = current_site->weak_next();
13204 }
13205 return false;
13206}
13207
13208
13209void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
13210 ElementsKind to_kind) {
13211 Isolate* isolate = site->GetIsolate();
13212
13213 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
13214 Handle<JSArray> transition_info =
13215 handle(JSArray::cast(site->transition_info()));
13216 ElementsKind kind = transition_info->GetElementsKind();
13217 // if kind is holey ensure that to_kind is as well.
13218 if (IsHoleyElementsKind(kind)) {
13219 to_kind = GetHoleyElementsKind(to_kind);
13220 }
13221 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
13222 // If the array is huge, it's not likely to be defined in a local
13223 // function, so we shouldn't make new instances of it very often.
13224 uint32_t length = 0;
13225 CHECK(transition_info->length()->ToArrayIndex(&length));
13226 if (length <= kMaximumArrayBytesToPretransition) {
13227 if (FLAG_trace_track_allocation_sites) {
13228 bool is_nested = site->IsNestedSite();
13229 PrintF(
13230 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
13231 reinterpret_cast<void*>(*site),
13232 is_nested ? "(nested)" : "",
13233 ElementsKindToString(kind),
13234 ElementsKindToString(to_kind));
13235 }
13236 JSObject::TransitionElementsKind(transition_info, to_kind);
13237 site->dependent_code()->DeoptimizeDependentCodeGroup(
13238 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
13239 }
13240 }
13241 } else {
13242 ElementsKind kind = site->GetElementsKind();
13243 // if kind is holey ensure that to_kind is as well.
13244 if (IsHoleyElementsKind(kind)) {
13245 to_kind = GetHoleyElementsKind(to_kind);
13246 }
13247 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
13248 if (FLAG_trace_track_allocation_sites) {
13249 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
13250 reinterpret_cast<void*>(*site),
13251 ElementsKindToString(kind),
13252 ElementsKindToString(to_kind));
13253 }
13254 site->SetElementsKind(to_kind);
13255 site->dependent_code()->DeoptimizeDependentCodeGroup(
13256 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
13257 }
13258 }
13259}
13260
13261
13262// static
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013263void AllocationSite::RegisterForDeoptOnTenureChange(Handle<AllocationSite> site,
13264 CompilationInfo* info) {
13265 AddDependentCompilationInfo(
13266 site, DependentCode::kAllocationSiteTenuringChangedGroup, info);
13267}
13268
13269
13270// static
13271void AllocationSite::RegisterForDeoptOnTransitionChange(
13272 Handle<AllocationSite> site, CompilationInfo* info) {
13273 // Do nothing if the object doesn't have any useful element transitions left.
13274 ElementsKind kind =
13275 site->SitePointsToLiteral()
13276 ? JSObject::cast(site->transition_info())->GetElementsKind()
13277 : site->GetElementsKind();
13278 if (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE) {
13279 AddDependentCompilationInfo(
13280 site, DependentCode::kAllocationSiteTransitionChangedGroup, info);
13281 }
13282}
13283
13284
13285// static
13286void AllocationSite::AddDependentCompilationInfo(
13287 Handle<AllocationSite> site, DependentCode::DependencyGroup group,
13288 CompilationInfo* info) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013289 Handle<DependentCode> dep(site->dependent_code());
13290 Handle<DependentCode> codes =
13291 DependentCode::Insert(dep, group, info->object_wrapper());
13292 if (*codes != site->dependent_code()) site->set_dependent_code(*codes);
13293 info->dependencies(group)->Add(Handle<HeapObject>(*site), info->zone());
13294}
13295
13296
13297const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
13298 switch (decision) {
13299 case kUndecided: return "undecided";
13300 case kDontTenure: return "don't tenure";
13301 case kMaybeTenure: return "maybe tenure";
13302 case kTenure: return "tenure";
13303 case kZombie: return "zombie";
13304 default: UNREACHABLE();
13305 }
13306 return NULL;
13307}
13308
13309
13310void JSObject::UpdateAllocationSite(Handle<JSObject> object,
13311 ElementsKind to_kind) {
13312 if (!object->IsJSArray()) return;
13313
13314 Heap* heap = object->GetHeap();
13315 if (!heap->InNewSpace(*object)) return;
13316
13317 Handle<AllocationSite> site;
13318 {
13319 DisallowHeapAllocation no_allocation;
13320
13321 AllocationMemento* memento = heap->FindAllocationMemento(*object);
13322 if (memento == NULL) return;
13323
13324 // Walk through to the Allocation Site
13325 site = handle(memento->GetAllocationSite());
13326 }
13327 AllocationSite::DigestTransitionFeedback(site, to_kind);
13328}
13329
13330
13331void JSObject::TransitionElementsKind(Handle<JSObject> object,
13332 ElementsKind to_kind) {
13333 ElementsKind from_kind = object->map()->elements_kind();
13334
13335 if (IsFastHoleyElementsKind(from_kind)) {
13336 to_kind = GetHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013337 }
13338
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013339 if (from_kind == to_kind) return;
13340 // Don't update the site if to_kind isn't fast
13341 if (IsFastElementsKind(to_kind)) {
13342 UpdateAllocationSite(object, to_kind);
13343 }
13344
13345 Isolate* isolate = object->GetIsolate();
13346 if (object->elements() == isolate->heap()->empty_fixed_array() ||
13347 (IsFastSmiOrObjectElementsKind(from_kind) &&
13348 IsFastSmiOrObjectElementsKind(to_kind)) ||
13349 (from_kind == FAST_DOUBLE_ELEMENTS &&
13350 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
13351 DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
13352 // No change is needed to the elements() buffer, the transition
13353 // only requires a map change.
13354 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
13355 MigrateToMap(object, new_map);
13356 if (FLAG_trace_elements_transitions) {
13357 Handle<FixedArrayBase> elms(object->elements());
13358 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
13359 }
13360 return;
13361 }
13362
13363 Handle<FixedArrayBase> elms(object->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013364 uint32_t capacity = static_cast<uint32_t>(elms->length());
13365 uint32_t length = capacity;
13366
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013367 if (object->IsJSArray()) {
13368 Object* raw_length = Handle<JSArray>::cast(object)->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013369 if (raw_length->IsUndefined()) {
13370 // If length is undefined, then JSArray is being initialized and has no
13371 // elements, assume a length of zero.
13372 length = 0;
13373 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013374 CHECK(raw_length->ToArrayIndex(&length));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013375 }
13376 }
13377
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013378 if (IsFastSmiElementsKind(from_kind) &&
13379 IsFastDoubleElementsKind(to_kind)) {
13380 SetFastDoubleElementsCapacityAndLength(object, capacity, length);
13381 JSObject::ValidateElements(object);
13382 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013383 }
13384
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013385 if (IsFastDoubleElementsKind(from_kind) &&
13386 IsFastObjectElementsKind(to_kind)) {
13387 SetFastElementsCapacityAndLength(object, capacity, length,
13388 kDontAllowSmiElements);
13389 JSObject::ValidateElements(object);
13390 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013391 }
13392
13393 // This method should never be called for any other case than the ones
13394 // handled above.
13395 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013396}
13397
13398
13399// static
13400bool Map::IsValidElementsTransition(ElementsKind from_kind,
13401 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013402 // Transitions can't go backwards.
13403 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
13404 return false;
13405 }
13406
13407 // Transitions from HOLEY -> PACKED are not allowed.
13408 return !IsFastHoleyElementsKind(from_kind) ||
13409 IsFastHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013410}
13411
13412
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013413void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
13414 uint32_t index,
13415 Handle<Object> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013416 uint32_t old_len = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013417 CHECK(array->length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +000013418 // Check to see if we need to update the length. For now, we make
13419 // sure that the length stays within 32-bits (unsigned).
13420 if (index >= old_len && index != 0xffffffff) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013421 Handle<Object> len = array->GetIsolate()->factory()->NewNumber(
13422 static_cast<double>(index) + 1);
13423 array->set_length(*len);
Steve Blocka7e24c12009-10-30 11:49:00 +000013424 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013425}
13426
13427
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013428bool JSArray::IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
13429 Isolate* isolate = jsarray_map->GetIsolate();
13430 DCHECK(!jsarray_map->is_dictionary_map());
13431 LookupResult lookup(isolate);
13432 Handle<Name> length_string = isolate->factory()->length_string();
13433 jsarray_map->LookupDescriptor(NULL, *length_string, &lookup);
13434 return lookup.IsReadOnly();
13435}
13436
13437
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013438bool JSArray::HasReadOnlyLength(Handle<JSArray> array) {
13439 LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
13440 LookupIterator::OWN_SKIP_INTERCEPTOR);
13441 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
13442 CHECK(it.IsFound());
13443 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
13444 return it.IsReadOnly();
13445}
13446
13447
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013448bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
13449 uint32_t index) {
13450 uint32_t length = 0;
13451 CHECK(array->length()->ToArrayIndex(&length));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013452 if (length <= index) return HasReadOnlyLength(array);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013453 return false;
13454}
13455
13456
13457MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) {
13458 Isolate* isolate = array->GetIsolate();
13459 Handle<Name> length = isolate->factory()->length_string();
13460 Handle<Object> args[2] = { length, array };
13461 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
13462 HandleVector(args, arraysize(args))),
13463 Object);
13464}
13465
13466
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013467MaybeHandle<Object> JSObject::GetElementWithInterceptor(Handle<JSObject> object,
13468 Handle<Object> receiver,
13469 uint32_t index,
13470 bool check_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013471 Isolate* isolate = object->GetIsolate();
13472
Steve Blocka7e24c12009-10-30 11:49:00 +000013473 // Make sure that the top context does not change when doing
13474 // callbacks or interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013475 AssertNoContextChange ncc(isolate);
13476
13477 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013478 if (!interceptor->getter()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013479 v8::IndexedPropertyGetterCallback getter =
13480 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +010013481 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013482 ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index));
13483 PropertyCallbackArguments
13484 args(isolate, interceptor->data(), *receiver, *object);
13485 v8::Handle<v8::Value> result = args.Call(getter, index);
13486 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
13487 if (!result.IsEmpty()) {
13488 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13489 result_internal->VerifyApiCallResultType();
13490 // Rebox handle before return.
13491 return handle(*result_internal, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013492 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013493 }
13494
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013495 if (!check_prototype) return MaybeHandle<Object>();
13496
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013497 ElementsAccessor* handler = object->GetElementsAccessor();
13498 Handle<Object> result;
13499 ASSIGN_RETURN_ON_EXCEPTION(
13500 isolate, result, handler->Get(receiver, object, index),
13501 Object);
13502 if (!result->IsTheHole()) return result;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013503
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013504 PrototypeIterator iter(isolate, object);
13505 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
13506 return Object::GetElementWithReceiver(
13507 isolate, PrototypeIterator::GetCurrent(iter), receiver, index);
Steve Blocka7e24c12009-10-30 11:49:00 +000013508}
13509
13510
13511bool JSObject::HasDenseElements() {
13512 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013513 int used = 0;
13514 GetElementsCapacityAndUsage(&capacity, &used);
13515 return (capacity == 0) || (used > (capacity / 2));
13516}
13517
13518
13519void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
13520 *capacity = 0;
13521 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000013522
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013523 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
13524 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000013525 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013526 case SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013527 backing_store_base =
13528 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
13529 backing_store = FixedArray::cast(backing_store_base);
13530 if (backing_store->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000013531 SeededNumberDictionary* dictionary =
13532 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013533 *capacity = dictionary->Capacity();
13534 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013535 break;
13536 }
13537 // Fall through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013538 case FAST_SMI_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013539 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013540 if (IsJSArray()) {
13541 *capacity = backing_store_base->length();
13542 *used = Smi::cast(JSArray::cast(this)->length())->value();
13543 break;
13544 }
13545 // Fall through if packing is not guaranteed.
13546 case FAST_HOLEY_SMI_ELEMENTS:
13547 case FAST_HOLEY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013548 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013549 *capacity = backing_store->length();
13550 for (int i = 0; i < *capacity; ++i) {
13551 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013552 }
13553 break;
13554 case DICTIONARY_ELEMENTS: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013555 SeededNumberDictionary* dictionary = element_dictionary();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013556 *capacity = dictionary->Capacity();
13557 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013558 break;
13559 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013560 case FAST_DOUBLE_ELEMENTS:
13561 if (IsJSArray()) {
13562 *capacity = backing_store_base->length();
13563 *used = Smi::cast(JSArray::cast(this)->length())->value();
13564 break;
13565 }
13566 // Fall through if packing is not guaranteed.
13567 case FAST_HOLEY_DOUBLE_ELEMENTS: {
13568 *capacity = elements()->length();
13569 if (*capacity == 0) break;
13570 FixedDoubleArray * elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013571 for (int i = 0; i < *capacity; i++) {
13572 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +000013573 }
13574 break;
13575 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013576
13577#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13578 case EXTERNAL_##TYPE##_ELEMENTS: \
13579 case TYPE##_ELEMENTS: \
13580
13581 TYPED_ARRAYS(TYPED_ARRAY_CASE)
13582#undef TYPED_ARRAY_CASE
13583 {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013584 // External arrays are considered 100% used.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013585 FixedArrayBase* external_array = FixedArrayBase::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013586 *capacity = external_array->length();
13587 *used = external_array->length();
13588 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013589 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013590 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013591}
13592
13593
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013594bool JSObject::WouldConvertToSlowElements(Handle<Object> key) {
13595 uint32_t index;
13596 if (HasFastElements() && key->ToArrayIndex(&index)) {
13597 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
13598 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
13599 if (index >= capacity) {
13600 if ((index - capacity) >= kMaxGap) return true;
13601 uint32_t new_capacity = NewElementsCapacity(index + 1);
13602 return ShouldConvertToSlowElements(new_capacity);
13603 }
13604 }
13605 return false;
13606}
13607
13608
Steve Blocka7e24c12009-10-30 11:49:00 +000013609bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013610 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
13611 kMaxUncheckedFastElementsLength);
13612 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
13613 (new_capacity <= kMaxUncheckedFastElementsLength &&
13614 GetHeap()->InNewSpace(this))) {
13615 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013616 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013617 // If the fast-case backing storage takes up roughly three times as
13618 // much space (in machine words) as a dictionary backing storage
13619 // would, the object should have slow elements.
13620 int old_capacity = 0;
13621 int used_elements = 0;
13622 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +000013623 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
13624 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013625 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +000013626}
13627
13628
13629bool JSObject::ShouldConvertToFastElements() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013630 DCHECK(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000013631 // If the elements are sparse, we should not go back to fast case.
13632 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000013633 // An object requiring access checks is never allowed to have fast
13634 // elements. If it had fast elements we would skip security checks.
13635 if (IsAccessCheckNeeded()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013636 // Observed objects may not go to fast mode because they rely on map checks,
13637 // and for fast element accesses we sometimes check element kinds only.
13638 if (map()->is_observed()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013639
13640 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +000013641 SeededNumberDictionary* dictionary = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013642 if (elements->map() == GetHeap()->sloppy_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000013643 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013644 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +000013645 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013646 }
13647 // If an element has been added at a very high index in the elements
13648 // dictionary, we cannot go back to fast case.
13649 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000013650 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013651 // space (in machine words) as a fast-case backing storage would,
13652 // the object should have fast elements.
13653 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000013654 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013655 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000013656 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013657 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +000013658 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013659 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
Ben Murdochc7cc0282012-03-05 14:35:55 +000013660 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013661 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +000013662}
13663
13664
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013665bool JSObject::ShouldConvertToFastDoubleElements(
13666 bool* has_smi_only_elements) {
13667 *has_smi_only_elements = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013668 if (HasSloppyArgumentsElements()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013669 if (FLAG_unbox_double_arrays) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013670 DCHECK(HasDictionaryElements());
13671 SeededNumberDictionary* dictionary = element_dictionary();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013672 bool found_double = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013673 for (int i = 0; i < dictionary->Capacity(); i++) {
13674 Object* key = dictionary->KeyAt(i);
13675 if (key->IsNumber()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013676 Object* value = dictionary->ValueAt(i);
13677 if (!value->IsNumber()) return false;
13678 if (!value->IsSmi()) {
13679 found_double = true;
13680 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013681 }
13682 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013683 *has_smi_only_elements = !found_double;
13684 return found_double;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013685 } else {
13686 return false;
13687 }
13688}
13689
13690
Steve Blocka7e24c12009-10-30 11:49:00 +000013691// Certain compilers request function template instantiation when they
13692// see the definition of the other template functions in the
13693// class. This requires us to have the template functions put
13694// together, so even though this function belongs in objects-debug.cc,
13695// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013696#ifdef OBJECT_PRINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013697template <typename Derived, typename Shape, typename Key>
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013698void Dictionary<Derived, Shape, Key>::Print(std::ostream& os) { // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013699 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000013700 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013701 Object* k = DerivedHashTable::KeyAt(i);
13702 if (DerivedHashTable::IsKey(k)) {
13703 os << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +000013704 if (k->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013705 String::cast(k)->StringPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000013706 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013707 os << Brief(k);
Steve Blocka7e24c12009-10-30 11:49:00 +000013708 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013709 os << ": " << Brief(ValueAt(i)) << " " << DetailsAt(i) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000013710 }
13711 }
13712}
13713#endif
13714
13715
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013716template<typename Derived, typename Shape, typename Key>
13717void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013718 int pos = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013719 int capacity = DerivedHashTable::Capacity();
13720 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000013721 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000013722 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013723 Object* k = Dictionary::KeyAt(i);
13724 if (Dictionary::IsKey(k)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013725 elements->set(pos++, ValueAt(i), mode);
13726 }
13727 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013728 DCHECK(pos == elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000013729}
13730
13731
13732InterceptorInfo* JSObject::GetNamedInterceptor() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013733 DCHECK(map()->has_named_interceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +000013734 JSFunction* constructor = JSFunction::cast(map()->constructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013735 DCHECK(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000013736 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010013737 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000013738 return InterceptorInfo::cast(result);
13739}
13740
13741
13742InterceptorInfo* JSObject::GetIndexedInterceptor() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013743 DCHECK(map()->has_indexed_interceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +000013744 JSFunction* constructor = JSFunction::cast(map()->constructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013745 DCHECK(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000013746 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010013747 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000013748 return InterceptorInfo::cast(result);
13749}
13750
13751
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013752MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(
13753 Handle<JSObject> holder,
13754 Handle<Object> receiver,
13755 Handle<Name> name) {
13756 Isolate* isolate = holder->GetIsolate();
13757
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013758 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013759 if (interceptor->getter()->IsUndefined()) return MaybeHandle<Object>();
13760
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013761 if (name->IsSymbol() && !interceptor->can_intercept_symbols()) {
13762 return MaybeHandle<Object>();
13763 }
13764
13765 v8::GenericNamedPropertyGetterCallback getter =
13766 v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
13767 interceptor->getter());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013768 LOG(isolate,
13769 ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
13770 PropertyCallbackArguments
13771 args(isolate, interceptor->data(), *receiver, *holder);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013772 v8::Handle<v8::Value> result = args.Call(getter, v8::Utils::ToLocal(name));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013773 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
13774 if (result.IsEmpty()) return MaybeHandle<Object>();
13775
13776 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13777 result_internal->VerifyApiCallResultType();
13778 // Rebox handle before return
13779 return handle(*result_internal, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013780}
13781
13782
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013783// Compute the property keys from the interceptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013784MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
13785 Handle<JSObject> object, Handle<JSReceiver> receiver) {
13786 Isolate* isolate = receiver->GetIsolate();
13787 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
13788 PropertyCallbackArguments
13789 args(isolate, interceptor->data(), *receiver, *object);
13790 v8::Handle<v8::Object> result;
13791 if (!interceptor->enumerator()->IsUndefined()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013792 v8::GenericNamedPropertyEnumeratorCallback enum_fun =
13793 v8::ToCData<v8::GenericNamedPropertyEnumeratorCallback>(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013794 interceptor->enumerator());
13795 LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
13796 result = args.Call(enum_fun);
Andrei Popescu402d9372010-02-26 13:31:12 +000013797 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013798 if (result.IsEmpty()) return MaybeHandle<JSObject>();
13799#if ENABLE_EXTRA_CHECKS
13800 CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13801 v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13802#endif
13803 // Rebox before returning.
13804 return handle(*v8::Utils::OpenHandle(*result), isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000013805}
13806
13807
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013808// Compute the element keys from the interceptor.
13809MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor(
13810 Handle<JSObject> object, Handle<JSReceiver> receiver) {
13811 Isolate* isolate = receiver->GetIsolate();
13812 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
13813 PropertyCallbackArguments
13814 args(isolate, interceptor->data(), *receiver, *object);
13815 v8::Handle<v8::Object> result;
13816 if (!interceptor->enumerator()->IsUndefined()) {
13817 v8::IndexedPropertyEnumeratorCallback enum_fun =
13818 v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
13819 interceptor->enumerator());
13820 LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
13821 result = args.Call(enum_fun);
13822 }
13823 if (result.IsEmpty()) return MaybeHandle<JSObject>();
13824#if ENABLE_EXTRA_CHECKS
13825 CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13826 v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13827#endif
13828 // Rebox before returning.
13829 return handle(*v8::Utils::OpenHandle(*result), isolate);
13830}
13831
13832
13833Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
13834 Handle<Name> key) {
13835 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
13836 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
13837 if (!maybe_result.has_value) return Maybe<bool>();
13838 return maybe(it.IsFound());
13839}
13840
13841
13842Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
13843 uint32_t index) {
13844 Isolate* isolate = object->GetIsolate();
Steve Block44f0eee2011-05-26 01:26:41 +010013845 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013846 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013847 if (object->IsAccessCheckNeeded()) {
13848 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
13849 isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
13850 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<bool>());
13851 return maybe(false);
Ben Murdoch8b112d22011-06-08 16:22:53 +010013852 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013853 }
13854
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013855 if (object->IsJSGlobalProxy()) {
13856 HandleScope scope(isolate);
13857 PrototypeIterator iter(isolate, object);
13858 if (iter.IsAtEnd()) return maybe(false);
13859 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
13860 return HasRealElementProperty(
13861 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
13862 }
13863
13864 Maybe<PropertyAttributes> result =
13865 GetElementAttributeWithoutInterceptor(object, object, index, false);
13866 if (!result.has_value) return Maybe<bool>();
13867 return maybe(result.value != ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +000013868}
13869
13870
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013871Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
13872 Handle<Name> key) {
13873 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
13874 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
13875 if (!maybe_result.has_value) return Maybe<bool>();
13876 return maybe(it.state() == LookupIterator::ACCESSOR);
Steve Blocka7e24c12009-10-30 11:49:00 +000013877}
13878
13879
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013880int JSObject::NumberOfOwnProperties(PropertyAttributes filter) {
13881 if (HasFastProperties()) {
13882 Map* map = this->map();
13883 if (filter == NONE) return map->NumberOfOwnDescriptors();
13884 if (filter & DONT_ENUM) {
13885 int result = map->EnumLength();
13886 if (result != kInvalidEnumCacheSentinel) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010013887 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013888 return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013889 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013890 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013891}
13892
13893
13894void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
13895 Object* temp = get(i);
13896 set(i, get(j));
13897 set(j, temp);
13898 if (this != numbers) {
13899 temp = numbers->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013900 numbers->set(i, Smi::cast(numbers->get(j)));
13901 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000013902 }
13903}
13904
13905
13906static void InsertionSortPairs(FixedArray* content,
13907 FixedArray* numbers,
13908 int len) {
13909 for (int i = 1; i < len; i++) {
13910 int j = i;
13911 while (j > 0 &&
13912 (NumberToUint32(numbers->get(j - 1)) >
13913 NumberToUint32(numbers->get(j)))) {
13914 content->SwapPairs(numbers, j - 1, j);
13915 j--;
13916 }
13917 }
13918}
13919
13920
13921void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
13922 // In-place heap sort.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013923 DCHECK(content->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000013924
13925 // Bottom-up max-heap construction.
13926 for (int i = 1; i < len; ++i) {
13927 int child_index = i;
13928 while (child_index > 0) {
13929 int parent_index = ((child_index + 1) >> 1) - 1;
13930 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13931 uint32_t child_value = NumberToUint32(numbers->get(child_index));
13932 if (parent_value < child_value) {
13933 content->SwapPairs(numbers, parent_index, child_index);
13934 } else {
13935 break;
13936 }
13937 child_index = parent_index;
13938 }
13939 }
13940
13941 // Extract elements and create sorted array.
13942 for (int i = len - 1; i > 0; --i) {
13943 // Put max element at the back of the array.
13944 content->SwapPairs(numbers, 0, i);
13945 // Sift down the new top element.
13946 int parent_index = 0;
13947 while (true) {
13948 int child_index = ((parent_index + 1) << 1) - 1;
13949 if (child_index >= i) break;
13950 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
13951 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
13952 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13953 if (child_index + 1 >= i || child1_value > child2_value) {
13954 if (parent_value > child1_value) break;
13955 content->SwapPairs(numbers, parent_index, child_index);
13956 parent_index = child_index;
13957 } else {
13958 if (parent_value > child2_value) break;
13959 content->SwapPairs(numbers, parent_index, child_index + 1);
13960 parent_index = child_index + 1;
13961 }
13962 }
13963 }
13964}
13965
13966
13967// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
13968void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013969 DCHECK(this->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000013970 // For small arrays, simply use insertion sort.
13971 if (len <= 10) {
13972 InsertionSortPairs(this, numbers, len);
13973 return;
13974 }
13975 // Check the range of indices.
13976 uint32_t min_index = NumberToUint32(numbers->get(0));
13977 uint32_t max_index = min_index;
13978 uint32_t i;
13979 for (i = 1; i < len; i++) {
13980 if (NumberToUint32(numbers->get(i)) < min_index) {
13981 min_index = NumberToUint32(numbers->get(i));
13982 } else if (NumberToUint32(numbers->get(i)) > max_index) {
13983 max_index = NumberToUint32(numbers->get(i));
13984 }
13985 }
13986 if (max_index - min_index + 1 == len) {
13987 // Indices form a contiguous range, unless there are duplicates.
13988 // Do an in-place linear time sort assuming distinct numbers, but
13989 // avoid hanging in case they are not.
13990 for (i = 0; i < len; i++) {
13991 uint32_t p;
13992 uint32_t j = 0;
13993 // While the current element at i is not at its correct position p,
13994 // swap the elements at these two positions.
13995 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
13996 j++ < len) {
13997 SwapPairs(numbers, i, p);
13998 }
13999 }
14000 } else {
14001 HeapSortPairs(this, numbers, len);
14002 return;
14003 }
14004}
14005
14006
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014007// Fill in the names of own properties into the supplied storage. The main
Steve Blocka7e24c12009-10-30 11:49:00 +000014008// purpose of this function is to provide reflection information for the object
14009// mirrors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014010void JSObject::GetOwnPropertyNames(
14011 FixedArray* storage, int index, PropertyAttributes filter) {
14012 DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index));
Steve Blocka7e24c12009-10-30 11:49:00 +000014013 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014014 int real_size = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +000014015 DescriptorArray* descs = map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014016 for (int i = 0; i < real_size; i++) {
14017 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
14018 !FilterKey(descs->GetKey(i), filter)) {
14019 storage->set(index++, descs->GetKey(i));
14020 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014021 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014022 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014023 property_dictionary()->CopyKeysTo(storage,
14024 index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014025 filter,
14026 NameDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000014027 }
14028}
14029
14030
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014031int JSObject::NumberOfOwnElements(PropertyAttributes filter) {
14032 return GetOwnElementKeys(NULL, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000014033}
14034
14035
14036int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +000014037 // Fast case for objects with no elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014038 if (!IsJSValue() && HasFastObjectElements()) {
Steve Blockd0582a62009-12-15 09:54:21 +000014039 uint32_t length = IsJSArray() ?
14040 static_cast<uint32_t>(
14041 Smi::cast(JSArray::cast(this)->length())->value()) :
14042 static_cast<uint32_t>(FixedArray::cast(elements())->length());
14043 if (length == 0) return 0;
14044 }
14045 // Compute the number of enumerable elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014046 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM));
Steve Blocka7e24c12009-10-30 11:49:00 +000014047}
14048
14049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014050int JSObject::GetOwnElementKeys(FixedArray* storage,
14051 PropertyAttributes filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014052 int counter = 0;
14053 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014054 case FAST_SMI_ELEMENTS:
14055 case FAST_ELEMENTS:
14056 case FAST_HOLEY_SMI_ELEMENTS:
14057 case FAST_HOLEY_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +000014058 int length = IsJSArray() ?
14059 Smi::cast(JSArray::cast(this)->length())->value() :
14060 FixedArray::cast(elements())->length();
14061 for (int i = 0; i < length; i++) {
14062 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
14063 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000014064 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000014065 }
14066 counter++;
14067 }
14068 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014069 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000014070 break;
14071 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014072 case FAST_DOUBLE_ELEMENTS:
14073 case FAST_HOLEY_DOUBLE_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014074 int length = IsJSArray() ?
14075 Smi::cast(JSArray::cast(this)->length())->value() :
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014076 FixedArrayBase::cast(elements())->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014077 for (int i = 0; i < length; i++) {
14078 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
14079 if (storage != NULL) {
14080 storage->set(counter, Smi::FromInt(i));
14081 }
14082 counter++;
14083 }
14084 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014085 DCHECK(!storage || storage->length() >= counter);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014086 break;
14087 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014088
14089#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
14090 case EXTERNAL_##TYPE##_ELEMENTS: \
14091 case TYPE##_ELEMENTS: \
14092
14093 TYPED_ARRAYS(TYPED_ARRAY_CASE)
14094#undef TYPED_ARRAY_CASE
14095 {
14096 int length = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000014097 while (counter < length) {
14098 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000014099 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000014100 }
14101 counter++;
14102 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014103 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000014104 break;
14105 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014106
Steve Blocka7e24c12009-10-30 11:49:00 +000014107 case DICTIONARY_ELEMENTS: {
14108 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014109 element_dictionary()->CopyKeysTo(storage,
14110 filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +000014111 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000014112 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014113 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000014114 break;
14115 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014116 case SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014117 FixedArray* parameter_map = FixedArray::cast(elements());
14118 int mapped_length = parameter_map->length() - 2;
14119 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
14120 if (arguments->IsDictionary()) {
14121 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
14122 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +000014123 SeededNumberDictionary* dictionary =
14124 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014125 if (storage != NULL) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000014126 dictionary->CopyKeysTo(
14127 storage, filter, SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014128 }
14129 counter += dictionary->NumberOfElementsFilterAttributes(filter);
14130 for (int i = 0; i < mapped_length; ++i) {
14131 if (!parameter_map->get(i + 2)->IsTheHole()) {
14132 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14133 ++counter;
14134 }
14135 }
14136 if (storage != NULL) storage->SortPairs(storage, counter);
14137
14138 } else {
14139 int backing_length = arguments->length();
14140 int i = 0;
14141 for (; i < mapped_length; ++i) {
14142 if (!parameter_map->get(i + 2)->IsTheHole()) {
14143 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14144 ++counter;
14145 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
14146 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14147 ++counter;
14148 }
14149 }
14150 for (; i < backing_length; ++i) {
14151 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
14152 ++counter;
14153 }
14154 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014155 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014156 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014157 }
14158
14159 if (this->IsJSValue()) {
14160 Object* val = JSValue::cast(this)->value();
14161 if (val->IsString()) {
14162 String* str = String::cast(val);
14163 if (storage) {
14164 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000014165 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000014166 }
14167 }
14168 counter += str->length();
14169 }
14170 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014171 DCHECK(!storage || storage->length() == counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000014172 return counter;
14173}
14174
14175
14176int JSObject::GetEnumElementKeys(FixedArray* storage) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014177 return GetOwnElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM));
Steve Blocka7e24c12009-10-30 11:49:00 +000014178}
14179
14180
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014181const char* Symbol::PrivateSymbolToName() const {
14182 Heap* heap = GetIsolate()->heap();
14183#define SYMBOL_CHECK_AND_PRINT(name) \
14184 if (this == heap->name()) return #name;
14185 PRIVATE_SYMBOL_LIST(SYMBOL_CHECK_AND_PRINT)
14186#undef SYMBOL_CHECK_AND_PRINT
14187 return "UNKNOWN";
14188}
14189
14190
14191void Symbol::SymbolShortPrint(std::ostream& os) {
14192 os << "<Symbol: " << Hash();
14193 if (!name()->IsUndefined()) {
14194 os << " ";
14195 HeapStringAllocator allocator;
14196 StringStream accumulator(&allocator);
14197 String::cast(name())->StringShortPrint(&accumulator);
14198 os << accumulator.ToCString().get();
14199 } else {
14200 os << " (" << PrivateSymbolToName() << ")";
14201 }
14202 os << ">";
14203}
14204
14205
Steve Blocka7e24c12009-10-30 11:49:00 +000014206// StringSharedKeys are used as keys in the eval cache.
14207class StringSharedKey : public HashTableKey {
14208 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014209 StringSharedKey(Handle<String> source,
14210 Handle<SharedFunctionInfo> shared,
14211 StrictMode strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014212 int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010014213 : source_(source),
14214 shared_(shared),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014215 strict_mode_(strict_mode),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014216 scope_position_(scope_position) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000014217
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014218 bool IsMatch(Object* other) OVERRIDE {
14219 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014220 if (!other->IsFixedArray()) {
14221 if (!other->IsNumber()) return false;
14222 uint32_t other_hash = static_cast<uint32_t>(other->Number());
14223 return Hash() == other_hash;
14224 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014225 FixedArray* other_array = FixedArray::cast(other);
14226 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014227 if (shared != *shared_) return false;
14228 int strict_unchecked = Smi::cast(other_array->get(2))->value();
14229 DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
14230 StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
14231 if (strict_mode != strict_mode_) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014232 int scope_position = Smi::cast(other_array->get(3))->value();
14233 if (scope_position != scope_position_) return false;
14234 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014235 return source->Equals(*source_);
Steve Blocka7e24c12009-10-30 11:49:00 +000014236 }
14237
14238 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010014239 SharedFunctionInfo* shared,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014240 StrictMode strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014241 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014242 uint32_t hash = source->Hash();
14243 if (shared->HasSourceCode()) {
14244 // Instead of using the SharedFunctionInfo pointer in the hash
14245 // code computation, we use a combination of the hash of the
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014246 // script source code and the start position of the calling scope.
14247 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000014248 // collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014249 Script* script(Script::cast(shared->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +000014250 hash ^= String::cast(script->source())->Hash();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014251 if (strict_mode == STRICT) hash ^= 0x8000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014252 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000014253 }
14254 return hash;
14255 }
14256
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014257 uint32_t Hash() OVERRIDE {
14258 return StringSharedHashHelper(*source_, *shared_, strict_mode_,
14259 scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000014260 }
14261
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014262 uint32_t HashForObject(Object* obj) OVERRIDE {
14263 DisallowHeapAllocation no_allocation;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014264 if (obj->IsNumber()) {
14265 return static_cast<uint32_t>(obj->Number());
14266 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014267 FixedArray* other_array = FixedArray::cast(obj);
14268 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
14269 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014270 int strict_unchecked = Smi::cast(other_array->get(2))->value();
14271 DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
14272 StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014273 int scope_position = Smi::cast(other_array->get(3))->value();
14274 return StringSharedHashHelper(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014275 source, shared, strict_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000014276 }
14277
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014278
14279 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
14280 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
14281 array->set(0, *shared_);
14282 array->set(1, *source_);
14283 array->set(2, Smi::FromInt(strict_mode_));
14284 array->set(3, Smi::FromInt(scope_position_));
14285 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000014286 }
14287
14288 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014289 Handle<String> source_;
14290 Handle<SharedFunctionInfo> shared_;
14291 StrictMode strict_mode_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014292 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000014293};
14294
14295
14296// RegExpKey carries the source and flags of a regular expression as key.
14297class RegExpKey : public HashTableKey {
14298 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014299 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
Steve Blocka7e24c12009-10-30 11:49:00 +000014300 : string_(string),
14301 flags_(Smi::FromInt(flags.value())) { }
14302
Steve Block3ce2e202009-11-05 08:53:23 +000014303 // Rather than storing the key in the hash table, a pointer to the
14304 // stored value is stored where the key should be. IsMatch then
14305 // compares the search key to the found object, rather than comparing
14306 // a key to a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014307 bool IsMatch(Object* obj) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000014308 FixedArray* val = FixedArray::cast(obj);
14309 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
14310 && (flags_ == val->get(JSRegExp::kFlagsIndex));
14311 }
14312
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014313 uint32_t Hash() OVERRIDE { return RegExpHash(*string_, flags_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000014314
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014315 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000014316 // Plain hash maps, which is where regexp keys are used, don't
14317 // use this function.
14318 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014319 return MaybeHandle<Object>().ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000014320 }
14321
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014322 uint32_t HashForObject(Object* obj) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000014323 FixedArray* val = FixedArray::cast(obj);
14324 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
14325 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
14326 }
14327
14328 static uint32_t RegExpHash(String* string, Smi* flags) {
14329 return string->Hash() + flags->value();
14330 }
14331
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014332 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000014333 Smi* flags_;
14334};
14335
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014336
14337Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
14338 if (hash_field_ == 0) Hash();
14339 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
14340}
14341
14342
14343Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
14344 if (hash_field_ == 0) Hash();
14345 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
14346}
14347
14348
14349Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
14350 if (hash_field_ == 0) Hash();
14351 return isolate->factory()->NewOneByteInternalizedSubString(
14352 string_, from_, length_, hash_field_);
14353}
14354
14355
14356bool SeqOneByteSubStringKey::IsMatch(Object* string) {
14357 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
14358 return String::cast(string)->IsOneByteEqualTo(chars);
14359}
14360
14361
14362// InternalizedStringKey carries a string/internalized-string object as key.
14363class InternalizedStringKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000014364 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014365 explicit InternalizedStringKey(Handle<String> string)
Steve Block44f0eee2011-05-26 01:26:41 +010014366 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000014367
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014368 bool IsMatch(Object* string) OVERRIDE {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014369 return String::cast(string)->Equals(*string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000014370 }
14371
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014372 uint32_t Hash() OVERRIDE { return string_->Hash(); }
Steve Blocka7e24c12009-10-30 11:49:00 +000014373
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014374 uint32_t HashForObject(Object* other) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000014375 return String::cast(other)->Hash();
14376 }
14377
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014378 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014379 // Internalize the string if possible.
14380 MaybeHandle<Map> maybe_map =
14381 isolate->factory()->InternalizedStringMapForString(string_);
14382 Handle<Map> map;
14383 if (maybe_map.ToHandle(&map)) {
14384 string_->set_map_no_write_barrier(*map);
14385 DCHECK(string_->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +000014386 return string_;
14387 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014388 // Otherwise allocate a new internalized string.
14389 return isolate->factory()->NewInternalizedStringImpl(
14390 string_, string_->length(), string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000014391 }
14392
14393 static uint32_t StringHash(Object* obj) {
14394 return String::cast(obj)->Hash();
14395 }
14396
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014397 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000014398};
14399
14400
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014401template<typename Derived, typename Shape, typename Key>
14402void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014403 IteratePointers(v, 0, kElementsStartOffset);
14404}
14405
14406
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014407template<typename Derived, typename Shape, typename Key>
14408void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014409 IteratePointers(v,
14410 kElementsStartOffset,
14411 kHeaderSize + length() * kPointerSize);
14412}
14413
14414
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014415template<typename Derived, typename Shape, typename Key>
14416Handle<Derived> HashTable<Derived, Shape, Key>::New(
14417 Isolate* isolate,
14418 int at_least_space_for,
14419 MinimumCapacity capacity_option,
14420 PretenureFlag pretenure) {
14421 DCHECK(0 <= at_least_space_for);
14422 DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
14423 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
14424 ? at_least_space_for
14425 : ComputeCapacity(at_least_space_for);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014426 if (capacity > HashTable::kMaxCapacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014427 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
Leon Clarkee46be812010-01-19 14:06:41 +000014428 }
14429
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014430 Factory* factory = isolate->factory();
14431 int length = EntryToIndex(capacity);
14432 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
14433 array->set_map_no_write_barrier(*factory->hash_table_map());
14434 Handle<Derived> table = Handle<Derived>::cast(array);
14435
14436 table->SetNumberOfElements(0);
14437 table->SetNumberOfDeletedElements(0);
14438 table->SetCapacity(capacity);
14439 return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000014440}
14441
14442
Leon Clarkee46be812010-01-19 14:06:41 +000014443// Find entry for key otherwise return kNotFound.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014444int NameDictionary::FindEntry(Handle<Name> key) {
14445 if (!key->IsUniqueName()) {
14446 return DerivedHashTable::FindEntry(key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010014447 }
14448
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014449 // Optimized for unique names. Knowledge of the key type allows:
14450 // 1. Move the check if the key is unique out of the loop.
14451 // 2. Avoid comparing hash codes in unique-to-unique comparison.
14452 // 3. Detect a case when a dictionary key is not unique but the key is.
14453 // In case of positive result the dictionary key may be replaced by the
14454 // internalized string with minimal performance penalty. It gives a chance
14455 // to perform further lookups in code stubs (and significant performance
14456 // boost a certain style of code).
Ben Murdoch3bec4d22010-07-22 14:51:16 +010014457
14458 // EnsureCapacity will guarantee the hash table is never full.
14459 uint32_t capacity = Capacity();
14460 uint32_t entry = FirstProbe(key->Hash(), capacity);
14461 uint32_t count = 1;
14462
14463 while (true) {
14464 int index = EntryToIndex(entry);
14465 Object* element = get(index);
14466 if (element->IsUndefined()) break; // Empty entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014467 if (*key == element) return entry;
14468 if (!element->IsUniqueName() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014469 !element->IsTheHole() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014470 Name::cast(element)->Equals(*key)) {
14471 // Replace a key that is a non-internalized string by the equivalent
14472 // internalized string for faster further lookups.
14473 set(index, *key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010014474 return entry;
14475 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014476 DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010014477 entry = NextProbe(entry, count++, capacity);
14478 }
14479 return kNotFound;
14480}
14481
14482
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014483template<typename Derived, typename Shape, typename Key>
14484void HashTable<Derived, Shape, Key>::Rehash(
14485 Handle<Derived> new_table,
14486 Key key) {
14487 DCHECK(NumberOfElements() < new_table->Capacity());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014488
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014489 DisallowHeapAllocation no_gc;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014490 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
14491
14492 // Copy prefix to new array.
14493 for (int i = kPrefixStartIndex;
14494 i < kPrefixStartIndex + Shape::kPrefixSize;
14495 i++) {
14496 new_table->set(i, get(i), mode);
14497 }
14498
14499 // Rehash the elements.
14500 int capacity = Capacity();
14501 for (int i = 0; i < capacity; i++) {
14502 uint32_t from_index = EntryToIndex(i);
14503 Object* k = get(from_index);
14504 if (IsKey(k)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014505 uint32_t hash = HashTable::HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014506 uint32_t insertion_index =
14507 EntryToIndex(new_table->FindInsertionEntry(hash));
14508 for (int j = 0; j < Shape::kEntrySize; j++) {
14509 new_table->set(insertion_index + j, get(from_index + j), mode);
14510 }
14511 }
14512 }
14513 new_table->SetNumberOfElements(NumberOfElements());
14514 new_table->SetNumberOfDeletedElements(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014515}
14516
14517
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014518template<typename Derived, typename Shape, typename Key>
14519uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
14520 Key key,
14521 Object* k,
14522 int probe,
14523 uint32_t expected) {
14524 uint32_t hash = HashTable::HashForObject(key, k);
14525 uint32_t capacity = Capacity();
14526 uint32_t entry = FirstProbe(hash, capacity);
14527 for (int i = 1; i < probe; i++) {
14528 if (entry == expected) return expected;
14529 entry = NextProbe(entry, i, capacity);
14530 }
14531 return entry;
14532}
14533
14534
14535template<typename Derived, typename Shape, typename Key>
14536void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
14537 uint32_t entry2,
14538 WriteBarrierMode mode) {
14539 int index1 = EntryToIndex(entry1);
14540 int index2 = EntryToIndex(entry2);
14541 Object* temp[Shape::kEntrySize];
14542 for (int j = 0; j < Shape::kEntrySize; j++) {
14543 temp[j] = get(index1 + j);
14544 }
14545 for (int j = 0; j < Shape::kEntrySize; j++) {
14546 set(index1 + j, get(index2 + j), mode);
14547 }
14548 for (int j = 0; j < Shape::kEntrySize; j++) {
14549 set(index2 + j, temp[j], mode);
14550 }
14551}
14552
14553
14554template<typename Derived, typename Shape, typename Key>
14555void HashTable<Derived, Shape, Key>::Rehash(Key key) {
14556 DisallowHeapAllocation no_gc;
14557 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
14558 uint32_t capacity = Capacity();
14559 bool done = false;
14560 for (int probe = 1; !done; probe++) {
14561 // All elements at entries given by one of the first _probe_ probes
14562 // are placed correctly. Other elements might need to be moved.
14563 done = true;
14564 for (uint32_t current = 0; current < capacity; current++) {
14565 Object* current_key = get(EntryToIndex(current));
14566 if (IsKey(current_key)) {
14567 uint32_t target = EntryForProbe(key, current_key, probe, current);
14568 if (current == target) continue;
14569 Object* target_key = get(EntryToIndex(target));
14570 if (!IsKey(target_key) ||
14571 EntryForProbe(key, target_key, probe, target) != target) {
14572 // Put the current element into the correct position.
14573 Swap(current, target, mode);
14574 // The other element will be processed on the next iteration.
14575 current--;
14576 } else {
14577 // The place for the current element is occupied. Leave the element
14578 // for the next probe.
14579 done = false;
14580 }
14581 }
14582 }
14583 }
14584}
14585
14586
14587template<typename Derived, typename Shape, typename Key>
14588Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
14589 Handle<Derived> table,
14590 int n,
14591 Key key,
14592 PretenureFlag pretenure) {
14593 Isolate* isolate = table->GetIsolate();
14594 int capacity = table->Capacity();
14595 int nof = table->NumberOfElements() + n;
14596 int nod = table->NumberOfDeletedElements();
Leon Clarkee46be812010-01-19 14:06:41 +000014597 // Return if:
14598 // 50% is still free after adding n elements and
14599 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +010014600 if (nod <= (capacity - nof) >> 1) {
14601 int needed_free = nof >> 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014602 if (nof + needed_free <= capacity) return table;
Steve Block6ded16b2010-05-10 14:33:55 +010014603 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014604
Steve Block6ded16b2010-05-10 14:33:55 +010014605 const int kMinCapacityForPretenure = 256;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014606 bool should_pretenure = pretenure == TENURED ||
14607 ((capacity > kMinCapacityForPretenure) &&
14608 !isolate->heap()->InNewSpace(*table));
14609 Handle<Derived> new_table = HashTable::New(
14610 isolate,
14611 nof * 2,
14612 USE_DEFAULT_MINIMUM_CAPACITY,
14613 should_pretenure ? TENURED : NOT_TENURED);
Leon Clarke4515c472010-02-03 11:58:03 +000014614
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014615 table->Rehash(new_table, key);
14616 return new_table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014617}
Steve Blocka7e24c12009-10-30 11:49:00 +000014618
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014619
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014620template<typename Derived, typename Shape, typename Key>
14621Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
14622 Key key) {
14623 int capacity = table->Capacity();
14624 int nof = table->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014625
14626 // Shrink to fit the number of elements if only a quarter of the
14627 // capacity is filled with elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014628 if (nof > (capacity >> 2)) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014629 // Allocate a new dictionary with room for at least the current
14630 // number of elements. The allocation method will make sure that
14631 // there is extra room in the dictionary for additions. Don't go
14632 // lower than room for 16 elements.
14633 int at_least_room_for = nof;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014634 if (at_least_room_for < 16) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014635
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014636 Isolate* isolate = table->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014637 const int kMinCapacityForPretenure = 256;
14638 bool pretenure =
14639 (at_least_room_for > kMinCapacityForPretenure) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014640 !isolate->heap()->InNewSpace(*table);
14641 Handle<Derived> new_table = HashTable::New(
14642 isolate,
14643 at_least_room_for,
14644 USE_DEFAULT_MINIMUM_CAPACITY,
14645 pretenure ? TENURED : NOT_TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014646
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014647 table->Rehash(new_table, key);
14648 return new_table;
Steve Blocka7e24c12009-10-30 11:49:00 +000014649}
14650
14651
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014652template<typename Derived, typename Shape, typename Key>
14653uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014654 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000014655 uint32_t entry = FirstProbe(hash, capacity);
14656 uint32_t count = 1;
14657 // EnsureCapacity will guarantee the hash table is never full.
14658 while (true) {
14659 Object* element = KeyAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014660 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000014661 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000014662 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014663 return entry;
14664}
14665
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014666
Steve Blocka7e24c12009-10-30 11:49:00 +000014667// Force instantiation of template instances class.
14668// Please note this list is compiler dependent.
14669
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014670template class HashTable<StringTable, StringTableShape, HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000014671
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014672template class HashTable<CompilationCacheTable,
14673 CompilationCacheShape,
14674 HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000014675
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014676template class HashTable<ObjectHashTable,
14677 ObjectHashTableShape,
14678 Handle<Object> >;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014679
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014680template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014681
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014682template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
Steve Blocka7e24c12009-10-30 11:49:00 +000014683
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014684template class Dictionary<SeededNumberDictionary,
14685 SeededNumberDictionaryShape,
14686 uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000014687
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014688template class Dictionary<UnseededNumberDictionary,
14689 UnseededNumberDictionaryShape,
14690 uint32_t>;
Ben Murdochc7cc0282012-03-05 14:35:55 +000014691
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014692template Handle<SeededNumberDictionary>
14693Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14694 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014696template Handle<UnseededNumberDictionary>
14697Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14698 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000014699
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014700template Handle<NameDictionary>
14701Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14702 New(Isolate*, int n, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000014703
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014704template Handle<SeededNumberDictionary>
14705Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14706 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
Steve Blocka7e24c12009-10-30 11:49:00 +000014707
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014708template Handle<UnseededNumberDictionary>
14709Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14710 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014711
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014712template Object*
14713Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014714 SlowReverseLookup(Object* value);
14715
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014716template Object*
14717Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000014718 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014719
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014720template void
14721Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14722 CopyKeysTo(
14723 FixedArray*,
14724 PropertyAttributes,
14725 Dictionary<SeededNumberDictionary,
14726 SeededNumberDictionaryShape,
14727 uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014728
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014729template Handle<Object>
14730Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
14731 Handle<NameDictionary>, int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014732
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014733template Handle<Object>
14734Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14735 DeleteProperty(Handle<SeededNumberDictionary>, int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014736
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014737template Handle<NameDictionary>
14738HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14739 New(Isolate*, int, MinimumCapacity, PretenureFlag);
Steve Blocka7e24c12009-10-30 11:49:00 +000014740
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014741template Handle<NameDictionary>
14742HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14743 Shrink(Handle<NameDictionary>, Handle<Name>);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014744
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014745template Handle<SeededNumberDictionary>
14746HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14747 Shrink(Handle<SeededNumberDictionary>, uint32_t);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014748
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014749template void Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14750 CopyKeysTo(
14751 FixedArray*,
14752 int,
14753 PropertyAttributes,
14754 Dictionary<
14755 NameDictionary, NameDictionaryShape, Handle<Name> >::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014756
14757template int
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014758Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000014759 NumberOfElementsFilterAttributes(PropertyAttributes);
Steve Blocka7e24c12009-10-30 11:49:00 +000014760
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014761template Handle<NameDictionary>
14762Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
14763 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000014764
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014765template Handle<FixedArray> Dictionary<
14766 NameDictionary, NameDictionaryShape,
14767 Handle<Name> >::BuildIterationIndicesArray(Handle<NameDictionary>);
14768
14769template Handle<FixedArray> Dictionary<
14770 NameDictionary, NameDictionaryShape,
14771 Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014772
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014773template int
14774Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14775 NumberOfElementsFilterAttributes(PropertyAttributes);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014776
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014777template Handle<SeededNumberDictionary>
14778Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14779 Add(Handle<SeededNumberDictionary>,
14780 uint32_t,
14781 Handle<Object>,
14782 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000014783
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014784template Handle<UnseededNumberDictionary>
14785Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14786 Add(Handle<UnseededNumberDictionary>,
14787 uint32_t,
14788 Handle<Object>,
14789 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000014790
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014791template Handle<SeededNumberDictionary>
14792Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14793 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014794
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014795template Handle<UnseededNumberDictionary>
14796Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14797 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000014798
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014799template Handle<NameDictionary>
14800Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14801 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
Steve Blocka7e24c12009-10-30 11:49:00 +000014802
14803template
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014804int Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14805 NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000014806
14807template
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014808int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14809 NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000014810
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014811template bool Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape,
14812 uint32_t>::HasComplexElements();
14813
14814template int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape,
14815 uint32_t>::FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000014816
14817
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014818Handle<Object> JSObject::PrepareSlowElementsForSort(
14819 Handle<JSObject> object, uint32_t limit) {
14820 DCHECK(object->HasDictionaryElements());
14821 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000014822 // Must stay in dictionary mode, either because of requires_slow_elements,
14823 // or because we are not going to sort (and therefore compact) all of the
14824 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014825 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
14826 Handle<SeededNumberDictionary> new_dict =
14827 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000014828
14829 uint32_t pos = 0;
14830 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010014831 int capacity = dict->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014832 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
14833 // Entry to the new dictionary does not cause it to grow, as we have
14834 // allocated one that is large enough for all entries.
14835 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000014836 for (int i = 0; i < capacity; i++) {
14837 Object* k = dict->KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014838 if (!dict->IsKey(k)) continue;
14839
14840 DCHECK(k->IsNumber());
14841 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
14842 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
14843 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
14844
14845 HandleScope scope(isolate);
14846 Handle<Object> value(dict->ValueAt(i), isolate);
14847 PropertyDetails details = dict->DetailsAt(i);
14848 if (details.type() == CALLBACKS || details.IsReadOnly()) {
14849 // Bail out and do the sorting of undefineds and array holes in JS.
14850 // Also bail out if the element is not supposed to be moved.
14851 return bailout;
14852 }
14853
14854 uint32_t key = NumberToUint32(k);
14855 if (key < limit) {
14856 if (value->IsUndefined()) {
14857 undefs++;
14858 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14859 // Adding an entry with the key beyond smi-range requires
14860 // allocation. Bailout.
14861 return bailout;
Steve Blocka7e24c12009-10-30 11:49:00 +000014862 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014863 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14864 new_dict, pos, value, details);
14865 DCHECK(result.is_identical_to(new_dict));
14866 USE(result);
14867 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000014868 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014869 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
14870 // Adding an entry with the key beyond smi-range requires
14871 // allocation. Bailout.
14872 return bailout;
14873 } else {
14874 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14875 new_dict, key, value, details);
14876 DCHECK(result.is_identical_to(new_dict));
14877 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014878 }
14879 }
14880
14881 uint32_t result = pos;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014882 PropertyDetails no_details(NONE, FIELD, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014883 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010014884 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14885 // Adding an entry with the key beyond smi-range requires
14886 // allocation. Bailout.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014887 return bailout;
Steve Block1e0659c2011-05-24 12:43:12 +010014888 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014889 HandleScope scope(isolate);
14890 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14891 new_dict, pos, isolate->factory()->undefined_value(), no_details);
14892 DCHECK(result.is_identical_to(new_dict));
14893 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014894 pos++;
14895 undefs--;
14896 }
14897
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014898 object->set_elements(*new_dict);
Steve Blocka7e24c12009-10-30 11:49:00 +000014899
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014900 AllowHeapAllocation allocate_return_value;
14901 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014902}
14903
14904
14905// Collects all defined (non-hole) and non-undefined (array) elements at
14906// the start of the elements array.
14907// If the object is in dictionary mode, it is converted to fast elements
14908// mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014909Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
14910 uint32_t limit) {
14911 Isolate* isolate = object->GetIsolate();
14912 if (object->HasSloppyArgumentsElements() ||
14913 object->map()->is_observed()) {
14914 return handle(Smi::FromInt(-1), isolate);
14915 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010014916
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014917 if (object->HasDictionaryElements()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014918 // Convert to fast elements containing only the existing properties.
14919 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014920 Handle<SeededNumberDictionary> dict(object->element_dictionary());
14921 if (object->IsJSArray() || dict->requires_slow_elements() ||
Steve Blocka7e24c12009-10-30 11:49:00 +000014922 dict->max_number_key() >= limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014923 return JSObject::PrepareSlowElementsForSort(object, limit);
Steve Blocka7e24c12009-10-30 11:49:00 +000014924 }
14925 // Convert to fast elements.
14926
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014927 Handle<Map> new_map =
14928 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
Steve Block8defd9f2010-07-08 12:39:36 +010014929
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014930 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
14931 NOT_TENURED: TENURED;
14932 Handle<FixedArray> fast_elements =
14933 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
14934 dict->CopyValuesTo(*fast_elements);
14935 JSObject::ValidateElements(object);
Steve Block8defd9f2010-07-08 12:39:36 +010014936
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014937 JSObject::SetMapAndElements(object, new_map, fast_elements);
14938 } else if (object->HasExternalArrayElements() ||
14939 object->HasFixedTypedArrayElements()) {
14940 // Typed arrays cannot have holes or undefined elements.
14941 return handle(Smi::FromInt(
14942 FixedArrayBase::cast(object->elements())->length()), isolate);
14943 } else if (!object->HasFastDoubleElements()) {
14944 EnsureWritableFastElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000014945 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014946 DCHECK(object->HasFastSmiOrObjectElements() ||
14947 object->HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000014948
14949 // Collect holes at the end, undefined before that and the rest at the
14950 // start, and return the number of non-hole, non-undefined values.
14951
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014952 Handle<FixedArrayBase> elements_base(object->elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014953 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000014954 if (limit > elements_length) {
14955 limit = elements_length ;
14956 }
14957 if (limit == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014958 return handle(Smi::FromInt(0), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014959 }
14960
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014961 uint32_t result = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014962 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
14963 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014964 // Split elements into defined and the_hole, in that order.
14965 unsigned int holes = limit;
14966 // Assume most arrays contain no holes and undefined values, so minimize the
14967 // number of stores of non-undefined, non-the-hole values.
14968 for (unsigned int i = 0; i < holes; i++) {
14969 if (elements->is_the_hole(i)) {
14970 holes--;
14971 } else {
14972 continue;
14973 }
14974 // Position i needs to be filled.
14975 while (holes > i) {
14976 if (elements->is_the_hole(holes)) {
14977 holes--;
14978 } else {
14979 elements->set(i, elements->get_scalar(holes));
14980 break;
14981 }
14982 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014983 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014984 result = holes;
14985 while (holes < limit) {
14986 elements->set_the_hole(holes);
14987 holes++;
14988 }
14989 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014990 FixedArray* elements = FixedArray::cast(*elements_base);
14991 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014992
14993 // Split elements into defined, undefined and the_hole, in that order. Only
14994 // count locations for undefined and the hole, and fill them afterwards.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014995 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014996 unsigned int undefs = limit;
14997 unsigned int holes = limit;
14998 // Assume most arrays contain no holes and undefined values, so minimize the
14999 // number of stores of non-undefined, non-the-hole values.
15000 for (unsigned int i = 0; i < undefs; i++) {
15001 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000015002 if (current->IsTheHole()) {
15003 holes--;
15004 undefs--;
15005 } else if (current->IsUndefined()) {
15006 undefs--;
15007 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015008 continue;
15009 }
15010 // Position i needs to be filled.
15011 while (undefs > i) {
15012 current = elements->get(undefs);
15013 if (current->IsTheHole()) {
15014 holes--;
15015 undefs--;
15016 } else if (current->IsUndefined()) {
15017 undefs--;
15018 } else {
15019 elements->set(i, current, write_barrier);
15020 break;
15021 }
Steve Blocka7e24c12009-10-30 11:49:00 +000015022 }
15023 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015024 result = undefs;
15025 while (undefs < holes) {
15026 elements->set_undefined(undefs);
15027 undefs++;
15028 }
15029 while (holes < limit) {
15030 elements->set_the_hole(holes);
15031 holes++;
15032 }
Steve Blocka7e24c12009-10-30 11:49:00 +000015033 }
15034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015035 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000015036}
15037
15038
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015039ExternalArrayType JSTypedArray::type() {
15040 switch (elements()->map()->instance_type()) {
15041#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
15042 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
15043 case FIXED_##TYPE##_ARRAY_TYPE: \
15044 return kExternal##Type##Array;
15045
15046 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
15047#undef INSTANCE_TYPE_TO_ARRAY_TYPE
15048
15049 default:
15050 UNREACHABLE();
15051 return static_cast<ExternalArrayType>(-1);
15052 }
15053}
15054
15055
15056size_t JSTypedArray::element_size() {
15057 switch (elements()->map()->instance_type()) {
15058#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
15059 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
15060 return size;
15061
15062 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
15063#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
15064
15065 default:
15066 UNREACHABLE();
15067 return 0;
15068 }
15069}
15070
15071
15072Handle<Object> ExternalUint8ClampedArray::SetValue(
15073 Handle<ExternalUint8ClampedArray> array,
15074 uint32_t index,
15075 Handle<Object> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015076 uint8_t clamped_value = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015077 if (index < static_cast<uint32_t>(array->length())) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015078 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015079 int int_value = Handle<Smi>::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015080 if (int_value < 0) {
15081 clamped_value = 0;
15082 } else if (int_value > 255) {
15083 clamped_value = 255;
15084 } else {
15085 clamped_value = static_cast<uint8_t>(int_value);
15086 }
15087 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015088 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015089 if (!(double_value > 0)) {
15090 // NaN and less than zero clamp to zero.
15091 clamped_value = 0;
15092 } else if (double_value > 255) {
15093 // Greater than 255 clamp to 255.
15094 clamped_value = 255;
15095 } else {
15096 // Other doubles are rounded to the nearest integer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015097 clamped_value = static_cast<uint8_t>(lrint(double_value));
Steve Blocka7e24c12009-10-30 11:49:00 +000015098 }
15099 } else {
15100 // Clamp undefined to zero (default). All other types have been
15101 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015102 DCHECK(value->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +000015103 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015104 array->set(index, clamped_value);
Steve Blocka7e24c12009-10-30 11:49:00 +000015105 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015106 return handle(Smi::FromInt(clamped_value), array->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015107}
15108
15109
Steve Block3ce2e202009-11-05 08:53:23 +000015110template<typename ExternalArrayClass, typename ValueType>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015111static Handle<Object> ExternalArrayIntSetter(
15112 Isolate* isolate,
15113 Handle<ExternalArrayClass> receiver,
15114 uint32_t index,
15115 Handle<Object> value) {
Steve Block3ce2e202009-11-05 08:53:23 +000015116 ValueType cast_value = 0;
15117 if (index < static_cast<uint32_t>(receiver->length())) {
15118 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015119 int int_value = Handle<Smi>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000015120 cast_value = static_cast<ValueType>(int_value);
15121 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015122 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000015123 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
15124 } else {
15125 // Clamp undefined to zero (default). All other types have been
15126 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015127 DCHECK(value->IsUndefined());
Steve Block3ce2e202009-11-05 08:53:23 +000015128 }
15129 receiver->set(index, cast_value);
15130 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015131 return isolate->factory()->NewNumberFromInt(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000015132}
15133
15134
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015135Handle<Object> ExternalInt8Array::SetValue(Handle<ExternalInt8Array> array,
15136 uint32_t index,
15137 Handle<Object> value) {
15138 return ExternalArrayIntSetter<ExternalInt8Array, int8_t>(
15139 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000015140}
15141
15142
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015143Handle<Object> ExternalUint8Array::SetValue(Handle<ExternalUint8Array> array,
15144 uint32_t index,
15145 Handle<Object> value) {
15146 return ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(
15147 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000015148}
15149
15150
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015151Handle<Object> ExternalInt16Array::SetValue(Handle<ExternalInt16Array> array,
15152 uint32_t index,
15153 Handle<Object> value) {
15154 return ExternalArrayIntSetter<ExternalInt16Array, int16_t>(
15155 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000015156}
15157
15158
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015159Handle<Object> ExternalUint16Array::SetValue(Handle<ExternalUint16Array> array,
15160 uint32_t index,
15161 Handle<Object> value) {
15162 return ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(
15163 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000015164}
15165
15166
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015167Handle<Object> ExternalInt32Array::SetValue(Handle<ExternalInt32Array> array,
15168 uint32_t index,
15169 Handle<Object> value) {
15170 return ExternalArrayIntSetter<ExternalInt32Array, int32_t>(
15171 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000015172}
15173
15174
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015175Handle<Object> ExternalUint32Array::SetValue(
15176 Handle<ExternalUint32Array> array,
15177 uint32_t index,
15178 Handle<Object> value) {
Steve Block3ce2e202009-11-05 08:53:23 +000015179 uint32_t cast_value = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015180 if (index < static_cast<uint32_t>(array->length())) {
Steve Block3ce2e202009-11-05 08:53:23 +000015181 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015182 int int_value = Handle<Smi>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000015183 cast_value = static_cast<uint32_t>(int_value);
15184 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015185 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000015186 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
15187 } else {
15188 // Clamp undefined to zero (default). All other types have been
15189 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015190 DCHECK(value->IsUndefined());
Steve Block3ce2e202009-11-05 08:53:23 +000015191 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015192 array->set(index, cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000015193 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015194 return array->GetIsolate()->factory()->NewNumberFromUint(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000015195}
15196
15197
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015198Handle<Object> ExternalFloat32Array::SetValue(
15199 Handle<ExternalFloat32Array> array,
15200 uint32_t index,
15201 Handle<Object> value) {
15202 float cast_value = static_cast<float>(base::OS::nan_value());
15203 if (index < static_cast<uint32_t>(array->length())) {
Steve Block3ce2e202009-11-05 08:53:23 +000015204 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015205 int int_value = Handle<Smi>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000015206 cast_value = static_cast<float>(int_value);
15207 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015208 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000015209 cast_value = static_cast<float>(double_value);
15210 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015211 // Clamp undefined to NaN (default). All other types have been
Steve Block3ce2e202009-11-05 08:53:23 +000015212 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015213 DCHECK(value->IsUndefined());
Steve Block3ce2e202009-11-05 08:53:23 +000015214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015215 array->set(index, cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000015216 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015217 return array->GetIsolate()->factory()->NewNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000015218}
15219
15220
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015221Handle<Object> ExternalFloat64Array::SetValue(
15222 Handle<ExternalFloat64Array> array,
15223 uint32_t index,
15224 Handle<Object> value) {
15225 double double_value = base::OS::nan_value();
15226 if (index < static_cast<uint32_t>(array->length())) {
15227 if (value->IsNumber()) {
15228 double_value = value->Number();
Ben Murdoch257744e2011-11-30 15:57:28 +000015229 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015230 // Clamp undefined to NaN (default). All other types have been
Ben Murdoch257744e2011-11-30 15:57:28 +000015231 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015232 DCHECK(value->IsUndefined());
Ben Murdoch257744e2011-11-30 15:57:28 +000015233 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015234 array->set(index, double_value);
Ben Murdoch257744e2011-11-30 15:57:28 +000015235 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015236 return array->GetIsolate()->factory()->NewNumber(double_value);
Ben Murdoch257744e2011-11-30 15:57:28 +000015237}
15238
15239
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015240void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
15241 Handle<Name> name) {
15242 DCHECK(!global->HasFastProperties());
15243 Isolate* isolate = global->GetIsolate();
15244 int entry = global->property_dictionary()->FindEntry(name);
15245 if (entry != NameDictionary::kNotFound) {
15246 Handle<PropertyCell> cell(
15247 PropertyCell::cast(global->property_dictionary()->ValueAt(entry)));
15248
15249 Handle<Object> value(cell->value(), isolate);
15250 Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(value);
15251 global->property_dictionary()->ValueAtPut(entry, *new_cell);
15252
15253 Handle<Object> hole = global->GetIsolate()->factory()->the_hole_value();
15254 PropertyCell::SetValueInferType(cell, hole);
15255 }
15256}
15257
15258
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015259Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
15260 Handle<JSGlobalObject> global,
15261 Handle<Name> name) {
15262 DCHECK(!global->HasFastProperties());
15263 int entry = global->property_dictionary()->FindEntry(name);
15264 if (entry == NameDictionary::kNotFound) {
15265 Isolate* isolate = global->GetIsolate();
15266 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
15267 isolate->factory()->the_hole_value());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015268 PropertyDetails details(NONE, FIELD, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000015269 details = details.AsDeleted();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015270 Handle<NameDictionary> dictionary = NameDictionary::Add(
15271 handle(global->property_dictionary()), name, cell, details);
15272 global->set_properties(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000015273 return cell;
15274 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015275 Object* value = global->property_dictionary()->ValueAt(entry);
15276 DCHECK(value->IsPropertyCell());
15277 return handle(PropertyCell::cast(value));
Steve Blocka7e24c12009-10-30 11:49:00 +000015278 }
15279}
15280
15281
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015282// This class is used for looking up two character strings in the string table.
Steve Blockd0582a62009-12-15 09:54:21 +000015283// If we don't have a hit we don't want to waste much time so we unroll the
15284// string hash calculation loop here for speed. Doesn't work if the two
15285// characters form a decimal integer, since such strings have a different hash
15286// algorithm.
15287class TwoCharHashTableKey : public HashTableKey {
15288 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015289 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000015290 : c1_(c1), c2_(c2) {
15291 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000015292 uint32_t hash = seed;
15293 hash += c1;
15294 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000015295 hash ^= hash >> 6;
15296 // Char 2.
15297 hash += c2;
15298 hash += hash << 10;
15299 hash ^= hash >> 6;
15300 // GetHash.
15301 hash += hash << 3;
15302 hash ^= hash >> 11;
15303 hash += hash << 15;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015304 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
15305 hash_ = hash;
Steve Blockd0582a62009-12-15 09:54:21 +000015306#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +000015307 // If this assert fails then we failed to reproduce the two-character
15308 // version of the string hashing algorithm above. One reason could be
15309 // that we were passed two digits as characters, since the hash
15310 // algorithm is different in that case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015311 uint16_t chars[2] = {c1, c2};
15312 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
15313 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
15314 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
Steve Blockd0582a62009-12-15 09:54:21 +000015315#endif
Steve Blockd0582a62009-12-15 09:54:21 +000015316 }
15317
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015318 bool IsMatch(Object* o) OVERRIDE {
Steve Blockd0582a62009-12-15 09:54:21 +000015319 if (!o->IsString()) return false;
15320 String* other = String::cast(o);
15321 if (other->length() != 2) return false;
15322 if (other->Get(0) != c1_) return false;
15323 return other->Get(1) == c2_;
15324 }
15325
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015326 uint32_t Hash() OVERRIDE { return hash_; }
15327 uint32_t HashForObject(Object* key) OVERRIDE {
Steve Blockd0582a62009-12-15 09:54:21 +000015328 if (!key->IsString()) return 0;
15329 return String::cast(key)->Hash();
15330 }
15331
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015332 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
15333 // The TwoCharHashTableKey is only used for looking in the string
Steve Blockd0582a62009-12-15 09:54:21 +000015334 // table, not for adding to it.
15335 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015336 return MaybeHandle<Object>().ToHandleChecked();
Steve Blockd0582a62009-12-15 09:54:21 +000015337 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015338
Steve Blockd0582a62009-12-15 09:54:21 +000015339 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015340 uint16_t c1_;
15341 uint16_t c2_;
Steve Blockd0582a62009-12-15 09:54:21 +000015342 uint32_t hash_;
15343};
15344
15345
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015346MaybeHandle<String> StringTable::InternalizeStringIfExists(
15347 Isolate* isolate,
15348 Handle<String> string) {
15349 if (string->IsInternalizedString()) {
15350 return string;
15351 }
15352 return LookupStringIfExists(isolate, string);
15353}
15354
15355
15356MaybeHandle<String> StringTable::LookupStringIfExists(
15357 Isolate* isolate,
15358 Handle<String> string) {
15359 Handle<StringTable> string_table = isolate->factory()->string_table();
15360 InternalizedStringKey key(string);
15361 int entry = string_table->FindEntry(&key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015362 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015363 return MaybeHandle<String>();
Steve Blocka7e24c12009-10-30 11:49:00 +000015364 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015365 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
15366 DCHECK(StringShape(*result).IsInternalized());
15367 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000015368 }
15369}
15370
15371
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015372MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
15373 Isolate* isolate,
15374 uint16_t c1,
15375 uint16_t c2) {
15376 Handle<StringTable> string_table = isolate->factory()->string_table();
15377 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
15378 int entry = string_table->FindEntry(&key);
Steve Blockd0582a62009-12-15 09:54:21 +000015379 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015380 return MaybeHandle<String>();
Steve Blockd0582a62009-12-15 09:54:21 +000015381 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015382 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
15383 DCHECK(StringShape(*result).IsInternalized());
15384 return result;
Steve Blockd0582a62009-12-15 09:54:21 +000015385 }
15386}
15387
15388
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015389void StringTable::EnsureCapacityForDeserialization(Isolate* isolate,
15390 int expected) {
15391 Handle<StringTable> table = isolate->factory()->string_table();
15392 // We need a key instance for the virtual hash function.
15393 InternalizedStringKey dummy_key(Handle<String>::null());
15394 table = StringTable::EnsureCapacity(table, expected, &dummy_key);
15395 isolate->factory()->set_string_table(table);
15396}
15397
15398
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015399Handle<String> StringTable::LookupString(Isolate* isolate,
15400 Handle<String> string) {
15401 InternalizedStringKey key(string);
15402 return LookupKey(isolate, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015403}
15404
15405
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015406Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
15407 Handle<StringTable> table = isolate->factory()->string_table();
15408 int entry = table->FindEntry(key);
Steve Block9fac8402011-05-12 15:51:54 +010015409
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015410 // String already in table.
Steve Blocka7e24c12009-10-30 11:49:00 +000015411 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015412 return handle(String::cast(table->KeyAt(entry)), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015413 }
15414
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015415 // Adding new string. Grow table if needed.
15416 table = StringTable::EnsureCapacity(table, 1, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015417
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015418 // Create string object.
15419 Handle<Object> string = key->AsHandle(isolate);
15420 // There must be no attempts to internalize strings that could throw
15421 // InvalidStringLength error.
15422 CHECK(!string.is_null());
Steve Blocka7e24c12009-10-30 11:49:00 +000015423
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015424 // Add the new string and return it along with the string table.
Steve Blocka7e24c12009-10-30 11:49:00 +000015425 entry = table->FindInsertionEntry(key->Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015426 table->set(EntryToIndex(entry), *string);
Steve Blocka7e24c12009-10-30 11:49:00 +000015427 table->ElementAdded();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015428
15429 isolate->factory()->set_string_table(table);
15430 return Handle<String>::cast(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000015431}
15432
15433
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015434Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
15435 Handle<Context> context) {
15436 Isolate* isolate = GetIsolate();
15437 Handle<SharedFunctionInfo> shared(context->closure()->shared());
15438 StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
15439 RelocInfo::kNoPosition);
Steve Blocka7e24c12009-10-30 11:49:00 +000015440 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015441 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015442 int index = EntryToIndex(entry);
15443 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
15444 return Handle<Object>(get(index + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015445}
15446
15447
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015448Handle<Object> CompilationCacheTable::LookupEval(
15449 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
15450 StrictMode strict_mode, int scope_position) {
15451 Isolate* isolate = GetIsolate();
15452 // Cache key is the tuple (source, outer shared function info, scope position)
15453 // to unambiguously identify the context chain the cached eval code assumes.
15454 StringSharedKey key(src, outer_info, strict_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000015455 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015456 if (entry == kNotFound) return isolate->factory()->undefined_value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015457 int index = EntryToIndex(entry);
15458 if (!get(index)->IsFixedArray()) return isolate->factory()->undefined_value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015459 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015460}
15461
15462
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015463Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
15464 JSRegExp::Flags flags) {
15465 Isolate* isolate = GetIsolate();
15466 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000015467 RegExpKey key(src, flags);
15468 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015469 if (entry == kNotFound) return isolate->factory()->undefined_value();
15470 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015471}
15472
15473
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015474Handle<CompilationCacheTable> CompilationCacheTable::Put(
15475 Handle<CompilationCacheTable> cache, Handle<String> src,
15476 Handle<Context> context, Handle<Object> value) {
15477 Isolate* isolate = cache->GetIsolate();
15478 Handle<SharedFunctionInfo> shared(context->closure()->shared());
15479 StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
15480 RelocInfo::kNoPosition);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015481 {
15482 Handle<Object> k = key.AsHandle(isolate);
15483 DisallowHeapAllocation no_allocation_scope;
15484 int entry = cache->FindEntry(&key);
15485 if (entry != kNotFound) {
15486 cache->set(EntryToIndex(entry), *k);
15487 cache->set(EntryToIndex(entry) + 1, *value);
15488 return cache;
15489 }
15490 }
15491
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015492 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015493 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015494 Handle<Object> k =
15495 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015496 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015497 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000015498 cache->ElementAdded();
15499 return cache;
15500}
15501
15502
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015503Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
15504 Handle<CompilationCacheTable> cache, Handle<String> src,
15505 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
15506 int scope_position) {
15507 Isolate* isolate = cache->GetIsolate();
15508 StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015509 {
15510 Handle<Object> k = key.AsHandle(isolate);
15511 DisallowHeapAllocation no_allocation_scope;
15512 int entry = cache->FindEntry(&key);
15513 if (entry != kNotFound) {
15514 cache->set(EntryToIndex(entry), *k);
15515 cache->set(EntryToIndex(entry) + 1, *value);
15516 return cache;
15517 }
15518 }
15519
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015520 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015521 int entry = cache->FindInsertionEntry(key.Hash());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015522 Handle<Object> k =
15523 isolate->factory()->NewNumber(static_cast<double>(key.Hash()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015524 cache->set(EntryToIndex(entry), *k);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015525 cache->set(EntryToIndex(entry) + 1, Smi::FromInt(kHashGenerations));
Steve Blocka7e24c12009-10-30 11:49:00 +000015526 cache->ElementAdded();
15527 return cache;
15528}
15529
15530
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015531Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
15532 Handle<CompilationCacheTable> cache, Handle<String> src,
15533 JSRegExp::Flags flags, Handle<FixedArray> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015534 RegExpKey key(src, flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015535 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015536 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000015537 // We store the value in the key slot, and compare the search key
15538 // to the stored value with a custon IsMatch function during lookups.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015539 cache->set(EntryToIndex(entry), *value);
15540 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000015541 cache->ElementAdded();
15542 return cache;
15543}
15544
15545
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015546void CompilationCacheTable::Age() {
15547 DisallowHeapAllocation no_allocation;
15548 Object* the_hole_value = GetHeap()->the_hole_value();
15549 for (int entry = 0, size = Capacity(); entry < size; entry++) {
15550 int entry_index = EntryToIndex(entry);
15551 int value_index = entry_index + 1;
15552
15553 if (get(entry_index)->IsNumber()) {
15554 Smi* count = Smi::cast(get(value_index));
15555 count = Smi::FromInt(count->value() - 1);
15556 if (count->value() == 0) {
15557 NoWriteBarrierSet(this, entry_index, the_hole_value);
15558 NoWriteBarrierSet(this, value_index, the_hole_value);
15559 ElementRemoved();
15560 } else {
15561 NoWriteBarrierSet(this, value_index, count);
15562 }
15563 } else if (get(entry_index)->IsFixedArray()) {
15564 SharedFunctionInfo* info = SharedFunctionInfo::cast(get(value_index));
15565 if (info->code()->kind() != Code::FUNCTION || info->code()->IsOld()) {
15566 NoWriteBarrierSet(this, entry_index, the_hole_value);
15567 NoWriteBarrierSet(this, value_index, the_hole_value);
15568 ElementRemoved();
15569 }
15570 }
15571 }
15572}
15573
15574
Ben Murdochb0fe1622011-05-05 13:52:32 +010015575void CompilationCacheTable::Remove(Object* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015576 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015577 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010015578 for (int entry = 0, size = Capacity(); entry < size; entry++) {
15579 int entry_index = EntryToIndex(entry);
15580 int value_index = entry_index + 1;
15581 if (get(value_index) == value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015582 NoWriteBarrierSet(this, entry_index, the_hole_value);
15583 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010015584 ElementRemoved();
15585 }
15586 }
15587 return;
15588}
15589
15590
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015591// StringsKey used for HashTable where key is array of internalized strings.
15592class StringsKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000015593 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015594 explicit StringsKey(Handle<FixedArray> strings) : strings_(strings) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000015595
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015596 bool IsMatch(Object* strings) OVERRIDE {
15597 FixedArray* o = FixedArray::cast(strings);
15598 int len = strings_->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000015599 if (o->length() != len) return false;
15600 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015601 if (o->get(i) != strings_->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000015602 }
15603 return true;
15604 }
15605
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015606 uint32_t Hash() OVERRIDE { return HashForObject(*strings_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000015607
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015608 uint32_t HashForObject(Object* obj) OVERRIDE {
15609 FixedArray* strings = FixedArray::cast(obj);
15610 int len = strings->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000015611 uint32_t hash = 0;
15612 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015613 hash ^= String::cast(strings->get(i))->Hash();
Steve Blocka7e24c12009-10-30 11:49:00 +000015614 }
15615 return hash;
15616 }
15617
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015618 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE { return strings_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000015619
15620 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015621 Handle<FixedArray> strings_;
Steve Blocka7e24c12009-10-30 11:49:00 +000015622};
15623
15624
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015625template<typename Derived, typename Shape, typename Key>
15626Handle<Derived> Dictionary<Derived, Shape, Key>::New(
15627 Isolate* isolate,
15628 int at_least_space_for,
15629 PretenureFlag pretenure) {
15630 DCHECK(0 <= at_least_space_for);
15631 Handle<Derived> dict = DerivedHashTable::New(isolate,
15632 at_least_space_for,
15633 USE_DEFAULT_MINIMUM_CAPACITY,
15634 pretenure);
15635
John Reck59135872010-11-02 12:39:01 -070015636 // Initialize the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015637 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
15638 return dict;
Steve Blocka7e24c12009-10-30 11:49:00 +000015639}
15640
15641
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015642template <typename Derived, typename Shape, typename Key>
15643Handle<FixedArray> Dictionary<Derived, Shape, Key>::BuildIterationIndicesArray(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015644 Handle<Derived> dictionary) {
15645 Factory* factory = dictionary->GetIsolate()->factory();
15646 int length = dictionary->NumberOfElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000015647
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015648 Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015649 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +000015650
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015651 // Fill both the iteration order array and the enumeration order array
15652 // with property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015653 int capacity = dictionary->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015654 int pos = 0;
15655 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015656 if (dictionary->IsKey(dictionary->KeyAt(i))) {
15657 int index = dictionary->DetailsAt(i).dictionary_index();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015658 iteration_order->set(pos, Smi::FromInt(i));
15659 enumeration_order->set(pos, Smi::FromInt(index));
15660 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000015661 }
15662 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015663 DCHECK(pos == length);
Steve Blocka7e24c12009-10-30 11:49:00 +000015664
15665 // Sort the arrays wrt. enumeration order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015666 iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015667 return iteration_order;
15668}
Steve Blocka7e24c12009-10-30 11:49:00 +000015669
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015670
15671template <typename Derived, typename Shape, typename Key>
15672Handle<FixedArray>
15673Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
15674 Handle<Derived> dictionary) {
15675 int length = dictionary->NumberOfElements();
15676
15677 Handle<FixedArray> iteration_order = BuildIterationIndicesArray(dictionary);
15678 DCHECK(iteration_order->length() == length);
15679
15680 // Iterate over the dictionary using the enumeration order and update
15681 // the dictionary with new enumeration indices.
Steve Blocka7e24c12009-10-30 11:49:00 +000015682 for (int i = 0; i < length; i++) {
15683 int index = Smi::cast(iteration_order->get(i))->value();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015684 DCHECK(dictionary->IsKey(dictionary->KeyAt(index)));
Steve Blocka7e24c12009-10-30 11:49:00 +000015685
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015686 int enum_index = PropertyDetails::kInitialIndex + i;
15687
15688 PropertyDetails details = dictionary->DetailsAt(index);
15689 PropertyDetails new_details =
15690 PropertyDetails(details.attributes(), details.type(), enum_index);
15691 dictionary->DetailsAtPut(index, new_details);
Steve Blocka7e24c12009-10-30 11:49:00 +000015692 }
15693
15694 // Set the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015695 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015696 return iteration_order;
Steve Blocka7e24c12009-10-30 11:49:00 +000015697}
15698
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015699
15700template<typename Derived, typename Shape, typename Key>
15701Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
15702 Handle<Derived> dictionary, int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015703 // Check whether there are enough enumeration indices to add n elements.
15704 if (Shape::kIsEnumerable &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015705 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015706 // If not, we generate new indices for the properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015707 GenerateNewEnumerationIndices(dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000015708 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015709 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015710}
15711
15712
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015713template<typename Derived, typename Shape, typename Key>
15714Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
15715 Handle<Derived> dictionary,
15716 int entry,
15717 JSObject::DeleteMode mode) {
15718 Factory* factory = dictionary->GetIsolate()->factory();
15719 PropertyDetails details = dictionary->DetailsAt(entry);
Steve Blocka7e24c12009-10-30 11:49:00 +000015720 // Ignore attributes if forcing a deletion.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015721 if (!details.IsConfigurable() && mode != JSReceiver::FORCE_DELETION) {
15722 return factory->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015724
15725 dictionary->SetEntry(
15726 entry, factory->the_hole_value(), factory->the_hole_value());
15727 dictionary->ElementRemoved();
15728 return factory->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015729}
15730
15731
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015732template<typename Derived, typename Shape, typename Key>
15733Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
15734 Handle<Derived> dictionary, Key key, Handle<Object> value) {
15735 int entry = dictionary->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015736
15737 // If the entry is present set the value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015738 if (entry != Dictionary::kNotFound) {
15739 dictionary->ValueAtPut(entry, *value);
15740 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000015741 }
15742
15743 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015744 dictionary = EnsureCapacity(dictionary, 1, key);
15745#ifdef DEBUG
15746 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
15747#endif
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015748 PropertyDetails details(NONE, FIELD, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000015749
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015750 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
15751 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000015752}
15753
15754
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015755template<typename Derived, typename Shape, typename Key>
15756Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
15757 Handle<Derived> dictionary,
15758 Key key,
15759 Handle<Object> value,
15760 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015761 // Valdate key is absent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015762 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000015763 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015764 dictionary = EnsureCapacity(dictionary, 1, key);
Ben Murdochc7cc0282012-03-05 14:35:55 +000015765
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015766 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
15767 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000015768}
15769
15770
15771// Add a key, value pair to the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015772template<typename Derived, typename Shape, typename Key>
15773void Dictionary<Derived, Shape, Key>::AddEntry(
15774 Handle<Derived> dictionary,
15775 Key key,
15776 Handle<Object> value,
15777 PropertyDetails details,
15778 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015779 // Compute the key object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015780 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015781
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015782 uint32_t entry = dictionary->FindInsertionEntry(hash);
Steve Blocka7e24c12009-10-30 11:49:00 +000015783 // Insert element at empty or deleted entry
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015784 if (!details.IsDeleted() &&
15785 details.dictionary_index() == 0 &&
15786 Shape::kIsEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015787 // Assign an enumeration index to the property and update
15788 // SetNextEnumerationIndex.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015789 int index = dictionary->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +000015790 details = PropertyDetails(details.attributes(), details.type(), index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015791 dictionary->SetNextEnumerationIndex(index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000015792 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015793 dictionary->SetEntry(entry, k, value, details);
15794 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
15795 dictionary->KeyAt(entry)->IsName()));
15796 dictionary->ElementAdded();
Steve Blocka7e24c12009-10-30 11:49:00 +000015797}
15798
15799
Ben Murdochc7cc0282012-03-05 14:35:55 +000015800void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015801 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000015802 // If the dictionary requires slow elements an element has already
15803 // been added at a high index.
15804 if (requires_slow_elements()) return;
15805 // Check if this index is high enough that we should require slow
15806 // elements.
15807 if (key > kRequiresSlowElementsLimit) {
15808 set_requires_slow_elements();
15809 return;
15810 }
15811 // Update max key value.
15812 Object* max_index_object = get(kMaxNumberKeyIndex);
15813 if (!max_index_object->IsSmi() || max_number_key() < key) {
15814 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000015815 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000015816 }
15817}
15818
15819
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015820Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
15821 Handle<SeededNumberDictionary> dictionary,
15822 uint32_t key,
15823 Handle<Object> value,
15824 PropertyDetails details) {
15825 dictionary->UpdateMaxNumberKey(key);
15826 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
15827 return Add(dictionary, key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000015828}
15829
15830
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015831Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
15832 Handle<UnseededNumberDictionary> dictionary,
15833 uint32_t key,
15834 Handle<Object> value) {
15835 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015836 return Add(dictionary, key, value, PropertyDetails(NONE, FIELD, 0));
Ben Murdochc7cc0282012-03-05 14:35:55 +000015837}
15838
15839
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015840Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
15841 Handle<SeededNumberDictionary> dictionary,
15842 uint32_t key,
15843 Handle<Object> value) {
15844 dictionary->UpdateMaxNumberKey(key);
15845 return AtPut(dictionary, key, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000015846}
15847
15848
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015849Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
15850 Handle<UnseededNumberDictionary> dictionary,
15851 uint32_t key,
15852 Handle<Object> value) {
15853 return AtPut(dictionary, key, value);
Ben Murdochc7cc0282012-03-05 14:35:55 +000015854}
15855
15856
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015857Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
15858 Handle<SeededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015859 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015860 Handle<Object> value,
15861 PropertyDetails details) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015862 int entry = dictionary->FindEntry(key);
15863 if (entry == kNotFound) {
15864 return AddNumberEntry(dictionary, key, value, details);
15865 }
15866 // Preserve enumeration index.
15867 details = PropertyDetails(details.attributes(),
15868 details.type(),
15869 dictionary->DetailsAt(entry).dictionary_index());
15870 Handle<Object> object_key =
15871 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15872 dictionary->SetEntry(entry, object_key, value, details);
15873 return dictionary;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015874}
15875
15876
15877Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
15878 Handle<UnseededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015879 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015880 Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015881 int entry = dictionary->FindEntry(key);
15882 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
15883 Handle<Object> object_key =
15884 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15885 dictionary->SetEntry(entry, object_key, value);
15886 return dictionary;
Ben Murdochc7cc0282012-03-05 14:35:55 +000015887}
15888
15889
Steve Blocka7e24c12009-10-30 11:49:00 +000015890
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015891template<typename Derived, typename Shape, typename Key>
15892int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +000015893 PropertyAttributes filter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015894 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015895 int result = 0;
15896 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015897 Object* k = DerivedHashTable::KeyAt(i);
15898 if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015899 PropertyDetails details = DetailsAt(i);
15900 if (details.IsDeleted()) continue;
15901 PropertyAttributes attr = details.attributes();
15902 if ((attr & filter) == 0) result++;
15903 }
15904 }
15905 return result;
15906}
15907
15908
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015909template<typename Derived, typename Shape, typename Key>
15910int Dictionary<Derived, Shape, Key>::NumberOfEnumElements() {
Steve Blocka7e24c12009-10-30 11:49:00 +000015911 return NumberOfElementsFilterAttributes(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015912 static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
Steve Blocka7e24c12009-10-30 11:49:00 +000015913}
15914
15915
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015916template <typename Derived, typename Shape, typename Key>
15917bool Dictionary<Derived, Shape, Key>::HasComplexElements() {
15918 int capacity = DerivedHashTable::Capacity();
15919 for (int i = 0; i < capacity; i++) {
15920 Object* k = DerivedHashTable::KeyAt(i);
15921 if (DerivedHashTable::IsKey(k) && !FilterKey(k, NONE)) {
15922 PropertyDetails details = DetailsAt(i);
15923 if (details.IsDeleted()) continue;
15924 if (details.type() == CALLBACKS) return true;
15925 PropertyAttributes attr = details.attributes();
15926 if (attr & (READ_ONLY | DONT_DELETE | DONT_ENUM)) return true;
15927 }
15928 }
15929 return false;
15930}
15931
15932
15933template <typename Derived, typename Shape, typename Key>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015934void Dictionary<Derived, Shape, Key>::CopyKeysTo(
Emily Bernierd0a1eb72015-03-24 16:35:39 -040015935 FixedArray* storage, PropertyAttributes filter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015936 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15937 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
15938 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015939 int index = 0;
15940 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015941 Object* k = DerivedHashTable::KeyAt(i);
15942 if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015943 PropertyDetails details = DetailsAt(i);
15944 if (details.IsDeleted()) continue;
15945 PropertyAttributes attr = details.attributes();
15946 if ((attr & filter) == 0) storage->set(index++, k);
15947 }
15948 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015949 if (sort_mode == Dictionary::SORTED) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015950 storage->SortPairs(storage, index);
15951 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015952 DCHECK(storage->length() >= index);
Steve Blocka7e24c12009-10-30 11:49:00 +000015953}
15954
15955
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015956struct EnumIndexComparator {
15957 explicit EnumIndexComparator(NameDictionary* dict) : dict(dict) { }
15958 bool operator() (Smi* a, Smi* b) {
15959 PropertyDetails da(dict->DetailsAt(a->value()));
15960 PropertyDetails db(dict->DetailsAt(b->value()));
15961 return da.dictionary_index() < db.dictionary_index();
15962 }
15963 NameDictionary* dict;
15964};
15965
15966
15967void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
15968 int length = storage->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000015969 int capacity = Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015970 int properties = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000015971 for (int i = 0; i < capacity; i++) {
15972 Object* k = KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015973 if (IsKey(k) && !k->IsSymbol()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015974 PropertyDetails details = DetailsAt(i);
15975 if (details.IsDeleted() || details.IsDontEnum()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015976 storage->set(properties, Smi::FromInt(i));
15977 properties++;
15978 if (properties == length) break;
Steve Blocka7e24c12009-10-30 11:49:00 +000015979 }
15980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015981 CHECK_EQ(length, properties);
15982 EnumIndexComparator cmp(this);
15983 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
15984 std::sort(start, start + length, cmp);
15985 for (int i = 0; i < length; i++) {
15986 int index = Smi::cast(storage->get(i))->value();
15987 storage->set(i, KeyAt(index));
15988 }
Steve Blocka7e24c12009-10-30 11:49:00 +000015989}
15990
15991
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015992template<typename Derived, typename Shape, typename Key>
15993void Dictionary<Derived, Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000015994 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015995 int index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015996 PropertyAttributes filter,
15997 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15998 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
15999 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000016000 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016001 Object* k = DerivedHashTable::KeyAt(i);
16002 if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016003 PropertyDetails details = DetailsAt(i);
16004 if (details.IsDeleted()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016005 PropertyAttributes attr = details.attributes();
16006 if ((attr & filter) == 0) storage->set(index++, k);
Steve Blocka7e24c12009-10-30 11:49:00 +000016007 }
16008 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016009 if (sort_mode == Dictionary::SORTED) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000016010 storage->SortPairs(storage, index);
16011 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016012 DCHECK(storage->length() >= index);
Steve Blocka7e24c12009-10-30 11:49:00 +000016013}
16014
16015
16016// Backwards lookup (slow).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016017template<typename Derived, typename Shape, typename Key>
16018Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
16019 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000016020 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016021 Object* k = DerivedHashTable::KeyAt(i);
16022 if (Dictionary::IsKey(k)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000016023 Object* e = ValueAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016024 if (e->IsPropertyCell()) {
16025 e = PropertyCell::cast(e)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016026 }
16027 if (e == value) return k;
16028 }
16029 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016030 Heap* heap = Dictionary::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010016031 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016032}
16033
16034
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016035Object* ObjectHashTable::Lookup(Handle<Object> key) {
16036 DisallowHeapAllocation no_gc;
16037 DCHECK(IsKey(*key));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016038
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016039 // If the object does not have an identity hash, it was never used as a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016040 Object* hash = key->GetHash();
16041 if (hash->IsUndefined()) {
16042 return GetHeap()->the_hole_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016043 }
16044 int entry = FindEntry(key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016045 if (entry == kNotFound) return GetHeap()->the_hole_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016046 return get(EntryToIndex(entry) + 1);
16047}
16048
16049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016050Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
16051 Handle<Object> key,
16052 Handle<Object> value) {
16053 DCHECK(table->IsKey(*key));
16054 DCHECK(!value->IsTheHole());
16055
16056 Isolate* isolate = table->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016057
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016058 // Make sure the key object has an identity hash code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016059 Handle<Smi> hash = Object::GetOrCreateHash(isolate, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016061 int entry = table->FindEntry(key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016062
16063 // Key is already in table, just overwrite value.
16064 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016065 table->set(EntryToIndex(entry) + 1, *value);
16066 return table;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016067 }
16068
16069 // Check whether the hash table should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016070 table = EnsureCapacity(table, 1, key);
16071 table->AddEntry(table->FindInsertionEntry(hash->value()),
16072 *key,
16073 *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016074 return table;
16075}
16076
16077
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016078Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
16079 Handle<Object> key,
16080 bool* was_present) {
16081 DCHECK(table->IsKey(*key));
16082
16083 Object* hash = key->GetHash();
16084 if (hash->IsUndefined()) {
16085 *was_present = false;
16086 return table;
16087 }
16088
16089 int entry = table->FindEntry(key);
16090 if (entry == kNotFound) {
16091 *was_present = false;
16092 return table;
16093 }
16094
16095 *was_present = true;
16096 table->RemoveEntry(entry);
16097 return Shrink(table, key);
16098}
16099
16100
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016101void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016102 set(EntryToIndex(entry), key);
16103 set(EntryToIndex(entry) + 1, value);
16104 ElementAdded();
16105}
16106
16107
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016108void ObjectHashTable::RemoveEntry(int entry) {
16109 set_the_hole(EntryToIndex(entry));
16110 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016111 ElementRemoved();
16112}
16113
16114
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016115Object* WeakHashTable::Lookup(Handle<Object> key) {
16116 DisallowHeapAllocation no_gc;
16117 DCHECK(IsKey(*key));
16118 int entry = FindEntry(key);
16119 if (entry == kNotFound) return GetHeap()->the_hole_value();
16120 return get(EntryToValueIndex(entry));
16121}
16122
16123
16124Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
16125 Handle<Object> key,
16126 Handle<Object> value) {
16127 DCHECK(table->IsKey(*key));
16128 int entry = table->FindEntry(key);
16129 // Key is already in table, just overwrite value.
16130 if (entry != kNotFound) {
16131 // TODO(ulan): Skipping write barrier is a temporary solution to avoid
16132 // memory leaks. Remove this once we have special visitor for weak fixed
16133 // arrays.
16134 table->set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
16135 return table;
16136 }
16137
16138 // Check whether the hash table should be extended.
16139 table = EnsureCapacity(table, 1, key, TENURED);
16140
16141 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key, value);
16142 return table;
16143}
16144
16145
16146void WeakHashTable::AddEntry(int entry,
16147 Handle<Object> key,
16148 Handle<Object> value) {
16149 DisallowHeapAllocation no_allocation;
16150 // TODO(ulan): Skipping write barrier is a temporary solution to avoid
16151 // memory leaks. Remove this once we have special visitor for weak fixed
16152 // arrays.
16153 set(EntryToIndex(entry), *key, SKIP_WRITE_BARRIER);
16154 set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
16155 ElementAdded();
16156}
16157
16158
16159template<class Derived, class Iterator, int entrysize>
16160Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
16161 Isolate* isolate, int capacity, PretenureFlag pretenure) {
16162 // Capacity must be a power of two, since we depend on being able
16163 // to divide and multiple by 2 (kLoadFactor) to derive capacity
16164 // from number of buckets. If we decide to change kLoadFactor
16165 // to something other than 2, capacity should be stored as another
16166 // field of this object.
16167 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
16168 if (capacity > kMaxCapacity) {
16169 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
16170 }
16171 int num_buckets = capacity / kLoadFactor;
16172 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
16173 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
16174 backing_store->set_map_no_write_barrier(
16175 isolate->heap()->ordered_hash_table_map());
16176 Handle<Derived> table = Handle<Derived>::cast(backing_store);
16177 for (int i = 0; i < num_buckets; ++i) {
16178 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
16179 }
16180 table->SetNumberOfBuckets(num_buckets);
16181 table->SetNumberOfElements(0);
16182 table->SetNumberOfDeletedElements(0);
16183 return table;
16184}
16185
16186
16187template<class Derived, class Iterator, int entrysize>
16188Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
16189 Handle<Derived> table) {
16190 DCHECK(!table->IsObsolete());
16191
16192 int nof = table->NumberOfElements();
16193 int nod = table->NumberOfDeletedElements();
16194 int capacity = table->Capacity();
16195 if ((nof + nod) < capacity) return table;
16196 // Don't need to grow if we can simply clear out deleted entries instead.
16197 // Note that we can't compact in place, though, so we always allocate
16198 // a new table.
16199 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
16200}
16201
16202
16203template<class Derived, class Iterator, int entrysize>
16204Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
16205 Handle<Derived> table) {
16206 DCHECK(!table->IsObsolete());
16207
16208 int nof = table->NumberOfElements();
16209 int capacity = table->Capacity();
16210 if (nof >= (capacity >> 2)) return table;
16211 return Rehash(table, capacity / 2);
16212}
16213
16214
16215template<class Derived, class Iterator, int entrysize>
16216Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
16217 Handle<Derived> table) {
16218 DCHECK(!table->IsObsolete());
16219
16220 Handle<Derived> new_table =
16221 Allocate(table->GetIsolate(),
16222 kMinCapacity,
16223 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
16224
16225 table->SetNextTable(*new_table);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016226 table->SetNumberOfDeletedElements(kClearedTableSentinel);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016227
16228 return new_table;
16229}
16230
16231
16232template<class Derived, class Iterator, int entrysize>
16233Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Remove(
16234 Handle<Derived> table, Handle<Object> key, bool* was_present) {
16235 int entry = table->FindEntry(key);
16236 if (entry == kNotFound) {
16237 *was_present = false;
16238 return table;
16239 }
16240 *was_present = true;
16241 table->RemoveEntry(entry);
16242 return Shrink(table);
16243}
16244
16245
16246template<class Derived, class Iterator, int entrysize>
16247Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
16248 Handle<Derived> table, int new_capacity) {
16249 DCHECK(!table->IsObsolete());
16250
16251 Handle<Derived> new_table =
16252 Allocate(table->GetIsolate(),
16253 new_capacity,
16254 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
16255 int nof = table->NumberOfElements();
16256 int nod = table->NumberOfDeletedElements();
16257 int new_buckets = new_table->NumberOfBuckets();
16258 int new_entry = 0;
16259 int removed_holes_index = 0;
16260
16261 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
16262 Object* key = table->KeyAt(old_entry);
16263 if (key->IsTheHole()) {
16264 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
16265 continue;
16266 }
16267
16268 Object* hash = key->GetHash();
16269 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
16270 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
16271 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
16272 int new_index = new_table->EntryToIndex(new_entry);
16273 int old_index = table->EntryToIndex(old_entry);
16274 for (int i = 0; i < entrysize; ++i) {
16275 Object* value = table->get(old_index + i);
16276 new_table->set(new_index + i, value);
16277 }
16278 new_table->set(new_index + kChainOffset, chain_entry);
16279 ++new_entry;
16280 }
16281
16282 DCHECK_EQ(nod, removed_holes_index);
16283
16284 new_table->SetNumberOfElements(nof);
16285 table->SetNextTable(*new_table);
16286
16287 return new_table;
16288}
16289
16290
16291template <class Derived, class Iterator, int entrysize>
16292int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
16293 Handle<Object> key, int hash) {
16294 DCHECK(!IsObsolete());
16295
16296 DisallowHeapAllocation no_gc;
16297 DCHECK(!key->IsTheHole());
16298 for (int entry = HashToEntry(hash); entry != kNotFound;
16299 entry = ChainAt(entry)) {
16300 Object* candidate = KeyAt(entry);
16301 if (candidate->SameValueZero(*key))
16302 return entry;
16303 }
16304 return kNotFound;
16305}
16306
16307
16308template <class Derived, class Iterator, int entrysize>
16309int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
16310 Handle<Object> key) {
16311 DisallowHeapAllocation no_gc;
16312 Object* hash = key->GetHash();
16313 if (!hash->IsSmi()) return kNotFound;
16314 return FindEntry(key, Smi::cast(hash)->value());
16315}
16316
16317
16318template <class Derived, class Iterator, int entrysize>
16319int OrderedHashTable<Derived, Iterator, entrysize>::AddEntry(int hash) {
16320 DCHECK(!IsObsolete());
16321
16322 int entry = UsedCapacity();
16323 int bucket = HashToBucket(hash);
16324 int index = EntryToIndex(entry);
16325 Object* chain_entry = get(kHashTableStartIndex + bucket);
16326 set(kHashTableStartIndex + bucket, Smi::FromInt(entry));
16327 set(index + kChainOffset, chain_entry);
16328 SetNumberOfElements(NumberOfElements() + 1);
16329 return index;
16330}
16331
16332
16333template<class Derived, class Iterator, int entrysize>
16334void OrderedHashTable<Derived, Iterator, entrysize>::RemoveEntry(int entry) {
16335 DCHECK(!IsObsolete());
16336
16337 int index = EntryToIndex(entry);
16338 for (int i = 0; i < entrysize; ++i) {
16339 set_the_hole(index + i);
16340 }
16341 SetNumberOfElements(NumberOfElements() - 1);
16342 SetNumberOfDeletedElements(NumberOfDeletedElements() + 1);
16343}
16344
16345
16346template Handle<OrderedHashSet>
16347OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
16348 Isolate* isolate, int capacity, PretenureFlag pretenure);
16349
16350template Handle<OrderedHashSet>
16351OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
16352 Handle<OrderedHashSet> table);
16353
16354template Handle<OrderedHashSet>
16355OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
16356 Handle<OrderedHashSet> table);
16357
16358template Handle<OrderedHashSet>
16359OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
16360 Handle<OrderedHashSet> table);
16361
16362template Handle<OrderedHashSet>
16363OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Remove(
16364 Handle<OrderedHashSet> table, Handle<Object> key, bool* was_present);
16365
16366template int OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
16367 Handle<Object> key, int hash);
16368template int OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
16369 Handle<Object> key);
16370
16371template int
16372OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::AddEntry(int hash);
16373
16374template void
16375OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::RemoveEntry(int entry);
16376
16377
16378template Handle<OrderedHashMap>
16379OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
16380 Isolate* isolate, int capacity, PretenureFlag pretenure);
16381
16382template Handle<OrderedHashMap>
16383OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
16384 Handle<OrderedHashMap> table);
16385
16386template Handle<OrderedHashMap>
16387OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
16388 Handle<OrderedHashMap> table);
16389
16390template Handle<OrderedHashMap>
16391OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
16392 Handle<OrderedHashMap> table);
16393
16394template Handle<OrderedHashMap>
16395OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Remove(
16396 Handle<OrderedHashMap> table, Handle<Object> key, bool* was_present);
16397
16398template int OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
16399 Handle<Object> key, int hash);
16400template int OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
16401 Handle<Object> key);
16402
16403template int
16404OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::AddEntry(int hash);
16405
16406template void
16407OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::RemoveEntry(int entry);
16408
16409
16410bool OrderedHashSet::Contains(Handle<Object> key) {
16411 return FindEntry(key) != kNotFound;
16412}
16413
16414
16415Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
16416 Handle<Object> key) {
16417 int hash = GetOrCreateHash(table->GetIsolate(), key)->value();
16418 if (table->FindEntry(key, hash) != kNotFound) return table;
16419
16420 table = EnsureGrowable(table);
16421
16422 int index = table->AddEntry(hash);
16423 table->set(index, *key);
16424 return table;
16425}
16426
16427
16428Object* OrderedHashMap::Lookup(Handle<Object> key) {
16429 DisallowHeapAllocation no_gc;
16430 int entry = FindEntry(key);
16431 if (entry == kNotFound) return GetHeap()->the_hole_value();
16432 return ValueAt(entry);
16433}
16434
16435
16436Handle<OrderedHashMap> OrderedHashMap::Put(Handle<OrderedHashMap> table,
16437 Handle<Object> key,
16438 Handle<Object> value) {
16439 DCHECK(!key->IsTheHole());
16440
16441 int hash = GetOrCreateHash(table->GetIsolate(), key)->value();
16442 int entry = table->FindEntry(key, hash);
16443
16444 if (entry != kNotFound) {
16445 table->set(table->EntryToIndex(entry) + kValueOffset, *value);
16446 return table;
16447 }
16448
16449 table = EnsureGrowable(table);
16450
16451 int index = table->AddEntry(hash);
16452 table->set(index, *key);
16453 table->set(index + kValueOffset, *value);
16454 return table;
16455}
16456
16457
16458template<class Derived, class TableType>
16459void OrderedHashTableIterator<Derived, TableType>::Transition() {
16460 DisallowHeapAllocation no_allocation;
16461 TableType* table = TableType::cast(this->table());
16462 if (!table->IsObsolete()) return;
16463
16464 int index = Smi::cast(this->index())->value();
16465 while (table->IsObsolete()) {
16466 TableType* next_table = table->NextTable();
16467
16468 if (index > 0) {
16469 int nod = table->NumberOfDeletedElements();
16470
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016471 if (nod == TableType::kClearedTableSentinel) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016472 index = 0;
16473 } else {
16474 int old_index = index;
16475 for (int i = 0; i < nod; ++i) {
16476 int removed_index = table->RemovedIndexAt(i);
16477 if (removed_index >= old_index) break;
16478 --index;
16479 }
16480 }
16481 }
16482
16483 table = next_table;
16484 }
16485
16486 set_table(table);
16487 set_index(Smi::FromInt(index));
16488}
16489
16490
16491template<class Derived, class TableType>
16492bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
16493 DisallowHeapAllocation no_allocation;
16494 if (this->table()->IsUndefined()) return false;
16495
16496 Transition();
16497
16498 TableType* table = TableType::cast(this->table());
16499 int index = Smi::cast(this->index())->value();
16500 int used_capacity = table->UsedCapacity();
16501
16502 while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
16503 index++;
16504 }
16505
16506 set_index(Smi::FromInt(index));
16507
16508 if (index < used_capacity) return true;
16509
16510 set_table(GetHeap()->undefined_value());
16511 return false;
16512}
16513
16514
16515template<class Derived, class TableType>
16516Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
16517 DisallowHeapAllocation no_allocation;
16518 if (HasMore()) {
16519 FixedArray* array = FixedArray::cast(value_array->elements());
16520 static_cast<Derived*>(this)->PopulateValueArray(array);
16521 MoveNext();
16522 return Smi::cast(kind());
16523 }
16524 return Smi::FromInt(0);
16525}
16526
16527
16528template Smi*
16529OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
16530 JSArray* value_array);
16531
16532template bool
16533OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
16534
16535template void
16536OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
16537
16538template Object*
16539OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
16540
16541template void
16542OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
16543
16544
16545template Smi*
16546OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
16547 JSArray* value_array);
16548
16549template bool
16550OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
16551
16552template void
16553OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
16554
16555template Object*
16556OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
16557
16558template void
16559OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
16560
16561
16562DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
16563 DeclaredAccessorDescriptor* descriptor)
16564 : array_(descriptor->serialized_data()->GetDataStartAddress()),
16565 length_(descriptor->serialized_data()->length()),
16566 offset_(0) {
16567}
16568
16569
16570const DeclaredAccessorDescriptorData*
16571 DeclaredAccessorDescriptorIterator::Next() {
16572 DCHECK(offset_ < length_);
16573 uint8_t* ptr = &array_[offset_];
16574 DCHECK(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
16575 const DeclaredAccessorDescriptorData* data =
16576 reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
16577 offset_ += sizeof(*data);
16578 DCHECK(offset_ <= length_);
16579 return data;
16580}
16581
16582
16583Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
16584 Isolate* isolate,
16585 const DeclaredAccessorDescriptorData& descriptor,
16586 Handle<DeclaredAccessorDescriptor> previous) {
16587 int previous_length =
16588 previous.is_null() ? 0 : previous->serialized_data()->length();
16589 int length = sizeof(descriptor) + previous_length;
16590 Handle<ByteArray> serialized_descriptor =
16591 isolate->factory()->NewByteArray(length);
16592 Handle<DeclaredAccessorDescriptor> value =
16593 isolate->factory()->NewDeclaredAccessorDescriptor();
16594 value->set_serialized_data(*serialized_descriptor);
16595 // Copy in the data.
16596 {
16597 DisallowHeapAllocation no_allocation;
16598 uint8_t* array = serialized_descriptor->GetDataStartAddress();
16599 if (previous_length != 0) {
16600 uint8_t* previous_array =
16601 previous->serialized_data()->GetDataStartAddress();
16602 MemCopy(array, previous_array, previous_length);
16603 array += previous_length;
16604 }
16605 DCHECK(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
16606 DeclaredAccessorDescriptorData* data =
16607 reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
16608 *data = descriptor;
16609 }
16610 return value;
16611}
16612
16613
Steve Blocka7e24c12009-10-30 11:49:00 +000016614// Check if there is a break point at this code position.
16615bool DebugInfo::HasBreakPoint(int code_position) {
16616 // Get the break point info object for this code position.
16617 Object* break_point_info = GetBreakPointInfo(code_position);
16618
16619 // If there is no break point info object or no break points in the break
16620 // point info object there is no break point at this code position.
16621 if (break_point_info->IsUndefined()) return false;
16622 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
16623}
16624
16625
16626// Get the break point info object for this code position.
16627Object* DebugInfo::GetBreakPointInfo(int code_position) {
16628 // Find the index of the break point info object for this code position.
16629 int index = GetBreakPointInfoIndex(code_position);
16630
16631 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010016632 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016633 return BreakPointInfo::cast(break_points()->get(index));
16634}
16635
16636
16637// Clear a break point at the specified code position.
16638void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
16639 int code_position,
16640 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016641 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
16642 debug_info->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000016643 if (break_point_info->IsUndefined()) return;
16644 BreakPointInfo::ClearBreakPoint(
16645 Handle<BreakPointInfo>::cast(break_point_info),
16646 break_point_object);
16647}
16648
16649
16650void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
16651 int code_position,
16652 int source_position,
16653 int statement_position,
16654 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016655 Isolate* isolate = debug_info->GetIsolate();
16656 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
16657 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000016658 if (!break_point_info->IsUndefined()) {
16659 BreakPointInfo::SetBreakPoint(
16660 Handle<BreakPointInfo>::cast(break_point_info),
16661 break_point_object);
16662 return;
16663 }
16664
16665 // Adding a new break point for a code position which did not have any
16666 // break points before. Try to find a free slot.
16667 int index = kNoBreakPointInfo;
16668 for (int i = 0; i < debug_info->break_points()->length(); i++) {
16669 if (debug_info->break_points()->get(i)->IsUndefined()) {
16670 index = i;
16671 break;
16672 }
16673 }
16674 if (index == kNoBreakPointInfo) {
16675 // No free slot - extend break point info array.
16676 Handle<FixedArray> old_break_points =
16677 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000016678 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010016679 isolate->factory()->NewFixedArray(
16680 old_break_points->length() +
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016681 DebugInfo::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010016682
16683 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000016684 for (int i = 0; i < old_break_points->length(); i++) {
16685 new_break_points->set(i, old_break_points->get(i));
16686 }
16687 index = old_break_points->length();
16688 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016689 DCHECK(index != kNoBreakPointInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +000016690
16691 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010016692 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
16693 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000016694 new_break_point_info->set_code_position(Smi::FromInt(code_position));
16695 new_break_point_info->set_source_position(Smi::FromInt(source_position));
16696 new_break_point_info->
16697 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010016698 new_break_point_info->set_break_point_objects(
16699 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000016700 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
16701 debug_info->break_points()->set(index, *new_break_point_info);
16702}
16703
16704
16705// Get the break point objects for a code position.
16706Object* DebugInfo::GetBreakPointObjects(int code_position) {
16707 Object* break_point_info = GetBreakPointInfo(code_position);
16708 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010016709 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016710 }
16711 return BreakPointInfo::cast(break_point_info)->break_point_objects();
16712}
16713
16714
16715// Get the total number of break points.
16716int DebugInfo::GetBreakPointCount() {
16717 if (break_points()->IsUndefined()) return 0;
16718 int count = 0;
16719 for (int i = 0; i < break_points()->length(); i++) {
16720 if (!break_points()->get(i)->IsUndefined()) {
16721 BreakPointInfo* break_point_info =
16722 BreakPointInfo::cast(break_points()->get(i));
16723 count += break_point_info->GetBreakPointCount();
16724 }
16725 }
16726 return count;
16727}
16728
16729
16730Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
16731 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010016732 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010016733 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016734 for (int i = 0; i < debug_info->break_points()->length(); i++) {
16735 if (!debug_info->break_points()->get(i)->IsUndefined()) {
16736 Handle<BreakPointInfo> break_point_info =
16737 Handle<BreakPointInfo>(BreakPointInfo::cast(
16738 debug_info->break_points()->get(i)));
16739 if (BreakPointInfo::HasBreakPointObject(break_point_info,
16740 break_point_object)) {
16741 return *break_point_info;
16742 }
16743 }
16744 }
Steve Block44f0eee2011-05-26 01:26:41 +010016745 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000016746}
16747
16748
16749// Find the index of the break point info object for the specified code
16750// position.
16751int DebugInfo::GetBreakPointInfoIndex(int code_position) {
16752 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
16753 for (int i = 0; i < break_points()->length(); i++) {
16754 if (!break_points()->get(i)->IsUndefined()) {
16755 BreakPointInfo* break_point_info =
16756 BreakPointInfo::cast(break_points()->get(i));
16757 if (break_point_info->code_position()->value() == code_position) {
16758 return i;
16759 }
16760 }
16761 }
16762 return kNoBreakPointInfo;
16763}
16764
16765
16766// Remove the specified break point object.
16767void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
16768 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016769 Isolate* isolate = break_point_info->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000016770 // If there are no break points just ignore.
16771 if (break_point_info->break_point_objects()->IsUndefined()) return;
16772 // If there is a single break point clear it if it is the same.
16773 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16774 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010016775 break_point_info->set_break_point_objects(
16776 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000016777 }
16778 return;
16779 }
16780 // If there are multiple break points shrink the array
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016781 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +000016782 Handle<FixedArray> old_array =
16783 Handle<FixedArray>(
16784 FixedArray::cast(break_point_info->break_point_objects()));
16785 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010016786 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016787 int found_count = 0;
16788 for (int i = 0; i < old_array->length(); i++) {
16789 if (old_array->get(i) == *break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016790 DCHECK(found_count == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000016791 found_count++;
16792 } else {
16793 new_array->set(i - found_count, old_array->get(i));
16794 }
16795 }
16796 // If the break point was found in the list change it.
16797 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
16798}
16799
16800
16801// Add the specified break point object.
16802void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
16803 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016804 Isolate* isolate = break_point_info->GetIsolate();
16805
Steve Blocka7e24c12009-10-30 11:49:00 +000016806 // If there was no break point objects before just set it.
16807 if (break_point_info->break_point_objects()->IsUndefined()) {
16808 break_point_info->set_break_point_objects(*break_point_object);
16809 return;
16810 }
16811 // If the break point object is the same as before just ignore.
16812 if (break_point_info->break_point_objects() == *break_point_object) return;
16813 // If there was one break point object before replace with array.
16814 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016815 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000016816 array->set(0, break_point_info->break_point_objects());
16817 array->set(1, *break_point_object);
16818 break_point_info->set_break_point_objects(*array);
16819 return;
16820 }
16821 // If there was more than one break point before extend array.
16822 Handle<FixedArray> old_array =
16823 Handle<FixedArray>(
16824 FixedArray::cast(break_point_info->break_point_objects()));
16825 Handle<FixedArray> new_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016826 isolate->factory()->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016827 for (int i = 0; i < old_array->length(); i++) {
16828 // If the break point was there before just ignore.
16829 if (old_array->get(i) == *break_point_object) return;
16830 new_array->set(i, old_array->get(i));
16831 }
16832 // Add the new break point.
16833 new_array->set(old_array->length(), *break_point_object);
16834 break_point_info->set_break_point_objects(*new_array);
16835}
16836
16837
16838bool BreakPointInfo::HasBreakPointObject(
16839 Handle<BreakPointInfo> break_point_info,
16840 Handle<Object> break_point_object) {
16841 // No break point.
16842 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016843 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000016844 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16845 return break_point_info->break_point_objects() == *break_point_object;
16846 }
16847 // Multiple break points.
16848 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
16849 for (int i = 0; i < array->length(); i++) {
16850 if (array->get(i) == *break_point_object) {
16851 return true;
16852 }
16853 }
16854 return false;
16855}
16856
16857
16858// Get the number of break points.
16859int BreakPointInfo::GetBreakPointCount() {
16860 // No break point.
16861 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016862 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000016863 if (!break_point_objects()->IsFixedArray()) return 1;
16864 // Multiple break points.
16865 return FixedArray::cast(break_point_objects())->length();
16866}
Steve Blocka7e24c12009-10-30 11:49:00 +000016867
16868
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016869Object* JSDate::GetField(Object* object, Smi* index) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016870 return JSDate::cast(object)->DoGetField(
16871 static_cast<FieldIndex>(index->value()));
16872}
16873
16874
16875Object* JSDate::DoGetField(FieldIndex index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016876 DCHECK(index != kDateValue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016877
16878 DateCache* date_cache = GetIsolate()->date_cache();
16879
16880 if (index < kFirstUncachedField) {
16881 Object* stamp = cache_stamp();
16882 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
16883 // Since the stamp is not NaN, the value is also not NaN.
16884 int64_t local_time_ms =
16885 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016886 SetCachedFields(local_time_ms, date_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016887 }
16888 switch (index) {
16889 case kYear: return year();
16890 case kMonth: return month();
16891 case kDay: return day();
16892 case kWeekday: return weekday();
16893 case kHour: return hour();
16894 case kMinute: return min();
16895 case kSecond: return sec();
16896 default: UNREACHABLE();
16897 }
16898 }
16899
16900 if (index >= kFirstUTCField) {
16901 return GetUTCField(index, value()->Number(), date_cache);
16902 }
16903
16904 double time = value()->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016905 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016906
16907 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
16908 int days = DateCache::DaysFromTime(local_time_ms);
16909
16910 if (index == kDays) return Smi::FromInt(days);
16911
16912 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16913 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016914 DCHECK(index == kTimeInDay);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016915 return Smi::FromInt(time_in_day_ms);
16916}
16917
16918
16919Object* JSDate::GetUTCField(FieldIndex index,
16920 double value,
16921 DateCache* date_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016922 DCHECK(index >= kFirstUTCField);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016923
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016924 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016925
16926 int64_t time_ms = static_cast<int64_t>(value);
16927
16928 if (index == kTimezoneOffset) {
16929 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
16930 }
16931
16932 int days = DateCache::DaysFromTime(time_ms);
16933
16934 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
16935
16936 if (index <= kDayUTC) {
16937 int year, month, day;
16938 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16939 if (index == kYearUTC) return Smi::FromInt(year);
16940 if (index == kMonthUTC) return Smi::FromInt(month);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016941 DCHECK(index == kDayUTC);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016942 return Smi::FromInt(day);
16943 }
16944
16945 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
16946 switch (index) {
16947 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
16948 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
16949 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
16950 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
16951 case kDaysUTC: return Smi::FromInt(days);
16952 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
16953 default: UNREACHABLE();
16954 }
16955
16956 UNREACHABLE();
16957 return NULL;
16958}
16959
16960
16961void JSDate::SetValue(Object* value, bool is_value_nan) {
16962 set_value(value);
16963 if (is_value_nan) {
16964 HeapNumber* nan = GetIsolate()->heap()->nan_value();
16965 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
16966 set_year(nan, SKIP_WRITE_BARRIER);
16967 set_month(nan, SKIP_WRITE_BARRIER);
16968 set_day(nan, SKIP_WRITE_BARRIER);
16969 set_hour(nan, SKIP_WRITE_BARRIER);
16970 set_min(nan, SKIP_WRITE_BARRIER);
16971 set_sec(nan, SKIP_WRITE_BARRIER);
16972 set_weekday(nan, SKIP_WRITE_BARRIER);
16973 } else {
16974 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
16975 }
16976}
16977
16978
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016979void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016980 int days = DateCache::DaysFromTime(local_time_ms);
16981 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16982 int year, month, day;
16983 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16984 int weekday = date_cache->Weekday(days);
16985 int hour = time_in_day_ms / (60 * 60 * 1000);
16986 int min = (time_in_day_ms / (60 * 1000)) % 60;
16987 int sec = (time_in_day_ms / 1000) % 60;
16988 set_cache_stamp(date_cache->stamp());
16989 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
16990 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
16991 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
16992 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
16993 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
16994 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
16995 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
16996}
16997
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016998
16999void JSArrayBuffer::Neuter() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017000 CHECK(is_neuterable());
17001 CHECK(is_external());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017002 set_backing_store(NULL);
17003 set_byte_length(Smi::FromInt(0));
17004}
17005
17006
17007void JSArrayBufferView::NeuterView() {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017008 CHECK(JSArrayBuffer::cast(buffer())->is_neuterable());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017009 set_byte_offset(Smi::FromInt(0));
17010 set_byte_length(Smi::FromInt(0));
17011}
17012
17013
17014void JSDataView::Neuter() {
17015 NeuterView();
17016}
17017
17018
17019void JSTypedArray::Neuter() {
17020 NeuterView();
17021 set_length(Smi::FromInt(0));
17022 set_elements(GetHeap()->EmptyExternalArrayForMap(map()));
17023}
17024
17025
17026static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) {
17027 switch (elements_kind) {
17028#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
17029 case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
17030
17031 TYPED_ARRAYS(TYPED_ARRAY_CASE)
17032#undef TYPED_ARRAY_CASE
17033
17034 default:
17035 UNREACHABLE();
17036 return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
17037 }
17038}
17039
17040
17041Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
17042 Handle<JSTypedArray> typed_array) {
17043
17044 Handle<Map> map(typed_array->map());
17045 Isolate* isolate = typed_array->GetIsolate();
17046
17047 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
17048
17049 Handle<Map> new_map = Map::TransitionElementsTo(
17050 map,
17051 FixedToExternalElementsKind(map->elements_kind()));
17052
17053 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
17054 Handle<FixedTypedArrayBase> fixed_typed_array(
17055 FixedTypedArrayBase::cast(typed_array->elements()));
17056 Runtime::SetupArrayBufferAllocatingData(isolate, buffer,
17057 fixed_typed_array->DataSize(), false);
17058 memcpy(buffer->backing_store(),
17059 fixed_typed_array->DataPtr(),
17060 fixed_typed_array->DataSize());
17061 Handle<ExternalArray> new_elements =
17062 isolate->factory()->NewExternalArray(
17063 fixed_typed_array->length(), typed_array->type(),
17064 static_cast<uint8_t*>(buffer->backing_store()));
17065
17066 buffer->set_weak_first_view(*typed_array);
17067 DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value());
17068 typed_array->set_buffer(*buffer);
17069 JSObject::SetMapAndElements(typed_array, new_map, new_elements);
17070
17071 return buffer;
17072}
17073
17074
17075Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
17076 Handle<Object> result(buffer(), GetIsolate());
17077 if (*result != Smi::FromInt(0)) {
17078 DCHECK(IsExternalArrayElementsKind(map()->elements_kind()));
17079 return Handle<JSArrayBuffer>::cast(result);
17080 }
17081 Handle<JSTypedArray> self(this);
17082 return MaterializeArrayBuffer(self);
17083}
17084
17085
17086HeapType* PropertyCell::type() {
17087 return static_cast<HeapType*>(type_raw());
17088}
17089
17090
17091void PropertyCell::set_type(HeapType* type, WriteBarrierMode ignored) {
17092 DCHECK(IsPropertyCell());
17093 set_type_raw(type, ignored);
17094}
17095
17096
17097Handle<HeapType> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
17098 Handle<Object> value) {
17099 Isolate* isolate = cell->GetIsolate();
17100 Handle<HeapType> old_type(cell->type(), isolate);
17101 Handle<HeapType> new_type = HeapType::Constant(value, isolate);
17102
17103 if (new_type->Is(old_type)) return old_type;
17104
17105 cell->dependent_code()->DeoptimizeDependentCodeGroup(
17106 isolate, DependentCode::kPropertyCellChangedGroup);
17107
17108 if (old_type->Is(HeapType::None()) || old_type->Is(HeapType::Undefined())) {
17109 return new_type;
17110 }
17111
17112 return HeapType::Any(isolate);
17113}
17114
17115
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017116Handle<Object> PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
17117 Handle<Object> value) {
17118 // Heuristic: if a small-ish string is stored in a previously uninitialized
17119 // property cell, internalize it.
17120 const int kMaxLengthForInternalization = 200;
17121 if ((cell->type()->Is(HeapType::None()) ||
17122 cell->type()->Is(HeapType::Undefined())) &&
17123 value->IsString() &&
17124 Handle<String>::cast(value)->length() <= kMaxLengthForInternalization) {
17125 value = cell->GetIsolate()->factory()->InternalizeString(
17126 Handle<String>::cast(value));
17127 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017128 cell->set_value(*value);
17129 if (!HeapType::Any()->Is(cell->type())) {
17130 Handle<HeapType> new_type = UpdatedType(cell, value);
17131 cell->set_type(*new_type);
17132 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040017133 return value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000017134}
17135
17136
17137// static
17138void PropertyCell::AddDependentCompilationInfo(Handle<PropertyCell> cell,
17139 CompilationInfo* info) {
17140 Handle<DependentCode> codes =
17141 DependentCode::Insert(handle(cell->dependent_code(), info->isolate()),
17142 DependentCode::kPropertyCellChangedGroup,
17143 info->object_wrapper());
17144 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes);
17145 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
17146 cell, info->zone());
17147}
17148
Steve Blocka7e24c12009-10-30 11:49:00 +000017149} } // namespace v8::internal