blob: 39d3d7c357c8692e0654c06da4cedc34e728de61 [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
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Steve Blocka7e24c12009-10-30 11:49:00 +00006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/accessors.h"
8#include "src/allocation-site-scopes.h"
9#include "src/api.h"
10#include "src/arguments.h"
11#include "src/base/bits.h"
12#include "src/bootstrapper.h"
13#include "src/code-stubs.h"
14#include "src/codegen.h"
15#include "src/cpu-profiler.h"
16#include "src/date.h"
17#include "src/debug.h"
18#include "src/deoptimizer.h"
19#include "src/elements.h"
20#include "src/execution.h"
21#include "src/field-index-inl.h"
22#include "src/field-index.h"
23#include "src/full-codegen.h"
24#include "src/heap/mark-compact.h"
25#include "src/heap/objects-visiting-inl.h"
26#include "src/hydrogen.h"
27#include "src/ic/ic.h"
28#include "src/isolate-inl.h"
29#include "src/log.h"
30#include "src/lookup.h"
31#include "src/macro-assembler.h"
32#include "src/objects-inl.h"
33#include "src/prototype.h"
34#include "src/safepoint-table.h"
35#include "src/string-search.h"
36#include "src/string-stream.h"
37#include "src/utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
39#ifdef ENABLE_DISASSEMBLER
Ben Murdochb8a8cc12014-11-26 15:28:44 +000040#include "src/disasm.h"
41#include "src/disassembler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042#endif
43
Steve Blocka7e24c12009-10-30 11:49:00 +000044namespace v8 {
45namespace internal {
46
Ben Murdochb8a8cc12014-11-26 15:28:44 +000047Handle<HeapType> Object::OptimalType(Isolate* isolate,
48 Representation representation) {
49 if (representation.IsNone()) return HeapType::None(isolate);
50 if (FLAG_track_field_types) {
51 if (representation.IsHeapObject() && IsHeapObject()) {
52 // We can track only JavaScript objects with stable maps.
53 Handle<Map> map(HeapObject::cast(this)->map(), isolate);
54 if (map->is_stable() &&
55 map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
56 map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
57 return HeapType::Class(map, isolate);
58 }
59 }
60 }
61 return HeapType::Any(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010062}
63
Steve Blocka7e24c12009-10-30 11:49:00 +000064
Ben Murdochb8a8cc12014-11-26 15:28:44 +000065MaybeHandle<JSReceiver> Object::ToObject(Isolate* isolate,
66 Handle<Object> object,
67 Handle<Context> native_context) {
68 if (object->IsJSReceiver()) return Handle<JSReceiver>::cast(object);
69 Handle<JSFunction> constructor;
70 if (object->IsNumber()) {
71 constructor = handle(native_context->number_function(), isolate);
72 } else if (object->IsBoolean()) {
73 constructor = handle(native_context->boolean_function(), isolate);
74 } else if (object->IsString()) {
75 constructor = handle(native_context->string_function(), isolate);
76 } else if (object->IsSymbol()) {
77 constructor = handle(native_context->symbol_function(), isolate);
78 } else {
79 return MaybeHandle<JSReceiver>();
John Reck59135872010-11-02 12:39:01 -070080 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000081 Handle<JSObject> result = isolate->factory()->NewJSObject(constructor);
82 Handle<JSValue>::cast(result)->set_value(*object);
Steve Blocka7e24c12009-10-30 11:49:00 +000083 return result;
84}
85
86
Ben Murdochb8a8cc12014-11-26 15:28:44 +000087bool Object::BooleanValue() {
88 if (IsBoolean()) return IsTrue();
89 if (IsSmi()) return Smi::cast(this)->value() != 0;
90 if (IsUndefined() || IsNull()) return false;
91 if (IsUndetectableObject()) return false; // Undetectable object is false.
92 if (IsString()) return String::cast(this)->length() != 0;
93 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
94 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +000095}
96
97
Ben Murdochb8a8cc12014-11-26 15:28:44 +000098bool Object::IsCallable() const {
99 const Object* fun = this;
100 while (fun->IsJSFunctionProxy()) {
101 fun = JSFunctionProxy::cast(fun)->call_trap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000102 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 return fun->IsJSFunction() ||
104 (fun->IsHeapObject() &&
105 HeapObject::cast(fun)->map()->has_instance_call_handler());
Steve Blocka7e24c12009-10-30 11:49:00 +0000106}
107
108
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000109MaybeHandle<Object> Object::GetProperty(LookupIterator* it) {
110 for (; it->IsFound(); it->Next()) {
111 switch (it->state()) {
112 case LookupIterator::NOT_FOUND:
113 case LookupIterator::TRANSITION:
114 UNREACHABLE();
115 case LookupIterator::JSPROXY:
116 return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
117 it->GetReceiver(), it->name());
118 case LookupIterator::INTERCEPTOR: {
119 MaybeHandle<Object> maybe_result = JSObject::GetPropertyWithInterceptor(
120 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
121 if (!maybe_result.is_null()) return maybe_result;
122 if (it->isolate()->has_pending_exception()) return maybe_result;
123 break;
124 }
125 case LookupIterator::ACCESS_CHECK:
126 if (it->HasAccess(v8::ACCESS_GET)) break;
127 return JSObject::GetPropertyWithFailedAccessCheck(it);
128 case LookupIterator::ACCESSOR:
129 return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
130 it->GetHolder<JSObject>(),
131 it->GetAccessors());
132 case LookupIterator::DATA:
133 return it->GetDataValue();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100134 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000136 return it->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000137}
138
139
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000140Handle<Object> JSObject::GetDataProperty(Handle<JSObject> object,
141 Handle<Name> key) {
142 LookupIterator it(object, key,
143 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
144 return GetDataProperty(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +0000145}
146
147
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000148Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
149 for (; it->IsFound(); it->Next()) {
150 switch (it->state()) {
151 case LookupIterator::INTERCEPTOR:
152 case LookupIterator::NOT_FOUND:
153 case LookupIterator::TRANSITION:
154 UNREACHABLE();
155 case LookupIterator::ACCESS_CHECK:
156 if (it->HasAccess(v8::ACCESS_GET)) continue;
157 // Fall through.
158 case LookupIterator::JSPROXY:
159 it->NotFound();
160 return it->isolate()->factory()->undefined_value();
161 case LookupIterator::ACCESSOR:
162 // TODO(verwaest): For now this doesn't call into
163 // ExecutableAccessorInfo, since clients don't need it. Update once
164 // relevant.
165 it->NotFound();
166 return it->isolate()->factory()->undefined_value();
167 case LookupIterator::DATA:
168 return it->GetDataValue();
169 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000170 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000171 return it->isolate()->factory()->undefined_value();
172}
Steve Blocka7e24c12009-10-30 11:49:00 +0000173
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000174
175bool Object::ToInt32(int32_t* value) {
176 if (IsSmi()) {
177 *value = Smi::cast(this)->value();
178 return true;
179 }
180 if (IsHeapNumber()) {
181 double num = HeapNumber::cast(this)->value();
182 if (FastI2D(FastD2I(num)) == num) {
183 *value = FastD2I(num);
184 return true;
185 }
186 }
187 return false;
188}
189
190
191bool Object::ToUint32(uint32_t* value) {
192 if (IsSmi()) {
193 int num = Smi::cast(this)->value();
194 if (num >= 0) {
195 *value = static_cast<uint32_t>(num);
196 return true;
197 }
198 }
199 if (IsHeapNumber()) {
200 double num = HeapNumber::cast(this)->value();
201 if (num >= 0 && FastUI2D(FastD2UI(num)) == num) {
202 *value = FastD2UI(num);
203 return true;
204 }
205 }
206 return false;
207}
208
209
210bool FunctionTemplateInfo::IsTemplateFor(Object* object) {
211 if (!object->IsHeapObject()) return false;
212 return IsTemplateFor(HeapObject::cast(object)->map());
213}
214
215
216bool FunctionTemplateInfo::IsTemplateFor(Map* map) {
217 // There is a constraint on the object; check.
218 if (!map->IsJSObjectMap()) return false;
219 // Fetch the constructor function of the object.
220 Object* cons_obj = map->constructor();
221 if (!cons_obj->IsJSFunction()) return false;
222 JSFunction* fun = JSFunction::cast(cons_obj);
223 // Iterate through the chain of inheriting function templates to
224 // see if the required one occurs.
225 for (Object* type = fun->shared()->function_data();
226 type->IsFunctionTemplateInfo();
227 type = FunctionTemplateInfo::cast(type)->parent_template()) {
228 if (type == this) return true;
229 }
230 // Didn't find the required type in the inheritance chain.
231 return false;
232}
233
234
235template<typename To>
236static inline To* CheckedCast(void *from) {
237 uintptr_t temp = reinterpret_cast<uintptr_t>(from);
238 DCHECK(temp % sizeof(To) == 0);
239 return reinterpret_cast<To*>(temp);
240}
241
242
243static Handle<Object> PerformCompare(const BitmaskCompareDescriptor& descriptor,
244 char* ptr,
245 Isolate* isolate) {
246 uint32_t bitmask = descriptor.bitmask;
247 uint32_t compare_value = descriptor.compare_value;
248 uint32_t value;
249 switch (descriptor.size) {
250 case 1:
251 value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
252 compare_value &= 0xff;
253 bitmask &= 0xff;
254 break;
255 case 2:
256 value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
257 compare_value &= 0xffff;
258 bitmask &= 0xffff;
259 break;
260 case 4:
261 value = *CheckedCast<uint32_t>(ptr);
262 break;
263 default:
264 UNREACHABLE();
265 return isolate->factory()->undefined_value();
266 }
267 return isolate->factory()->ToBoolean(
268 (bitmask & value) == (bitmask & compare_value));
269}
270
271
272static Handle<Object> PerformCompare(const PointerCompareDescriptor& descriptor,
273 char* ptr,
274 Isolate* isolate) {
275 uintptr_t compare_value =
276 reinterpret_cast<uintptr_t>(descriptor.compare_value);
277 uintptr_t value = *CheckedCast<uintptr_t>(ptr);
278 return isolate->factory()->ToBoolean(compare_value == value);
279}
280
281
282static Handle<Object> GetPrimitiveValue(
283 const PrimitiveValueDescriptor& descriptor,
284 char* ptr,
285 Isolate* isolate) {
286 int32_t int32_value = 0;
287 switch (descriptor.data_type) {
288 case kDescriptorInt8Type:
289 int32_value = *CheckedCast<int8_t>(ptr);
290 break;
291 case kDescriptorUint8Type:
292 int32_value = *CheckedCast<uint8_t>(ptr);
293 break;
294 case kDescriptorInt16Type:
295 int32_value = *CheckedCast<int16_t>(ptr);
296 break;
297 case kDescriptorUint16Type:
298 int32_value = *CheckedCast<uint16_t>(ptr);
299 break;
300 case kDescriptorInt32Type:
301 int32_value = *CheckedCast<int32_t>(ptr);
302 break;
303 case kDescriptorUint32Type: {
304 uint32_t value = *CheckedCast<uint32_t>(ptr);
305 AllowHeapAllocation allow_gc;
306 return isolate->factory()->NewNumberFromUint(value);
307 }
308 case kDescriptorBoolType: {
309 uint8_t byte = *CheckedCast<uint8_t>(ptr);
310 return isolate->factory()->ToBoolean(
311 byte & (0x1 << descriptor.bool_offset));
312 }
313 case kDescriptorFloatType: {
314 float value = *CheckedCast<float>(ptr);
315 AllowHeapAllocation allow_gc;
316 return isolate->factory()->NewNumber(value);
317 }
318 case kDescriptorDoubleType: {
319 double value = *CheckedCast<double>(ptr);
320 AllowHeapAllocation allow_gc;
321 return isolate->factory()->NewNumber(value);
322 }
323 }
324 AllowHeapAllocation allow_gc;
325 return isolate->factory()->NewNumberFromInt(int32_value);
326}
327
328
329static Handle<Object> GetDeclaredAccessorProperty(
330 Handle<Object> receiver,
331 Handle<DeclaredAccessorInfo> info,
332 Isolate* isolate) {
333 DisallowHeapAllocation no_gc;
334 char* current = reinterpret_cast<char*>(*receiver);
335 DeclaredAccessorDescriptorIterator iterator(info->descriptor());
336 while (true) {
337 const DeclaredAccessorDescriptorData* data = iterator.Next();
338 switch (data->type) {
339 case kDescriptorReturnObject: {
340 DCHECK(iterator.Complete());
341 current = *CheckedCast<char*>(current);
342 return handle(*CheckedCast<Object*>(current), isolate);
343 }
344 case kDescriptorPointerDereference:
345 DCHECK(!iterator.Complete());
346 current = *reinterpret_cast<char**>(current);
347 break;
348 case kDescriptorPointerShift:
349 DCHECK(!iterator.Complete());
350 current += data->pointer_shift_descriptor.byte_offset;
351 break;
352 case kDescriptorObjectDereference: {
353 DCHECK(!iterator.Complete());
354 Object* object = CheckedCast<Object>(current);
355 int field = data->object_dereference_descriptor.internal_field;
356 Object* smi = JSObject::cast(object)->GetInternalField(field);
357 DCHECK(smi->IsSmi());
358 current = reinterpret_cast<char*>(smi);
359 break;
360 }
361 case kDescriptorBitmaskCompare:
362 DCHECK(iterator.Complete());
363 return PerformCompare(data->bitmask_compare_descriptor,
364 current,
365 isolate);
366 case kDescriptorPointerCompare:
367 DCHECK(iterator.Complete());
368 return PerformCompare(data->pointer_compare_descriptor,
369 current,
370 isolate);
371 case kDescriptorPrimitiveValue:
372 DCHECK(iterator.Complete());
373 return GetPrimitiveValue(data->primitive_value_descriptor,
374 current,
375 isolate);
376 }
377 }
378 UNREACHABLE();
379 return isolate->factory()->undefined_value();
380}
381
382
383Handle<FixedArray> JSObject::EnsureWritableFastElements(
384 Handle<JSObject> object) {
385 DCHECK(object->HasFastSmiOrObjectElements());
386 Isolate* isolate = object->GetIsolate();
387 Handle<FixedArray> elems(FixedArray::cast(object->elements()), isolate);
388 if (elems->map() != isolate->heap()->fixed_cow_array_map()) return elems;
389 Handle<FixedArray> writable_elems = isolate->factory()->CopyFixedArrayWithMap(
390 elems, isolate->factory()->fixed_array_map());
391 object->set_elements(*writable_elems);
392 isolate->counters()->cow_arrays_converted()->Increment();
393 return writable_elems;
394}
395
396
397MaybeHandle<Object> JSProxy::GetPropertyWithHandler(Handle<JSProxy> proxy,
398 Handle<Object> receiver,
399 Handle<Name> name) {
400 Isolate* isolate = proxy->GetIsolate();
401
402 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
403 if (name->IsSymbol()) return isolate->factory()->undefined_value();
404
405 Handle<Object> args[] = { receiver, name };
406 return CallTrap(
407 proxy, "get", isolate->derived_get_trap(), arraysize(args), args);
408}
409
410
411MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
412 Handle<Name> name,
413 Handle<JSObject> holder,
414 Handle<Object> structure) {
415 Isolate* isolate = name->GetIsolate();
416 DCHECK(!structure->IsForeign());
Steve Blocka7e24c12009-10-30 11:49:00 +0000417 // api style callbacks.
418 if (structure->IsAccessorInfo()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000419 Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(structure);
420 if (!info->IsCompatibleReceiver(*receiver)) {
421 Handle<Object> args[2] = { name, receiver };
422 THROW_NEW_ERROR(isolate,
423 NewTypeError("incompatible_method_receiver",
424 HandleVector(args, arraysize(args))),
425 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000426 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427 if (structure->IsDeclaredAccessorInfo()) {
428 return GetDeclaredAccessorProperty(
429 receiver,
430 Handle<DeclaredAccessorInfo>::cast(structure),
431 isolate);
432 }
433
434 Handle<ExecutableAccessorInfo> data =
435 Handle<ExecutableAccessorInfo>::cast(structure);
436 v8::AccessorNameGetterCallback call_fun =
437 v8::ToCData<v8::AccessorNameGetterCallback>(data->getter());
438 if (call_fun == NULL) return isolate->factory()->undefined_value();
439
440 LOG(isolate, ApiNamedPropertyAccess("load", *holder, *name));
441 PropertyCallbackArguments args(isolate, data->data(), *receiver, *holder);
442 v8::Handle<v8::Value> result =
443 args.Call(call_fun, v8::Utils::ToLocal(name));
444 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
Steve Block44f0eee2011-05-26 01:26:41 +0100445 if (result.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 return isolate->factory()->undefined_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100447 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 Handle<Object> return_value = v8::Utils::OpenHandle(*result);
449 return_value->VerifyApiCallResultType();
450 // Rebox handle before return.
451 return handle(*return_value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 }
453
454 // __defineGetter__ callback
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000455 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
456 isolate);
457 if (getter->IsSpecFunction()) {
458 // TODO(rossberg): nicer would be to cast to some JSCallable here...
459 return Object::GetPropertyWithDefinedGetter(
460 receiver, Handle<JSReceiver>::cast(getter));
461 }
462 // Getter is not a function.
463 return isolate->factory()->undefined_value();
464}
465
466
467bool AccessorInfo::IsCompatibleReceiverType(Isolate* isolate,
468 Handle<AccessorInfo> info,
469 Handle<HeapType> type) {
470 if (!info->HasExpectedReceiverType()) return true;
471 Handle<Map> map = IC::TypeToMap(*type, isolate);
472 if (!map->IsJSObjectMap()) return false;
473 return FunctionTemplateInfo::cast(info->expected_receiver_type())
474 ->IsTemplateFor(*map);
475}
476
477
478MaybeHandle<Object> Object::SetPropertyWithAccessor(
479 Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
480 Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) {
481 Isolate* isolate = name->GetIsolate();
482
483 // We should never get here to initialize a const with the hole
484 // value since a const declaration would conflict with the setter.
485 DCHECK(!structure->IsForeign());
486 if (structure->IsExecutableAccessorInfo()) {
487 // Don't call executable accessor setters with non-JSObject receivers.
488 if (!receiver->IsJSObject()) return value;
489 // api style callbacks
490 ExecutableAccessorInfo* info = ExecutableAccessorInfo::cast(*structure);
491 if (!info->IsCompatibleReceiver(*receiver)) {
492 Handle<Object> args[2] = { name, receiver };
493 THROW_NEW_ERROR(isolate,
494 NewTypeError("incompatible_method_receiver",
495 HandleVector(args, arraysize(args))),
496 Object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000497 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000498 Object* call_obj = info->setter();
499 v8::AccessorNameSetterCallback call_fun =
500 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj);
501 if (call_fun == NULL) return value;
502 LOG(isolate, ApiNamedPropertyAccess("store", *holder, *name));
503 PropertyCallbackArguments args(isolate, info->data(), *receiver, *holder);
504 args.Call(call_fun,
505 v8::Utils::ToLocal(name),
506 v8::Utils::ToLocal(value));
507 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
508 return value;
509 }
510
511 if (structure->IsAccessorPair()) {
512 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
513 if (setter->IsSpecFunction()) {
514 // TODO(rossberg): nicer would be to cast to some JSCallable here...
515 return SetPropertyWithDefinedSetter(
516 receiver, Handle<JSReceiver>::cast(setter), value);
517 } else {
518 if (strict_mode == SLOPPY) return value;
519 Handle<Object> args[2] = { name, holder };
520 THROW_NEW_ERROR(
521 isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
522 Object);
523 }
524 }
525
526 // TODO(dcarney): Handle correctly.
527 if (structure->IsDeclaredAccessorInfo()) {
528 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000529 }
530
531 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 return MaybeHandle<Object>();
Steve Blocka7e24c12009-10-30 11:49:00 +0000533}
534
535
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536MaybeHandle<Object> Object::GetPropertyWithDefinedGetter(
537 Handle<Object> receiver,
538 Handle<JSReceiver> getter) {
539 Isolate* isolate = getter->GetIsolate();
540 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000541 // Handle stepping into a getter if step into is active.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100542 // TODO(rossberg): should this apply to getters that are function proxies?
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000543 if (debug->StepInActive() && getter->IsJSFunction()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100544 debug->HandleStepIn(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000545 Handle<JSFunction>::cast(getter), Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100547
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 return Execution::Call(isolate, getter, receiver, 0, NULL, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000549}
550
551
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
553 Handle<Object> receiver,
554 Handle<JSReceiver> setter,
555 Handle<Object> value) {
556 Isolate* isolate = setter->GetIsolate();
557
558 Debug* debug = isolate->debug();
559 // Handle stepping into a setter if step into is active.
560 // TODO(rossberg): should this apply to getters that are function proxies?
561 if (debug->StepInActive() && setter->IsJSFunction()) {
562 debug->HandleStepIn(
563 Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false);
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) {
575 for (; it->IsFound(); it->Next()) {
576 if (it->state() == LookupIterator::ACCESSOR) {
577 Handle<Object> accessors = it->GetAccessors();
578 if (accessors->IsAccessorInfo()) {
579 if (AccessorInfo::cast(*accessors)->all_can_read()) return true;
580 }
581 }
582 }
583 return false;
584}
585
586
587MaybeHandle<Object> JSObject::GetPropertyWithFailedAccessCheck(
588 LookupIterator* it) {
589 Handle<JSObject> checked = it->GetHolder<JSObject>();
590 if (FindAllCanReadHolder(it)) {
591 return GetPropertyWithAccessor(it->GetReceiver(), it->name(),
592 it->GetHolder<JSObject>(),
593 it->GetAccessors());
594 }
595 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_GET);
596 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
597 return it->factory()->undefined_value();
598}
599
600
601Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithFailedAccessCheck(
602 LookupIterator* it) {
603 Handle<JSObject> checked = it->GetHolder<JSObject>();
604 if (FindAllCanReadHolder(it))
605 return maybe(it->property_details().attributes());
606 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_HAS);
607 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(it->isolate(),
608 Maybe<PropertyAttributes>());
609 return maybe(ABSENT);
610}
611
612
613static bool FindAllCanWriteHolder(LookupIterator* it) {
614 for (; it->IsFound(); it->Next()) {
615 if (it->state() == LookupIterator::ACCESSOR) {
616 Handle<Object> accessors = it->GetAccessors();
617 if (accessors->IsAccessorInfo()) {
618 if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
619 }
620 }
621 }
622 return false;
623}
624
625
626MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
627 LookupIterator* it, Handle<Object> value, StrictMode strict_mode) {
628 Handle<JSObject> checked = it->GetHolder<JSObject>();
629 if (FindAllCanWriteHolder(it)) {
630 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
631 it->GetHolder<JSObject>(),
632 it->GetAccessors(), strict_mode);
633 }
634
635 it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET);
636 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
637 return value;
638}
639
640
641void JSObject::SetNormalizedProperty(Handle<JSObject> object,
642 Handle<Name> name,
643 Handle<Object> value,
644 PropertyDetails details) {
645 DCHECK(!object->HasFastProperties());
646 Handle<NameDictionary> property_dictionary(object->property_dictionary());
647
648 if (!name->IsUniqueName()) {
649 name = object->GetIsolate()->factory()->InternalizeString(
650 Handle<String>::cast(name));
651 }
652
653 int entry = property_dictionary->FindEntry(name);
654 if (entry == NameDictionary::kNotFound) {
655 Handle<Object> store_value = value;
656 if (object->IsGlobalObject()) {
657 store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
658 }
659
660 property_dictionary = NameDictionary::Add(
661 property_dictionary, name, store_value, details);
662 object->set_properties(*property_dictionary);
663 return;
664 }
665
666 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
667 int enumeration_index;
668 // Preserve the enumeration index unless the property was deleted.
669 if (original_details.IsDeleted()) {
670 enumeration_index = property_dictionary->NextEnumerationIndex();
671 property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000672 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 enumeration_index = original_details.dictionary_index();
674 DCHECK(enumeration_index > 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000676
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000677 details = PropertyDetails(
678 details.attributes(), details.type(), enumeration_index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000679
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000680 if (object->IsGlobalObject()) {
681 Handle<PropertyCell> cell(
682 PropertyCell::cast(property_dictionary->ValueAt(entry)));
683 PropertyCell::SetValueInferType(cell, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 // Please note we have to update the property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000685 property_dictionary->DetailsAtPut(entry, details);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000687 property_dictionary->SetEntry(entry, name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000689}
690
691
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000692Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
693 Handle<Name> name,
694 DeleteMode mode) {
695 DCHECK(!object->HasFastProperties());
696 Isolate* isolate = object->GetIsolate();
697 Handle<NameDictionary> dictionary(object->property_dictionary());
Steve Blocka7e24c12009-10-30 11:49:00 +0000698 int entry = dictionary->FindEntry(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000699 if (entry != NameDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000700 // If we have a global object set the cell to the hole.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000701 if (object->IsGlobalObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000702 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000703 if (!details.IsConfigurable()) {
704 if (mode != FORCE_DELETION) return isolate->factory()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000705 // When forced to delete global properties, we have to make a
706 // map change to invalidate any ICs that think they can load
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 // from the non-configurable cell without checking if it contains
Steve Blocka7e24c12009-10-30 11:49:00 +0000708 // the hole value.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000709 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
710 DCHECK(new_map->is_dictionary_map());
711 JSObject::MigrateToMap(object, new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +0000712 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
714 Handle<Object> value = isolate->factory()->the_hole_value();
715 PropertyCell::SetValueInferType(cell, value);
Steve Blocka7e24c12009-10-30 11:49:00 +0000716 dictionary->DetailsAtPut(entry, details.AsDeleted());
717 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 Handle<Object> deleted(
719 NameDictionary::DeleteProperty(dictionary, entry, mode));
720 if (*deleted == isolate->heap()->true_value()) {
721 Handle<NameDictionary> new_properties =
722 NameDictionary::Shrink(dictionary, name);
723 object->set_properties(*new_properties);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000724 }
725 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 }
727 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000728 return isolate->factory()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000729}
730
731
732bool JSObject::IsDirty() {
733 Object* cons_obj = map()->constructor();
734 if (!cons_obj->IsJSFunction())
735 return true;
736 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100737 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000738 return true;
739 // If the object is fully fast case and has the same map it was
740 // created with then no changes can have been made to it.
741 return map() != fun->initial_map()
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 || !HasFastObjectElements()
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 || !HasFastProperties();
744}
745
746
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000747MaybeHandle<Object> Object::GetElementWithReceiver(Isolate* isolate,
748 Handle<Object> object,
749 Handle<Object> receiver,
750 uint32_t index) {
751 if (object->IsUndefined()) {
752 // TODO(verwaest): Why is this check here?
753 UNREACHABLE();
754 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000755 }
756
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000757 // Iterate up the prototype chain until an element is found or the null
758 // prototype is encountered.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000759 for (PrototypeIterator iter(isolate, object,
760 object->IsJSProxy() || object->IsJSObject()
761 ? PrototypeIterator::START_AT_RECEIVER
762 : PrototypeIterator::START_AT_PROTOTYPE);
763 !iter.IsAtEnd(); iter.Advance()) {
764 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
765 return JSProxy::GetElementWithHandler(
766 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
767 index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000768 }
769
770 // Inline the case for JSObjects. Doing so significantly improves the
771 // performance of fetching elements where checking the prototype chain is
772 // necessary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000773 Handle<JSObject> js_object =
774 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000775
776 // Check access rights if needed.
777 if (js_object->IsAccessCheckNeeded()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000778 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
779 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000780 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
781 return isolate->factory()->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000782 }
783 }
784
785 if (js_object->HasIndexedInterceptor()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000786 return JSObject::GetElementWithInterceptor(js_object, receiver, index);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000787 }
788
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000789 if (js_object->elements() != isolate->heap()->empty_fixed_array()) {
790 Handle<Object> result;
791 ASSIGN_RETURN_ON_EXCEPTION(
792 isolate, result,
793 js_object->GetElementsAccessor()->Get(receiver, js_object, index),
794 Object);
795 if (!result->IsTheHole()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100796 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100797 }
798
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000799 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000800}
801
802
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000803Map* Object::GetRootMap(Isolate* isolate) {
804 DisallowHeapAllocation no_alloc;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100805 if (IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000806 Context* context = isolate->context()->native_context();
807 return context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100808 }
809
810 HeapObject* heap_object = HeapObject::cast(this);
811
Ben Murdoch257744e2011-11-30 15:57:28 +0000812 // The object is either a number, a string, a boolean,
813 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000814 if (heap_object->IsJSReceiver()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000815 return heap_object->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100816 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000817 Context* context = isolate->context()->native_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000818
Ben Murdoch8b112d22011-06-08 16:22:53 +0100819 if (heap_object->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000820 return context->number_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100821 }
822 if (heap_object->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000823 return context->string_function()->initial_map();
824 }
825 if (heap_object->IsSymbol()) {
826 return context->symbol_function()->initial_map();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100827 }
828 if (heap_object->IsBoolean()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000829 return context->boolean_function()->initial_map();
Steve Blocka7e24c12009-10-30 11:49:00 +0000830 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000831 return isolate->heap()->null_value()->map();
Steve Blocka7e24c12009-10-30 11:49:00 +0000832}
833
834
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000835Object* Object::GetHash() {
836 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100837 // a real JS object, or a Harmony proxy.
838 if (IsNumber()) {
839 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
840 return Smi::FromInt(hash & Smi::kMaxValue);
841 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000842 if (IsName()) {
843 uint32_t hash = Name::cast(this)->Hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100844 return Smi::FromInt(hash);
845 }
846 if (IsOddball()) {
847 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
848 return Smi::FromInt(hash);
849 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100850
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000851 DCHECK(IsJSReceiver());
852 return JSReceiver::cast(this)->GetIdentityHash();
853}
854
855
856Handle<Smi> Object::GetOrCreateHash(Isolate* isolate, Handle<Object> object) {
857 Handle<Object> hash(object->GetHash(), isolate);
858 if (hash->IsSmi()) return Handle<Smi>::cast(hash);
859
860 DCHECK(object->IsJSReceiver());
861 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100862}
863
864
865bool Object::SameValue(Object* other) {
866 if (other == this) return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100867
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000868 // The object is either a number, a name, an odd-ball,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100869 // a real JS object, or a Harmony proxy.
870 if (IsNumber() && other->IsNumber()) {
871 double this_value = Number();
872 double other_value = other->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000873 bool equal = this_value == other_value;
874 // SameValue(NaN, NaN) is true.
875 if (!equal) return std::isnan(this_value) && std::isnan(other_value);
876 // SameValue(0.0, -0.0) is false.
877 return (this_value != 0) || ((1 / this_value) == (1 / other_value));
878 }
879 if (IsString() && other->IsString()) {
880 return String::cast(this)->Equals(String::cast(other));
881 }
882 return false;
883}
884
885
886bool Object::SameValueZero(Object* other) {
887 if (other == this) return true;
888
889 // The object is either a number, a name, an odd-ball,
890 // a real JS object, or a Harmony proxy.
891 if (IsNumber() && other->IsNumber()) {
892 double this_value = Number();
893 double other_value = other->Number();
894 // +0 == -0 is true
895 return this_value == other_value
896 || (std::isnan(this_value) && std::isnan(other_value));
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100897 }
898 if (IsString() && other->IsString()) {
899 return String::cast(this)->Equals(String::cast(other));
900 }
901 return false;
902}
903
904
Ben Murdochb0fe1622011-05-05 13:52:32 +0100905void Object::ShortPrint(FILE* out) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906 OFStream os(out);
907 os << Brief(this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000908}
909
910
911void Object::ShortPrint(StringStream* accumulator) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912 OStringStream os;
913 os << Brief(this);
914 accumulator->Add(os.c_str());
915}
916
917
918OStream& operator<<(OStream& os, const Brief& v) {
919 if (v.value->IsSmi()) {
920 Smi::cast(v.value)->SmiPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000922 // TODO(svenpanne) Const-correct HeapObjectShortPrint!
923 HeapObject* obj = const_cast<HeapObject*>(HeapObject::cast(v.value));
924 obj->HeapObjectShortPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +0000925 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000926 return os;
Steve Blocka7e24c12009-10-30 11:49:00 +0000927}
928
929
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000930void Smi::SmiPrint(OStream& os) const { // NOLINT
931 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000932}
933
934
Steve Blocka7e24c12009-10-30 11:49:00 +0000935// Should a word be prefixed by 'a' or 'an' in order to read naturally in
936// English? Returns false for non-ASCII or words that don't start with
937// a capital letter. The a/an rule follows pronunciation in English.
938// We don't use the BBC's overcorrect "an historic occasion" though if
939// you speak a dialect you may well say "an 'istoric occasion".
940static bool AnWord(String* str) {
941 if (str->length() == 0) return false; // A nothing.
942 int c0 = str->Get(0);
943 int c1 = str->length() > 1 ? str->Get(1) : 0;
944 if (c0 == 'U') {
945 if (c1 > 'Z') {
946 return true; // An Umpire, but a UTF8String, a U.
947 }
948 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
949 return true; // An Ape, an ABCBook.
950 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
951 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
952 c0 == 'S' || c0 == 'X')) {
953 return true; // An MP3File, an M.
954 }
955 return false;
956}
957
958
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000959Handle<String> String::SlowFlatten(Handle<ConsString> cons,
960 PretenureFlag pretenure) {
961 DCHECK(AllowHeapAllocation::IsAllowed());
962 DCHECK(cons->second()->length() != 0);
963 Isolate* isolate = cons->GetIsolate();
964 int length = cons->length();
965 PretenureFlag tenure = isolate->heap()->InNewSpace(*cons) ? pretenure
966 : TENURED;
967 Handle<SeqString> result;
968 if (cons->IsOneByteRepresentation()) {
969 Handle<SeqOneByteString> flat = isolate->factory()->NewRawOneByteString(
970 length, tenure).ToHandleChecked();
971 DisallowHeapAllocation no_gc;
972 WriteToFlat(*cons, flat->GetChars(), 0, length);
973 result = flat;
974 } else {
975 Handle<SeqTwoByteString> flat = isolate->factory()->NewRawTwoByteString(
976 length, tenure).ToHandleChecked();
977 DisallowHeapAllocation no_gc;
978 WriteToFlat(*cons, flat->GetChars(), 0, length);
979 result = flat;
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000981 cons->set_first(*result);
982 cons->set_second(isolate->heap()->empty_string());
983 DCHECK(result->IsFlat());
984 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000985}
986
987
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000988
Steve Blocka7e24c12009-10-30 11:49:00 +0000989bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100990 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100991 // prohibited by the API.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000992 DCHECK(!this->IsExternalString());
993#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +0000994 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000995 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000996 DCHECK(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100997 ScopedVector<uc16> smart_chars(this->length());
998 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000999 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001000 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001001 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001002 }
1003#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001005 // Abort if size does not allow in-place conversion.
1006 if (size < ExternalString::kShortSize) return false;
1007 Heap* heap = GetHeap();
1008 bool is_one_byte = this->IsOneByteRepresentation();
1009 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001010
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001011 // Morph the string to an external string by replacing the map and
1012 // reinitializing the fields. This won't work if the space the existing
1013 // string occupies is too small for a regular external string.
1014 // Instead, we resort to a short external string instead, omitting
1015 // the field caching the address of the backing store. When we encounter
1016 // short external strings in generated code, we need to bailout to runtime.
1017 Map* new_map;
1018 if (size < ExternalString::kSize) {
1019 new_map = is_internalized
1020 ? (is_one_byte
1021 ? heap->short_external_internalized_string_with_one_byte_data_map()
1022 : heap->short_external_internalized_string_map())
1023 : (is_one_byte ? heap->short_external_string_with_one_byte_data_map()
1024 : heap->short_external_string_map());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001025 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001026 new_map = is_internalized
1027 ? (is_one_byte
1028 ? heap->external_internalized_string_with_one_byte_data_map()
1029 : heap->external_internalized_string_map())
1030 : (is_one_byte ? heap->external_string_with_one_byte_data_map()
1031 : heap->external_string_map());
Ben Murdoch85b71792012-04-11 18:30:58 +01001032 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001033
1034 // Byte size of the external String object.
1035 int new_size = this->SizeFromMap(new_map);
1036 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
1037
1038 // We are storing the new map using release store after creating a filler for
1039 // the left-over space to avoid races with the sweeper thread.
1040 this->synchronized_set_map(new_map);
1041
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001042 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1043 self->set_resource(resource);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001044 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
Steve Blocka7e24c12009-10-30 11:49:00 +00001045
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046 heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00001047 return true;
1048}
1049
1050
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001051bool String::MakeExternal(v8::String::ExternalOneByteStringResource* resource) {
1052 // Externalizing twice leaks the external resource, so it's
1053 // prohibited by the API.
1054 DCHECK(!this->IsExternalString());
1055#ifdef ENABLE_SLOW_DCHECKS
Steve Block3ce2e202009-11-05 08:53:23 +00001056 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001057 // Assert that the resource and the string are equivalent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001058 DCHECK(static_cast<size_t>(this->length()) == resource->length());
1059 if (this->IsTwoByteRepresentation()) {
1060 ScopedVector<uint16_t> smart_chars(this->length());
1061 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1062 DCHECK(String::IsOneByte(smart_chars.start(), this->length()));
1063 }
Kristian Monsen25f61362010-05-21 11:50:48 +01001064 ScopedVector<char> smart_chars(this->length());
1065 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001066 DCHECK(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +00001067 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +01001068 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001069 }
1070#endif // DEBUG
Steve Blocka7e24c12009-10-30 11:49:00 +00001071 int size = this->Size(); // Byte size of the original string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001072 // Abort if size does not allow in-place conversion.
1073 if (size < ExternalString::kShortSize) return false;
1074 Heap* heap = GetHeap();
1075 bool is_internalized = this->IsInternalizedString();
Steve Blocka7e24c12009-10-30 11:49:00 +00001076
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 // Morph the string to an external string by replacing the map and
1078 // reinitializing the fields. This won't work if the space the existing
1079 // string occupies is too small for a regular external string.
1080 // Instead, we resort to a short external string instead, omitting
1081 // the field caching the address of the backing store. When we encounter
1082 // short external strings in generated code, we need to bailout to runtime.
1083 Map* new_map;
1084 if (size < ExternalString::kSize) {
1085 new_map = is_internalized
1086 ? heap->short_external_one_byte_internalized_string_map()
1087 : heap->short_external_one_byte_string_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001088 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001089 new_map = is_internalized
1090 ? heap->external_one_byte_internalized_string_map()
1091 : heap->external_one_byte_string_map();
Ben Murdoch85b71792012-04-11 18:30:58 +01001092 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001093
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001094 // Byte size of the external String object.
1095 int new_size = this->SizeFromMap(new_map);
Steve Block44f0eee2011-05-26 01:26:41 +01001096 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001097
1098 // We are storing the new map using release store after creating a filler for
1099 // the left-over space to avoid races with the sweeper thread.
1100 this->synchronized_set_map(new_map);
1101
1102 ExternalOneByteString* self = ExternalOneByteString::cast(this);
1103 self->set_resource(resource);
1104 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
1105
1106 heap->AdjustLiveBytes(this->address(), new_size - size, Heap::FROM_MUTATOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 return true;
1108}
1109
1110
1111void String::StringShortPrint(StringStream* accumulator) {
1112 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +00001113 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001114 accumulator->Add("<Very long string[%u]>", len);
1115 return;
1116 }
1117
1118 if (!LooksValid()) {
1119 accumulator->Add("<Invalid String>");
1120 return;
1121 }
1122
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001123 ConsStringIteratorOp op;
1124 StringCharacterStream stream(this, &op);
Steve Blocka7e24c12009-10-30 11:49:00 +00001125
1126 bool truncated = false;
1127 if (len > kMaxShortPrintLength) {
1128 len = kMaxShortPrintLength;
1129 truncated = true;
1130 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001131 bool one_byte = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001132 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001133 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001134
1135 if (c < 32 || c >= 127) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001136 one_byte = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001137 }
1138 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001139 stream.Reset(this);
1140 if (one_byte) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001141 accumulator->Add("<String[%u]: ", length());
1142 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001143 accumulator->Put(static_cast<char>(stream.GetNext()));
Steve Blocka7e24c12009-10-30 11:49:00 +00001144 }
1145 accumulator->Put('>');
1146 } else {
1147 // Backslash indicates that the string contains control
1148 // characters and that backslashes are therefore escaped.
1149 accumulator->Add("<String[%u]\\: ", length());
1150 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001151 uint16_t c = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00001152 if (c == '\n') {
1153 accumulator->Add("\\n");
1154 } else if (c == '\r') {
1155 accumulator->Add("\\r");
1156 } else if (c == '\\') {
1157 accumulator->Add("\\\\");
1158 } else if (c < 32 || c > 126) {
1159 accumulator->Add("\\x%02x", c);
1160 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001161 accumulator->Put(static_cast<char>(c));
Steve Blocka7e24c12009-10-30 11:49:00 +00001162 }
1163 }
1164 if (truncated) {
1165 accumulator->Put('.');
1166 accumulator->Put('.');
1167 accumulator->Put('.');
1168 }
1169 accumulator->Put('>');
1170 }
1171 return;
1172}
1173
1174
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001175void String::PrintUC16(OStream& os, int start, int end) { // NOLINT
1176 if (end < 0) end = length();
1177 ConsStringIteratorOp op;
1178 StringCharacterStream stream(this, &op, start);
1179 for (int i = start; i < end && stream.HasMore(); i++) {
1180 os << AsUC16(stream.GetNext());
1181 }
1182}
1183
1184
Steve Blocka7e24c12009-10-30 11:49:00 +00001185void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1186 switch (map()->instance_type()) {
1187 case JS_ARRAY_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001188 double length = JSArray::cast(this)->length()->IsUndefined()
1189 ? 0
1190 : JSArray::cast(this)->length()->Number();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001191 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
Steve Blocka7e24c12009-10-30 11:49:00 +00001192 break;
1193 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001194 case JS_WEAK_MAP_TYPE: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001195 accumulator->Add("<JS WeakMap>");
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001196 break;
1197 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001198 case JS_WEAK_SET_TYPE: {
1199 accumulator->Add("<JS WeakSet>");
1200 break;
1201 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001202 case JS_REGEXP_TYPE: {
1203 accumulator->Add("<JS RegExp>");
1204 break;
1205 }
1206 case JS_FUNCTION_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001207 JSFunction* function = JSFunction::cast(this);
1208 Object* fun_name = function->shared()->DebugName();
Steve Blocka7e24c12009-10-30 11:49:00 +00001209 bool printed = false;
1210 if (fun_name->IsString()) {
1211 String* str = String::cast(fun_name);
1212 if (str->length() > 0) {
1213 accumulator->Add("<JS Function ");
1214 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001215 printed = true;
1216 }
1217 }
1218 if (!printed) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 accumulator->Add("<JS Function");
Steve Blocka7e24c12009-10-30 11:49:00 +00001220 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001221 accumulator->Add(" (SharedFunctionInfo %p)",
1222 reinterpret_cast<void*>(function->shared()));
1223 accumulator->Put('>');
1224 break;
1225 }
1226 case JS_GENERATOR_OBJECT_TYPE: {
1227 accumulator->Add("<JS Generator>");
1228 break;
1229 }
1230 case JS_MODULE_TYPE: {
1231 accumulator->Add("<JS Module>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 break;
1233 }
1234 // All other JSObjects are rather similar to each other (JSObject,
1235 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1236 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001237 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001238 Heap* heap = GetHeap();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001239 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 bool printed = false;
1241 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001242 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1244 } else {
1245 bool global_object = IsJSGlobalProxy();
1246 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001247 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001248 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1249 } else {
1250 Object* constructor_name =
1251 JSFunction::cast(constructor)->shared()->name();
1252 if (constructor_name->IsString()) {
1253 String* str = String::cast(constructor_name);
1254 if (str->length() > 0) {
1255 bool vowel = AnWord(str);
1256 accumulator->Add("<%sa%s ",
1257 global_object ? "Global Object: " : "",
1258 vowel ? "n" : "");
1259 accumulator->Put(str);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001260 accumulator->Add(" with %smap %p",
1261 map_of_this->is_deprecated() ? "deprecated " : "",
1262 map_of_this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001263 printed = true;
1264 }
1265 }
1266 }
1267 }
1268 if (!printed) {
1269 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1270 }
1271 }
1272 if (IsJSValue()) {
1273 accumulator->Add(" value = ");
1274 JSValue::cast(this)->value()->ShortPrint(accumulator);
1275 }
1276 accumulator->Put('>');
1277 break;
1278 }
1279 }
1280}
1281
1282
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001283void JSObject::PrintElementsTransition(
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284 FILE* file, Handle<JSObject> object,
1285 ElementsKind from_kind, Handle<FixedArrayBase> from_elements,
1286 ElementsKind to_kind, Handle<FixedArrayBase> to_elements) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001287 if (from_kind != to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001288 OFStream os(file);
1289 os << "elements transition [" << ElementsKindToString(from_kind) << " -> "
1290 << ElementsKindToString(to_kind) << "] in ";
1291 JavaScriptFrame::PrintTop(object->GetIsolate(), file, false, true);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001292 PrintF(file, " for ");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001293 object->ShortPrint(file);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001294 PrintF(file, " from ");
1295 from_elements->ShortPrint(file);
1296 PrintF(file, " to ");
1297 to_elements->ShortPrint(file);
1298 PrintF(file, "\n");
1299 }
1300}
1301
1302
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001303void Map::PrintGeneralization(FILE* file,
1304 const char* reason,
1305 int modify_index,
1306 int split,
1307 int descriptors,
1308 bool constant_to_field,
1309 Representation old_representation,
1310 Representation new_representation,
1311 HeapType* old_field_type,
1312 HeapType* new_field_type) {
1313 OFStream os(file);
1314 os << "[generalizing ";
1315 constructor_name()->PrintOn(file);
1316 os << "] ";
1317 Name* name = instance_descriptors()->GetKey(modify_index);
1318 if (name->IsString()) {
1319 String::cast(name)->PrintOn(file);
1320 } else {
1321 os << "{symbol " << static_cast<void*>(name) << "}";
1322 }
1323 os << ":";
1324 if (constant_to_field) {
1325 os << "c";
1326 } else {
1327 os << old_representation.Mnemonic() << "{";
1328 old_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
1329 os << "}";
1330 }
1331 os << "->" << new_representation.Mnemonic() << "{";
1332 new_field_type->PrintTo(os, HeapType::SEMANTIC_DIM);
1333 os << "} (";
1334 if (strlen(reason) > 0) {
1335 os << reason;
1336 } else {
1337 os << "+" << (descriptors - split) << " maps";
1338 }
1339 os << ") [";
1340 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
1341 os << "]\n";
1342}
1343
1344
1345void JSObject::PrintInstanceMigration(FILE* file,
1346 Map* original_map,
1347 Map* new_map) {
1348 PrintF(file, "[migrating ");
1349 map()->constructor_name()->PrintOn(file);
1350 PrintF(file, "] ");
1351 DescriptorArray* o = original_map->instance_descriptors();
1352 DescriptorArray* n = new_map->instance_descriptors();
1353 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
1354 Representation o_r = o->GetDetails(i).representation();
1355 Representation n_r = n->GetDetails(i).representation();
1356 if (!o_r.Equals(n_r)) {
1357 String::cast(o->GetKey(i))->PrintOn(file);
1358 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
1359 } else if (o->GetDetails(i).type() == CONSTANT &&
1360 n->GetDetails(i).type() == FIELD) {
1361 Name* name = o->GetKey(i);
1362 if (name->IsString()) {
1363 String::cast(name)->PrintOn(file);
1364 } else {
1365 PrintF(file, "{symbol %p}", static_cast<void*>(name));
1366 }
1367 PrintF(file, " ");
1368 }
1369 }
1370 PrintF(file, "\n");
1371}
1372
1373
1374void HeapObject::HeapObjectShortPrint(OStream& os) { // NOLINT
Steve Block44f0eee2011-05-26 01:26:41 +01001375 Heap* heap = GetHeap();
1376 if (!heap->Contains(this)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377 os << "!!!INVALID POINTER!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 return;
1379 }
Steve Block44f0eee2011-05-26 01:26:41 +01001380 if (!heap->Contains(map())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001381 os << "!!!INVALID MAP!!!";
Steve Blocka7e24c12009-10-30 11:49:00 +00001382 return;
1383 }
1384
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385 os << this << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +00001386
1387 if (IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001388 HeapStringAllocator allocator;
1389 StringStream accumulator(&allocator);
1390 String::cast(this)->StringShortPrint(&accumulator);
1391 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00001392 return;
1393 }
1394 if (IsJSObject()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 HeapStringAllocator allocator;
1396 StringStream accumulator(&allocator);
1397 JSObject::cast(this)->JSObjectShortPrint(&accumulator);
1398 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00001399 return;
1400 }
1401 switch (map()->instance_type()) {
1402 case MAP_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001403 os << "<Map(elements=" << Map::cast(this)->elements_kind() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 break;
1405 case FIXED_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 os << "<FixedArray[" << FixedArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001407 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001408 case FIXED_DOUBLE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 os << "<FixedDoubleArray[" << FixedDoubleArray::cast(this)->length()
1410 << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001411 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 case BYTE_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413 os << "<ByteArray[" << ByteArray::cast(this)->length() << "]>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001414 break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001415 case FREE_SPACE_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001416 os << "<FreeSpace[" << FreeSpace::cast(this)->Size() << "]>";
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001417 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418#define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \
1419 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
1420 os << "<External" #Type "Array[" \
1421 << External##Type##Array::cast(this)->length() << "]>"; \
1422 break; \
1423 case FIXED_##TYPE##_ARRAY_TYPE: \
1424 os << "<Fixed" #Type "Array[" << Fixed##Type##Array::cast(this)->length() \
1425 << "]>"; \
1426 break;
1427
1428 TYPED_ARRAYS(TYPED_ARRAY_SHORT_PRINT)
1429#undef TYPED_ARRAY_SHORT_PRINT
1430
1431 case SHARED_FUNCTION_INFO_TYPE: {
1432 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
1433 SmartArrayPointer<char> debug_name =
1434 shared->DebugName()->ToCString();
1435 if (debug_name[0] != 0) {
1436 os << "<SharedFunctionInfo " << debug_name.get() << ">";
1437 } else {
1438 os << "<SharedFunctionInfo>";
1439 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001440 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441 }
Steve Block1e0659c2011-05-24 12:43:12 +01001442 case JS_MESSAGE_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 os << "<JSMessageObject>";
Steve Block1e0659c2011-05-24 12:43:12 +01001444 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001445#define MAKE_STRUCT_CASE(NAME, Name, name) \
1446 case NAME##_TYPE: \
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 os << "<" #Name ">"; \
Steve Blocka7e24c12009-10-30 11:49:00 +00001448 break;
1449 STRUCT_LIST(MAKE_STRUCT_CASE)
1450#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001451 case CODE_TYPE: {
1452 Code* code = Code::cast(this);
1453 os << "<Code: " << Code::Kind2String(code->kind()) << ">";
Steve Blocka7e24c12009-10-30 11:49:00 +00001454 break;
1455 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 case ODDBALL_TYPE: {
1457 if (IsUndefined()) {
1458 os << "<undefined>";
1459 } else if (IsTheHole()) {
1460 os << "<the hole>";
1461 } else if (IsNull()) {
1462 os << "<null>";
1463 } else if (IsTrue()) {
1464 os << "<true>";
1465 } else if (IsFalse()) {
1466 os << "<false>";
1467 } else {
1468 os << "<Odd Oddball>";
1469 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001471 }
1472 case SYMBOL_TYPE: {
1473 Symbol* symbol = Symbol::cast(this);
1474 os << "<Symbol: " << symbol->Hash();
1475 if (!symbol->name()->IsUndefined()) {
1476 os << " ";
1477 HeapStringAllocator allocator;
1478 StringStream accumulator(&allocator);
1479 String::cast(symbol->name())->StringShortPrint(&accumulator);
1480 os << accumulator.ToCString().get();
1481 }
1482 os << ">";
1483 break;
1484 }
1485 case HEAP_NUMBER_TYPE: {
1486 os << "<Number: ";
1487 HeapNumber::cast(this)->HeapNumberPrint(os);
1488 os << ">";
1489 break;
1490 }
1491 case MUTABLE_HEAP_NUMBER_TYPE: {
1492 os << "<MutableNumber: ";
1493 HeapNumber::cast(this)->HeapNumberPrint(os);
1494 os << '>';
1495 break;
1496 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001497 case JS_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001498 os << "<JSProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00001499 break;
1500 case JS_FUNCTION_PROXY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001501 os << "<JSFunctionProxy>";
Ben Murdoch589d6972011-11-30 16:04:58 +00001502 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001503 case FOREIGN_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504 os << "<Foreign>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001505 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001506 case CELL_TYPE: {
1507 os << "Cell for ";
1508 HeapStringAllocator allocator;
1509 StringStream accumulator(&allocator);
1510 Cell::cast(this)->value()->ShortPrint(&accumulator);
1511 os << accumulator.ToCString().get();
Steve Blocka7e24c12009-10-30 11:49:00 +00001512 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001513 }
1514 case PROPERTY_CELL_TYPE: {
1515 os << "PropertyCell for ";
1516 HeapStringAllocator allocator;
1517 StringStream accumulator(&allocator);
1518 PropertyCell::cast(this)->value()->ShortPrint(&accumulator);
1519 os << accumulator.ToCString().get();
1520 break;
1521 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001522 default:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001523 os << "<Other heap object (" << map()->instance_type() << ")>";
Steve Blocka7e24c12009-10-30 11:49:00 +00001524 break;
1525 }
1526}
1527
1528
Steve Blocka7e24c12009-10-30 11:49:00 +00001529void HeapObject::Iterate(ObjectVisitor* v) {
1530 // Handle header
1531 IteratePointer(v, kMapOffset);
1532 // Handle object body
1533 Map* m = map();
1534 IterateBody(m->instance_type(), SizeFromMap(m), v);
1535}
1536
1537
1538void HeapObject::IterateBody(InstanceType type, int object_size,
1539 ObjectVisitor* v) {
1540 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1541 // During GC, the map pointer field is encoded.
1542 if (type < FIRST_NONSTRING_TYPE) {
1543 switch (type & kStringRepresentationMask) {
1544 case kSeqStringTag:
1545 break;
1546 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001547 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001549 case kSlicedStringTag:
1550 SlicedString::BodyDescriptor::IterateBody(this, v);
1551 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001552 case kExternalStringTag:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001553 if ((type & kStringEncodingMask) == kOneByteStringTag) {
1554 reinterpret_cast<ExternalOneByteString*>(this)
1555 ->ExternalOneByteStringIterateBody(v);
Steve Blockd0582a62009-12-15 09:54:21 +00001556 } else {
1557 reinterpret_cast<ExternalTwoByteString*>(this)->
1558 ExternalTwoByteStringIterateBody(v);
1559 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 break;
1561 }
1562 return;
1563 }
1564
1565 switch (type) {
1566 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001567 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001568 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001569 case CONSTANT_POOL_ARRAY_TYPE:
1570 reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
1571 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001572 case FIXED_DOUBLE_ARRAY_TYPE:
1573 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001574 case JS_OBJECT_TYPE:
1575 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001576 case JS_GENERATOR_OBJECT_TYPE:
1577 case JS_MODULE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001578 case JS_VALUE_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001579 case JS_DATE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001580 case JS_ARRAY_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001581 case JS_ARRAY_BUFFER_TYPE:
1582 case JS_TYPED_ARRAY_TYPE:
1583 case JS_DATA_VIEW_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001584 case JS_SET_TYPE:
1585 case JS_MAP_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001586 case JS_SET_ITERATOR_TYPE:
1587 case JS_MAP_ITERATOR_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001588 case JS_WEAK_MAP_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 case JS_WEAK_SET_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001590 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 case JS_GLOBAL_PROXY_TYPE:
1592 case JS_GLOBAL_OBJECT_TYPE:
1593 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001594 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001595 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001596 break;
Steve Block791712a2010-08-27 10:21:07 +01001597 case JS_FUNCTION_TYPE:
1598 reinterpret_cast<JSFunction*>(this)
1599 ->JSFunctionIterateBody(object_size, v);
1600 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001601 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001602 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001603 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001604 case JS_PROXY_TYPE:
1605 JSProxy::BodyDescriptor::IterateBody(this, v);
1606 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001607 case JS_FUNCTION_PROXY_TYPE:
1608 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1609 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001610 case FOREIGN_TYPE:
1611 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001612 break;
1613 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001614 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001615 break;
1616 case CODE_TYPE:
1617 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1618 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001619 case CELL_TYPE:
1620 Cell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001622 case PROPERTY_CELL_TYPE:
1623 PropertyCell::BodyDescriptor::IterateBody(this, v);
1624 break;
1625 case SYMBOL_TYPE:
1626 Symbol::BodyDescriptor::IterateBody(this, v);
1627 break;
1628
Steve Blocka7e24c12009-10-30 11:49:00 +00001629 case HEAP_NUMBER_TYPE:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001630 case MUTABLE_HEAP_NUMBER_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 case FILLER_TYPE:
1632 case BYTE_ARRAY_TYPE:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001633 case FREE_SPACE_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001634 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001635
1636#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
1637 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
1638 case FIXED_##TYPE##_ARRAY_TYPE: \
1639 break;
1640
1641 TYPED_ARRAYS(TYPED_ARRAY_CASE)
1642#undef TYPED_ARRAY_CASE
1643
Ben Murdoch8f9999f2012-04-23 10:39:17 +01001644 case SHARED_FUNCTION_INFO_TYPE: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001645 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001646 break;
Ben Murdoch8f9999f2012-04-23 10:39:17 +01001647 }
Iain Merrick75681382010-08-19 15:07:18 +01001648
Steve Blocka7e24c12009-10-30 11:49:00 +00001649#define MAKE_STRUCT_CASE(NAME, Name, name) \
1650 case NAME##_TYPE:
1651 STRUCT_LIST(MAKE_STRUCT_CASE)
1652#undef MAKE_STRUCT_CASE
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001653 if (type == ALLOCATION_SITE_TYPE) {
1654 AllocationSite::BodyDescriptor::IterateBody(this, v);
1655 } else {
1656 StructBodyDescriptor::IterateBody(this, object_size, v);
1657 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001658 break;
1659 default:
1660 PrintF("Unknown type: %d\n", type);
1661 UNREACHABLE();
1662 }
1663}
1664
1665
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001666bool HeapNumber::HeapNumberBooleanValue() {
1667 return DoubleToBoolean(value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001668}
1669
1670
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001671void HeapNumber::HeapNumberPrint(OStream& os) { // NOLINT
1672 os << value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001673}
1674
1675
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001676String* JSReceiver::class_name() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001677 if (IsJSFunction() || IsJSFunctionProxy()) {
1678 return GetHeap()->Function_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001679 }
1680 if (map()->constructor()->IsJSFunction()) {
1681 JSFunction* constructor = JSFunction::cast(map()->constructor());
1682 return String::cast(constructor->shared()->instance_class_name());
1683 }
1684 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001685 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001686}
1687
1688
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001689String* Map::constructor_name() {
1690 if (constructor()->IsJSFunction()) {
1691 JSFunction* constructor = JSFunction::cast(this->constructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00001692 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001693 if (name->length() > 0) return name;
1694 String* inferred_name = constructor->shared()->inferred_name();
1695 if (inferred_name->length() > 0) return inferred_name;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001696 Object* proto = prototype();
Ben Murdochf87a2032010-10-22 12:50:53 +01001697 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001698 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001699 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001700 // If the constructor is not present, return "Object".
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001701 return GetHeap()->Object_string();
Steve Blocka7e24c12009-10-30 11:49:00 +00001702}
1703
1704
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001705String* JSReceiver::constructor_name() {
1706 return map()->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001707}
1708
1709
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001710MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
1711 Handle<Name> name,
1712 Handle<HeapType> type,
1713 PropertyAttributes attributes,
1714 Representation representation,
1715 TransitionFlag flag) {
1716 DCHECK(DescriptorArray::kNotFound ==
1717 map->instance_descriptors()->Search(
1718 *name, map->NumberOfOwnDescriptors()));
Ben Murdoch8b112d22011-06-08 16:22:53 +01001719
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001720 // Ensure the descriptor array does not get too big.
1721 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1722 return MaybeHandle<Map>();
Steve Blocka7e24c12009-10-30 11:49:00 +00001723 }
1724
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001725 Isolate* isolate = map->GetIsolate();
1726
Steve Blocka7e24c12009-10-30 11:49:00 +00001727 // Compute the new index for new field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001728 int index = map->NextFreePropertyIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00001729
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001730 if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
1731 representation = Representation::Tagged();
1732 type = HeapType::Any(isolate);
John Reck59135872010-11-02 12:39:01 -07001733 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001734
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001735 FieldDescriptor new_field_desc(name, index, type, attributes, representation);
1736 Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
1737 int unused_property_fields = new_map->unused_property_fields() - 1;
1738 if (unused_property_fields < 0) {
1739 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07001740 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001741 new_map->set_unused_property_fields(unused_property_fields);
1742 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00001743}
1744
1745
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001746MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
1747 Handle<Name> name,
1748 Handle<Object> constant,
1749 PropertyAttributes attributes,
1750 TransitionFlag flag) {
1751 // Ensure the descriptor array does not get too big.
1752 if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
1753 return MaybeHandle<Map>();
John Reck59135872010-11-02 12:39:01 -07001754 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001755
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001756 // Allocate new instance descriptors with (name, constant) added.
1757 ConstantDescriptor new_constant_desc(name, constant, attributes);
1758 return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
Steve Blocka7e24c12009-10-30 11:49:00 +00001759}
1760
1761
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001762void JSObject::AddSlowProperty(Handle<JSObject> object,
1763 Handle<Name> name,
1764 Handle<Object> value,
1765 PropertyAttributes attributes) {
1766 DCHECK(!object->HasFastProperties());
1767 Isolate* isolate = object->GetIsolate();
1768 Handle<NameDictionary> dict(object->property_dictionary());
1769 if (object->IsGlobalObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001770 // In case name is an orphaned property reuse the cell.
1771 int entry = dict->FindEntry(name);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001772 if (entry != NameDictionary::kNotFound) {
1773 Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
1774 PropertyCell::SetValueInferType(cell, value);
Steve Blocka7e24c12009-10-30 11:49:00 +00001775 // Assign an enumeration index to the property and update
1776 // SetNextEnumerationIndex.
1777 int index = dict->NextEnumerationIndex();
1778 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1779 dict->SetNextEnumerationIndex(index + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001780 dict->SetEntry(entry, name, cell, details);
1781 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001782 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001783 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
1784 PropertyCell::SetValueInferType(cell, value);
1785 value = cell;
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001787 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
1788 Handle<NameDictionary> result =
1789 NameDictionary::Add(dict, name, value, details);
1790 if (*dict != *result) object->set_properties(*result);
Steve Blocka7e24c12009-10-30 11:49:00 +00001791}
1792
1793
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001794Context* JSObject::GetCreationContext() {
1795 Object* constructor = this->map()->constructor();
1796 JSFunction* function;
1797 if (!constructor->IsJSFunction()) {
1798 // Functions have null as a constructor,
1799 // but any JSFunction knows its context immediately.
1800 function = JSFunction::cast(this);
1801 } else {
1802 function = JSFunction::cast(constructor);
1803 }
1804
1805 return function->context()->native_context();
1806}
1807
1808
1809void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
1810 const char* type_str,
1811 Handle<Name> name,
1812 Handle<Object> old_value) {
1813 DCHECK(!object->IsJSGlobalProxy());
1814 DCHECK(!object->IsJSGlobalObject());
1815 Isolate* isolate = object->GetIsolate();
1816 HandleScope scope(isolate);
1817 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
1818 Handle<Object> args[] = { type, object, name, old_value };
1819 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
1820
1821 Execution::Call(isolate,
1822 Handle<JSFunction>(isolate->observers_notify_change()),
1823 isolate->factory()->undefined_value(),
1824 argc, args).Assert();
1825}
1826
1827
1828const char* Representation::Mnemonic() const {
1829 switch (kind_) {
1830 case kNone: return "v";
1831 case kTagged: return "t";
1832 case kSmi: return "s";
1833 case kDouble: return "d";
1834 case kInteger32: return "i";
1835 case kHeapObject: return "h";
1836 case kExternal: return "x";
1837 default:
1838 UNREACHABLE();
1839 return NULL;
1840 }
1841}
1842
1843
1844bool Map::InstancesNeedRewriting(Map* target, int target_number_of_fields,
1845 int target_inobject, int target_unused,
1846 int* old_number_of_fields) {
1847 // If fields were added (or removed), rewrite the instance.
1848 *old_number_of_fields = NumberOfFields();
1849 DCHECK(target_number_of_fields >= *old_number_of_fields);
1850 if (target_number_of_fields != *old_number_of_fields) return true;
1851
1852 // If smi descriptors were replaced by double descriptors, rewrite.
1853 DescriptorArray* old_desc = instance_descriptors();
1854 DescriptorArray* new_desc = target->instance_descriptors();
1855 int limit = NumberOfOwnDescriptors();
1856 for (int i = 0; i < limit; i++) {
1857 if (new_desc->GetDetails(i).representation().IsDouble() !=
1858 old_desc->GetDetails(i).representation().IsDouble()) {
1859 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01001860 }
Steve Block8defd9f2010-07-08 12:39:36 +01001861 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001862
1863 // If no fields were added, and no inobject properties were removed, setting
1864 // the map is sufficient.
1865 if (target_inobject == inobject_properties()) return false;
1866 // In-object slack tracking may have reduced the object size of the new map.
1867 // In that case, succeed if all existing fields were inobject, and they still
1868 // fit within the new inobject size.
1869 DCHECK(target_inobject < inobject_properties());
1870 if (target_number_of_fields <= target_inobject) {
1871 DCHECK(target_number_of_fields + target_unused == target_inobject);
1872 return false;
1873 }
1874 // Otherwise, properties will need to be moved to the backing store.
1875 return true;
1876}
1877
1878
1879void Map::ConnectElementsTransition(Handle<Map> parent, Handle<Map> child) {
1880 Isolate* isolate = parent->GetIsolate();
1881 Handle<Name> name = isolate->factory()->elements_transition_symbol();
1882 ConnectTransition(parent, child, name, FULL_TRANSITION);
1883}
1884
1885
1886void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
1887 if (object->map() == *new_map) return;
1888 if (object->HasFastProperties()) {
1889 if (!new_map->is_dictionary_map()) {
1890 Handle<Map> old_map(object->map());
1891 MigrateFastToFast(object, new_map);
1892 if (old_map->is_prototype_map()) {
1893 // Clear out the old descriptor array to avoid problems to sharing
1894 // the descriptor array without using an explicit.
1895 old_map->InitializeDescriptors(
1896 old_map->GetHeap()->empty_descriptor_array());
1897 // Ensure that no transition was inserted for prototype migrations.
1898 DCHECK(!old_map->HasTransitionArray());
1899 DCHECK(new_map->GetBackPointer()->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001900 }
1901 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001902 MigrateFastToSlow(object, new_map, 0);
1903 }
1904 } else {
1905 // For slow-to-fast migrations JSObject::TransformToFastProperties()
1906 // must be used instead.
1907 CHECK(new_map->is_dictionary_map());
1908
1909 // Slow-to-slow migration is trivial.
1910 object->set_map(*new_map);
1911 }
1912}
1913
1914
1915// To migrate a fast instance to a fast map:
1916// - First check whether the instance needs to be rewritten. If not, simply
1917// change the map.
1918// - Otherwise, allocate a fixed array large enough to hold all fields, in
1919// addition to unused space.
1920// - Copy all existing properties in, in the following order: backing store
1921// properties, unused fields, inobject properties.
1922// - If all allocation succeeded, commit the state atomically:
1923// * Copy inobject properties from the backing store back into the object.
1924// * Trim the difference in instance size of the object. This also cleanly
1925// frees inobject properties that moved to the backing store.
1926// * If there are properties left in the backing store, trim of the space used
1927// to temporarily store the inobject properties.
1928// * If there are properties left in the backing store, install the backing
1929// store.
1930void JSObject::MigrateFastToFast(Handle<JSObject> object, Handle<Map> new_map) {
1931 Isolate* isolate = object->GetIsolate();
1932 Handle<Map> old_map(object->map());
1933 int old_number_of_fields;
1934 int number_of_fields = new_map->NumberOfFields();
1935 int inobject = new_map->inobject_properties();
1936 int unused = new_map->unused_property_fields();
1937
1938 // Nothing to do if no functions were converted to fields and no smis were
1939 // converted to doubles.
1940 if (!old_map->InstancesNeedRewriting(*new_map, number_of_fields, inobject,
1941 unused, &old_number_of_fields)) {
1942 object->synchronized_set_map(*new_map);
1943 return;
1944 }
1945
1946 int total_size = number_of_fields + unused;
1947 int external = total_size - inobject;
1948
1949 if (number_of_fields != old_number_of_fields &&
1950 new_map->GetBackPointer() == *old_map) {
1951 PropertyDetails details = new_map->GetLastDescriptorDetails();
1952
1953 if (old_map->unused_property_fields() > 0) {
1954 if (details.representation().IsDouble()) {
1955 Handle<Object> value = isolate->factory()->NewHeapNumber(0, MUTABLE);
1956 FieldIndex index =
1957 FieldIndex::ForDescriptor(*new_map, new_map->LastAdded());
1958 object->FastPropertyAtPut(index, *value);
John Reck59135872010-11-02 12:39:01 -07001959 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001960 object->synchronized_set_map(*new_map);
1961 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001962 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001963
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001964 DCHECK(number_of_fields == old_number_of_fields + 1);
1965 // This migration is a transition from a map that has run out out property
1966 // space. Therefore it could be done by extending the backing store.
1967 Handle<FixedArray> old_storage = handle(object->properties(), isolate);
1968 Handle<FixedArray> new_storage =
1969 FixedArray::CopySize(old_storage, external);
Steve Blocka7e24c12009-10-30 11:49:00 +00001970
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001971 // Properly initialize newly added property.
1972 Handle<Object> value;
1973 if (details.representation().IsDouble()) {
1974 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
1975 } else {
1976 value = isolate->factory()->uninitialized_value();
John Reck59135872010-11-02 12:39:01 -07001977 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001978 DCHECK(details.type() == FIELD);
1979 int target_index = details.field_index() - inobject;
1980 DCHECK(target_index >= 0); // Must be a backing store index.
1981 new_storage->set(target_index, *value);
1982
1983 // From here on we cannot fail and we shouldn't GC anymore.
1984 DisallowHeapAllocation no_allocation;
1985
1986 // Set the new property value and do the map transition.
1987 object->set_properties(*new_storage);
1988 object->synchronized_set_map(*new_map);
1989 return;
John Reck59135872010-11-02 12:39:01 -07001990 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001991 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
1992
1993 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
1994 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
1995 int old_nof = old_map->NumberOfOwnDescriptors();
1996 int new_nof = new_map->NumberOfOwnDescriptors();
1997
1998 // This method only supports generalizing instances to at least the same
1999 // number of properties.
2000 DCHECK(old_nof <= new_nof);
2001
2002 for (int i = 0; i < old_nof; i++) {
2003 PropertyDetails details = new_descriptors->GetDetails(i);
2004 if (details.type() != FIELD) continue;
2005 PropertyDetails old_details = old_descriptors->GetDetails(i);
2006 if (old_details.type() == CALLBACKS) {
2007 DCHECK(details.representation().IsTagged());
2008 continue;
2009 }
2010 DCHECK(old_details.type() == CONSTANT ||
2011 old_details.type() == FIELD);
2012 Object* raw_value = old_details.type() == CONSTANT
2013 ? old_descriptors->GetValue(i)
2014 : object->RawFastPropertyAt(FieldIndex::ForDescriptor(*old_map, i));
2015 Handle<Object> value(raw_value, isolate);
2016 if (!old_details.representation().IsDouble() &&
2017 details.representation().IsDouble()) {
2018 if (old_details.representation().IsNone()) {
2019 value = handle(Smi::FromInt(0), isolate);
2020 }
2021 value = Object::NewStorageFor(isolate, value, details.representation());
2022 } else if (old_details.representation().IsDouble() &&
2023 !details.representation().IsDouble()) {
2024 value = Object::WrapForRead(isolate, value, old_details.representation());
2025 }
2026 DCHECK(!(details.representation().IsDouble() && value->IsSmi()));
2027 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2028 if (target_index < 0) target_index += total_size;
2029 array->set(target_index, *value);
2030 }
2031
2032 for (int i = old_nof; i < new_nof; i++) {
2033 PropertyDetails details = new_descriptors->GetDetails(i);
2034 if (details.type() != FIELD) continue;
2035 Handle<Object> value;
2036 if (details.representation().IsDouble()) {
2037 value = isolate->factory()->NewHeapNumber(0, MUTABLE);
2038 } else {
2039 value = isolate->factory()->uninitialized_value();
2040 }
2041 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2042 if (target_index < 0) target_index += total_size;
2043 array->set(target_index, *value);
2044 }
2045
2046 // From here on we cannot fail and we shouldn't GC anymore.
2047 DisallowHeapAllocation no_allocation;
2048
2049 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2050 // avoid overwriting |one_pointer_filler_map|.
2051 int limit = Min(inobject, number_of_fields);
2052 for (int i = 0; i < limit; i++) {
2053 FieldIndex index = FieldIndex::ForPropertyIndex(*new_map, i);
2054 object->FastPropertyAtPut(index, array->get(external + i));
2055 }
2056
2057 Heap* heap = isolate->heap();
2058
2059 // If there are properties in the new backing store, trim it to the correct
2060 // size and install the backing store into the object.
2061 if (external > 0) {
2062 heap->RightTrimFixedArray<Heap::FROM_MUTATOR>(*array, inobject);
2063 object->set_properties(*array);
2064 }
2065
2066 // Create filler object past the new instance size.
2067 int new_instance_size = new_map->instance_size();
2068 int instance_size_delta = old_map->instance_size() - new_instance_size;
2069 DCHECK(instance_size_delta >= 0);
2070
2071 if (instance_size_delta > 0) {
2072 Address address = object->address();
2073 heap->CreateFillerObjectAt(
2074 address + new_instance_size, instance_size_delta);
2075 heap->AdjustLiveBytes(address, -instance_size_delta, Heap::FROM_MUTATOR);
2076 }
2077
2078 // We are storing the new map using release store after creating a filler for
2079 // the left-over space to avoid races with the sweeper thread.
2080 object->synchronized_set_map(*new_map);
2081}
2082
2083
2084void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
2085 int modify_index,
2086 Representation new_representation,
2087 Handle<HeapType> new_field_type) {
2088 Handle<Map> new_map = Map::GeneralizeRepresentation(
2089 handle(object->map()), modify_index, new_representation, new_field_type,
2090 FORCE_FIELD);
2091 MigrateToMap(object, new_map);
2092}
2093
2094
2095int Map::NumberOfFields() {
2096 DescriptorArray* descriptors = instance_descriptors();
2097 int result = 0;
2098 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2099 if (descriptors->GetDetails(i).type() == FIELD) result++;
2100 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002101 return result;
2102}
2103
2104
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002105Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2106 int modify_index,
2107 StoreMode store_mode,
2108 PropertyAttributes attributes,
2109 const char* reason) {
2110 Isolate* isolate = map->GetIsolate();
2111 Handle<Map> new_map = Copy(map);
Steve Blocka7e24c12009-10-30 11:49:00 +00002112
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002113 DescriptorArray* descriptors = new_map->instance_descriptors();
2114 int length = descriptors->number_of_descriptors();
2115 for (int i = 0; i < length; i++) {
2116 descriptors->SetRepresentation(i, Representation::Tagged());
2117 if (descriptors->GetDetails(i).type() == FIELD) {
2118 descriptors->SetValue(i, HeapType::Any());
John Reck59135872010-11-02 12:39:01 -07002119 }
2120 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002121
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002122 // Unless the instance is being migrated, ensure that modify_index is a field.
2123 PropertyDetails details = descriptors->GetDetails(modify_index);
2124 if (store_mode == FORCE_FIELD &&
2125 (details.type() != FIELD || details.attributes() != attributes)) {
2126 int field_index = details.type() == FIELD ? details.field_index()
2127 : new_map->NumberOfFields();
2128 FieldDescriptor d(handle(descriptors->GetKey(modify_index), isolate),
2129 field_index, attributes, Representation::Tagged());
2130 descriptors->Replace(modify_index, &d);
2131 if (details.type() != FIELD) {
2132 int unused_property_fields = new_map->unused_property_fields() - 1;
2133 if (unused_property_fields < 0) {
2134 unused_property_fields += JSObject::kFieldsAdded;
John Reck59135872010-11-02 12:39:01 -07002135 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002136 new_map->set_unused_property_fields(unused_property_fields);
John Reck59135872010-11-02 12:39:01 -07002137 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002138 } else {
2139 DCHECK(details.attributes() == attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00002140 }
2141
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002142 if (FLAG_trace_generalization) {
2143 HeapType* field_type = (details.type() == FIELD)
2144 ? map->instance_descriptors()->GetFieldType(modify_index)
2145 : NULL;
2146 map->PrintGeneralization(stdout, reason, modify_index,
2147 new_map->NumberOfOwnDescriptors(),
2148 new_map->NumberOfOwnDescriptors(),
2149 details.type() == CONSTANT && store_mode == FORCE_FIELD,
2150 details.representation(), Representation::Tagged(),
2151 field_type, HeapType::Any());
Steve Blocka7e24c12009-10-30 11:49:00 +00002152 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002153 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002154}
2155
2156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002157// static
2158Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2159 int modify_index,
2160 StoreMode store_mode,
2161 const char* reason) {
2162 PropertyDetails details =
2163 map->instance_descriptors()->GetDetails(modify_index);
2164 return CopyGeneralizeAllRepresentations(map, modify_index, store_mode,
2165 details.attributes(), reason);
2166}
Steve Blocka7e24c12009-10-30 11:49:00 +00002167
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002168
2169void Map::DeprecateTransitionTree() {
2170 if (is_deprecated()) return;
2171 if (HasTransitionArray()) {
2172 TransitionArray* transitions = this->transitions();
2173 for (int i = 0; i < transitions->number_of_transitions(); i++) {
2174 transitions->GetTarget(i)->DeprecateTransitionTree();
Steve Blocka7e24c12009-10-30 11:49:00 +00002175 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002177 deprecate();
2178 dependent_code()->DeoptimizeDependentCodeGroup(
2179 GetIsolate(), DependentCode::kTransitionGroup);
2180 NotifyLeafMapLayoutChange();
Steve Blocka7e24c12009-10-30 11:49:00 +00002181}
2182
2183
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002184// Invalidates a transition target at |key|, and installs |new_descriptors| over
2185// the current instance_descriptors to ensure proper sharing of descriptor
2186// arrays.
2187void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
2188 if (HasTransitionArray()) {
2189 TransitionArray* transitions = this->transitions();
2190 int transition = transitions->Search(key);
2191 if (transition != TransitionArray::kNotFound) {
2192 transitions->GetTarget(transition)->DeprecateTransitionTree();
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002194 }
2195
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002196 // Don't overwrite the empty descriptor array.
2197 if (NumberOfOwnDescriptors() == 0) return;
2198
2199 DescriptorArray* to_replace = instance_descriptors();
2200 Map* current = this;
2201 GetHeap()->incremental_marking()->RecordWrites(to_replace);
2202 while (current->instance_descriptors() == to_replace) {
2203 current->SetEnumLength(kInvalidEnumCacheSentinel);
2204 current->set_instance_descriptors(new_descriptors);
2205 Object* next = current->GetBackPointer();
2206 if (next->IsUndefined()) break;
2207 current = Map::cast(next);
2208 }
2209
2210 set_owns_descriptors(false);
2211}
2212
2213
2214Map* Map::FindRootMap() {
2215 Map* result = this;
2216 while (true) {
2217 Object* back = result->GetBackPointer();
2218 if (back->IsUndefined()) return result;
2219 result = Map::cast(back);
2220 }
2221}
2222
2223
2224Map* Map::FindLastMatchMap(int verbatim,
2225 int length,
2226 DescriptorArray* descriptors) {
2227 DisallowHeapAllocation no_allocation;
2228
2229 // This can only be called on roots of transition trees.
2230 DCHECK(GetBackPointer()->IsUndefined());
2231
2232 Map* current = this;
2233
2234 for (int i = verbatim; i < length; i++) {
2235 if (!current->HasTransitionArray()) break;
2236 Name* name = descriptors->GetKey(i);
2237 TransitionArray* transitions = current->transitions();
2238 int transition = transitions->Search(name);
2239 if (transition == TransitionArray::kNotFound) break;
2240
2241 Map* next = transitions->GetTarget(transition);
2242 DescriptorArray* next_descriptors = next->instance_descriptors();
2243
2244 PropertyDetails details = descriptors->GetDetails(i);
2245 PropertyDetails next_details = next_descriptors->GetDetails(i);
2246 if (details.type() != next_details.type()) break;
2247 if (details.attributes() != next_details.attributes()) break;
2248 if (!details.representation().Equals(next_details.representation())) break;
2249 if (next_details.type() == FIELD) {
2250 if (!descriptors->GetFieldType(i)->NowIs(
2251 next_descriptors->GetFieldType(i))) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002252 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002253 if (descriptors->GetValue(i) != next_descriptors->GetValue(i)) break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002254 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002255
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002256 current = next;
2257 }
2258 return current;
Steve Blocka7e24c12009-10-30 11:49:00 +00002259}
2260
2261
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002262Map* Map::FindFieldOwner(int descriptor) {
2263 DisallowHeapAllocation no_allocation;
2264 DCHECK_EQ(FIELD, instance_descriptors()->GetDetails(descriptor).type());
2265 Map* result = this;
2266 while (true) {
2267 Object* back = result->GetBackPointer();
2268 if (back->IsUndefined()) break;
2269 Map* parent = Map::cast(back);
2270 if (parent->NumberOfOwnDescriptors() <= descriptor) break;
2271 result = parent;
Steve Blocka7e24c12009-10-30 11:49:00 +00002272 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002273 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002274}
2275
2276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002277void Map::UpdateFieldType(int descriptor, Handle<Name> name,
2278 Handle<HeapType> new_type) {
2279 DisallowHeapAllocation no_allocation;
2280 PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
2281 if (details.type() != FIELD) return;
2282 if (HasTransitionArray()) {
2283 TransitionArray* transitions = this->transitions();
2284 for (int i = 0; i < transitions->number_of_transitions(); ++i) {
2285 transitions->GetTarget(i)->UpdateFieldType(descriptor, name, new_type);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002286 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002287 }
2288 // Skip if already updated the shared descriptor.
2289 if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return;
2290 FieldDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
2291 new_type, details.attributes(), details.representation());
2292 instance_descriptors()->Replace(descriptor, &d);
2293}
2294
2295
2296// static
2297Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
2298 Handle<HeapType> type2,
2299 Isolate* isolate) {
2300 static const int kMaxClassesPerFieldType = 5;
2301 if (type1->NowIs(type2)) return type2;
2302 if (type2->NowIs(type1)) return type1;
2303 if (type1->NowStable() && type2->NowStable()) {
2304 Handle<HeapType> type = HeapType::Union(type1, type2, isolate);
2305 if (type->NumClasses() <= kMaxClassesPerFieldType) {
2306 DCHECK(type->NowStable());
2307 DCHECK(type1->NowIs(type));
2308 DCHECK(type2->NowIs(type));
2309 return type;
2310 }
2311 }
2312 return HeapType::Any(isolate);
2313}
2314
2315
2316// static
2317void Map::GeneralizeFieldType(Handle<Map> map,
2318 int modify_index,
2319 Handle<HeapType> new_field_type) {
2320 Isolate* isolate = map->GetIsolate();
2321
2322 // Check if we actually need to generalize the field type at all.
2323 Handle<HeapType> old_field_type(
2324 map->instance_descriptors()->GetFieldType(modify_index), isolate);
2325 if (new_field_type->NowIs(old_field_type)) {
2326 DCHECK(Map::GeneralizeFieldType(old_field_type,
2327 new_field_type,
2328 isolate)->NowIs(old_field_type));
2329 return;
2330 }
2331
2332 // Determine the field owner.
2333 Handle<Map> field_owner(map->FindFieldOwner(modify_index), isolate);
2334 Handle<DescriptorArray> descriptors(
2335 field_owner->instance_descriptors(), isolate);
2336 DCHECK_EQ(*old_field_type, descriptors->GetFieldType(modify_index));
2337
2338 // Determine the generalized new field type.
2339 new_field_type = Map::GeneralizeFieldType(
2340 old_field_type, new_field_type, isolate);
2341
2342 PropertyDetails details = descriptors->GetDetails(modify_index);
2343 Handle<Name> name(descriptors->GetKey(modify_index));
2344 field_owner->UpdateFieldType(modify_index, name, new_field_type);
2345 field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
2346 isolate, DependentCode::kFieldTypeGroup);
2347
2348 if (FLAG_trace_generalization) {
2349 map->PrintGeneralization(
2350 stdout, "field type generalization",
2351 modify_index, map->NumberOfOwnDescriptors(),
2352 map->NumberOfOwnDescriptors(), false,
2353 details.representation(), details.representation(),
2354 *old_field_type, *new_field_type);
2355 }
2356}
2357
2358
2359// Generalize the representation of the descriptor at |modify_index|.
2360// This method rewrites the transition tree to reflect the new change. To avoid
2361// high degrees over polymorphism, and to stabilize quickly, on every rewrite
2362// the new type is deduced by merging the current type with any potential new
2363// (partial) version of the type in the transition tree.
2364// To do this, on each rewrite:
2365// - Search the root of the transition tree using FindRootMap.
2366// - Find |target_map|, the newest matching version of this map using the keys
2367// in the |old_map|'s descriptor array to walk the transition tree.
2368// - Merge/generalize the descriptor array of the |old_map| and |target_map|.
2369// - Generalize the |modify_index| descriptor using |new_representation| and
2370// |new_field_type|.
2371// - Walk the tree again starting from the root towards |target_map|. Stop at
2372// |split_map|, the first map who's descriptor array does not match the merged
2373// descriptor array.
2374// - If |target_map| == |split_map|, |target_map| is in the expected state.
2375// Return it.
2376// - Otherwise, invalidate the outdated transition target from |target_map|, and
2377// replace its transition tree with a new branch for the updated descriptors.
2378Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
2379 int modify_index,
2380 Representation new_representation,
2381 Handle<HeapType> new_field_type,
2382 StoreMode store_mode) {
2383 Isolate* isolate = old_map->GetIsolate();
2384
2385 Handle<DescriptorArray> old_descriptors(
2386 old_map->instance_descriptors(), isolate);
2387 int old_nof = old_map->NumberOfOwnDescriptors();
2388 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2389 Representation old_representation = old_details.representation();
2390
2391 // It's fine to transition from None to anything but double without any
2392 // modification to the object, because the default uninitialized value for
2393 // representation None can be overwritten by both smi and tagged values.
2394 // Doubles, however, would require a box allocation.
2395 if (old_representation.IsNone() &&
2396 !new_representation.IsNone() &&
2397 !new_representation.IsDouble()) {
2398 DCHECK(old_details.type() == FIELD);
2399 DCHECK(old_descriptors->GetFieldType(modify_index)->NowIs(
2400 HeapType::None()));
2401 if (FLAG_trace_generalization) {
2402 old_map->PrintGeneralization(
2403 stdout, "uninitialized field",
2404 modify_index, old_map->NumberOfOwnDescriptors(),
2405 old_map->NumberOfOwnDescriptors(), false,
2406 old_representation, new_representation,
2407 old_descriptors->GetFieldType(modify_index), *new_field_type);
2408 }
2409 old_descriptors->SetRepresentation(modify_index, new_representation);
2410 old_descriptors->SetValue(modify_index, *new_field_type);
2411 return old_map;
2412 }
2413
2414 // Check the state of the root map.
2415 Handle<Map> root_map(old_map->FindRootMap(), isolate);
2416 if (!old_map->EquivalentToForTransition(*root_map)) {
2417 return CopyGeneralizeAllRepresentations(
2418 old_map, modify_index, store_mode, "not equivalent");
2419 }
2420 int root_nof = root_map->NumberOfOwnDescriptors();
2421 if (modify_index < root_nof) {
2422 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2423 if ((old_details.type() != FIELD && store_mode == FORCE_FIELD) ||
2424 (old_details.type() == FIELD &&
2425 (!new_field_type->NowIs(old_descriptors->GetFieldType(modify_index)) ||
2426 !new_representation.fits_into(old_details.representation())))) {
2427 return CopyGeneralizeAllRepresentations(
2428 old_map, modify_index, store_mode, "root modification");
2429 }
2430 }
2431
2432 Handle<Map> target_map = root_map;
2433 for (int i = root_nof; i < old_nof; ++i) {
2434 int j = target_map->SearchTransition(old_descriptors->GetKey(i));
2435 if (j == TransitionArray::kNotFound) break;
2436 Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2437 Handle<DescriptorArray> tmp_descriptors = handle(
2438 tmp_map->instance_descriptors(), isolate);
2439
2440 // Check if target map is incompatible.
2441 PropertyDetails old_details = old_descriptors->GetDetails(i);
2442 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2443 PropertyType old_type = old_details.type();
2444 PropertyType tmp_type = tmp_details.type();
2445 if (tmp_details.attributes() != old_details.attributes() ||
2446 ((tmp_type == CALLBACKS || old_type == CALLBACKS) &&
2447 (tmp_type != old_type ||
2448 tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
2449 return CopyGeneralizeAllRepresentations(
2450 old_map, modify_index, store_mode, "incompatible");
2451 }
2452 Representation old_representation = old_details.representation();
2453 Representation tmp_representation = tmp_details.representation();
2454 if (!old_representation.fits_into(tmp_representation) ||
2455 (!new_representation.fits_into(tmp_representation) &&
2456 modify_index == i)) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01002457 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002458 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002459 if (tmp_type == FIELD) {
2460 // Generalize the field type as necessary.
2461 Handle<HeapType> old_field_type = (old_type == FIELD)
2462 ? handle(old_descriptors->GetFieldType(i), isolate)
2463 : old_descriptors->GetValue(i)->OptimalType(
2464 isolate, tmp_representation);
2465 if (modify_index == i) {
2466 old_field_type = GeneralizeFieldType(
2467 new_field_type, old_field_type, isolate);
2468 }
2469 GeneralizeFieldType(tmp_map, i, old_field_type);
2470 } else if (tmp_type == CONSTANT) {
2471 if (old_type != CONSTANT ||
2472 old_descriptors->GetConstant(i) != tmp_descriptors->GetConstant(i)) {
2473 break;
2474 }
2475 } else {
2476 DCHECK_EQ(tmp_type, old_type);
2477 DCHECK_EQ(tmp_descriptors->GetValue(i), old_descriptors->GetValue(i));
2478 }
2479 target_map = tmp_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002480 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002481
2482 // Directly change the map if the target map is more general.
2483 Handle<DescriptorArray> target_descriptors(
2484 target_map->instance_descriptors(), isolate);
2485 int target_nof = target_map->NumberOfOwnDescriptors();
2486 if (target_nof == old_nof &&
2487 (store_mode != FORCE_FIELD ||
2488 target_descriptors->GetDetails(modify_index).type() == FIELD)) {
2489 DCHECK(modify_index < target_nof);
2490 DCHECK(new_representation.fits_into(
2491 target_descriptors->GetDetails(modify_index).representation()));
2492 DCHECK(target_descriptors->GetDetails(modify_index).type() != FIELD ||
2493 new_field_type->NowIs(
2494 target_descriptors->GetFieldType(modify_index)));
2495 return target_map;
2496 }
2497
2498 // Find the last compatible target map in the transition tree.
2499 for (int i = target_nof; i < old_nof; ++i) {
2500 int j = target_map->SearchTransition(old_descriptors->GetKey(i));
2501 if (j == TransitionArray::kNotFound) break;
2502 Handle<Map> tmp_map(target_map->GetTransition(j), isolate);
2503 Handle<DescriptorArray> tmp_descriptors(
2504 tmp_map->instance_descriptors(), isolate);
2505
2506 // Check if target map is compatible.
2507 PropertyDetails old_details = old_descriptors->GetDetails(i);
2508 PropertyDetails tmp_details = tmp_descriptors->GetDetails(i);
2509 if (tmp_details.attributes() != old_details.attributes() ||
2510 ((tmp_details.type() == CALLBACKS || old_details.type() == CALLBACKS) &&
2511 (tmp_details.type() != old_details.type() ||
2512 tmp_descriptors->GetValue(i) != old_descriptors->GetValue(i)))) {
2513 return CopyGeneralizeAllRepresentations(
2514 old_map, modify_index, store_mode, "incompatible");
2515 }
2516 target_map = tmp_map;
2517 }
2518 target_nof = target_map->NumberOfOwnDescriptors();
2519 target_descriptors = handle(target_map->instance_descriptors(), isolate);
2520
2521 // Allocate a new descriptor array large enough to hold the required
2522 // descriptors, with minimally the exact same size as the old descriptor
2523 // array.
2524 int new_slack = Max(
2525 old_nof, old_descriptors->number_of_descriptors()) - old_nof;
2526 Handle<DescriptorArray> new_descriptors = DescriptorArray::Allocate(
2527 isolate, old_nof, new_slack);
2528 DCHECK(new_descriptors->length() > target_descriptors->length() ||
2529 new_descriptors->NumberOfSlackDescriptors() > 0 ||
2530 new_descriptors->number_of_descriptors() ==
2531 old_descriptors->number_of_descriptors());
2532 DCHECK(new_descriptors->number_of_descriptors() == old_nof);
2533
2534 // 0 -> |root_nof|
2535 int current_offset = 0;
2536 for (int i = 0; i < root_nof; ++i) {
2537 PropertyDetails old_details = old_descriptors->GetDetails(i);
2538 if (old_details.type() == FIELD) current_offset++;
2539 Descriptor d(handle(old_descriptors->GetKey(i), isolate),
2540 handle(old_descriptors->GetValue(i), isolate),
2541 old_details);
2542 new_descriptors->Set(i, &d);
2543 }
2544
2545 // |root_nof| -> |target_nof|
2546 for (int i = root_nof; i < target_nof; ++i) {
2547 Handle<Name> target_key(target_descriptors->GetKey(i), isolate);
2548 PropertyDetails old_details = old_descriptors->GetDetails(i);
2549 PropertyDetails target_details = target_descriptors->GetDetails(i);
2550 target_details = target_details.CopyWithRepresentation(
2551 old_details.representation().generalize(
2552 target_details.representation()));
2553 if (modify_index == i) {
2554 target_details = target_details.CopyWithRepresentation(
2555 new_representation.generalize(target_details.representation()));
2556 }
2557 DCHECK_EQ(old_details.attributes(), target_details.attributes());
2558 if (old_details.type() == FIELD ||
2559 target_details.type() == FIELD ||
2560 (modify_index == i && store_mode == FORCE_FIELD) ||
2561 (target_descriptors->GetValue(i) != old_descriptors->GetValue(i))) {
2562 Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2563 ? handle(old_descriptors->GetFieldType(i), isolate)
2564 : old_descriptors->GetValue(i)->OptimalType(
2565 isolate, target_details.representation());
2566 Handle<HeapType> target_field_type = (target_details.type() == FIELD)
2567 ? handle(target_descriptors->GetFieldType(i), isolate)
2568 : target_descriptors->GetValue(i)->OptimalType(
2569 isolate, target_details.representation());
2570 target_field_type = GeneralizeFieldType(
2571 target_field_type, old_field_type, isolate);
2572 if (modify_index == i) {
2573 target_field_type = GeneralizeFieldType(
2574 target_field_type, new_field_type, isolate);
2575 }
2576 FieldDescriptor d(target_key,
2577 current_offset++,
2578 target_field_type,
2579 target_details.attributes(),
2580 target_details.representation());
2581 new_descriptors->Set(i, &d);
2582 } else {
2583 DCHECK_NE(FIELD, target_details.type());
2584 Descriptor d(target_key,
2585 handle(target_descriptors->GetValue(i), isolate),
2586 target_details);
2587 new_descriptors->Set(i, &d);
2588 }
2589 }
2590
2591 // |target_nof| -> |old_nof|
2592 for (int i = target_nof; i < old_nof; ++i) {
2593 PropertyDetails old_details = old_descriptors->GetDetails(i);
2594 Handle<Name> old_key(old_descriptors->GetKey(i), isolate);
2595 if (modify_index == i) {
2596 old_details = old_details.CopyWithRepresentation(
2597 new_representation.generalize(old_details.representation()));
2598 }
2599 if (old_details.type() == FIELD) {
2600 Handle<HeapType> old_field_type(
2601 old_descriptors->GetFieldType(i), isolate);
2602 if (modify_index == i) {
2603 old_field_type = GeneralizeFieldType(
2604 old_field_type, new_field_type, isolate);
2605 }
2606 FieldDescriptor d(old_key,
2607 current_offset++,
2608 old_field_type,
2609 old_details.attributes(),
2610 old_details.representation());
2611 new_descriptors->Set(i, &d);
2612 } else {
2613 DCHECK(old_details.type() == CONSTANT || old_details.type() == CALLBACKS);
2614 if (modify_index == i && store_mode == FORCE_FIELD) {
2615 FieldDescriptor d(old_key,
2616 current_offset++,
2617 GeneralizeFieldType(
2618 old_descriptors->GetValue(i)->OptimalType(
2619 isolate, old_details.representation()),
2620 new_field_type, isolate),
2621 old_details.attributes(),
2622 old_details.representation());
2623 new_descriptors->Set(i, &d);
2624 } else {
2625 DCHECK_NE(FIELD, old_details.type());
2626 Descriptor d(old_key,
2627 handle(old_descriptors->GetValue(i), isolate),
2628 old_details);
2629 new_descriptors->Set(i, &d);
2630 }
2631 }
2632 }
2633
2634 new_descriptors->Sort();
2635
2636 DCHECK(store_mode != FORCE_FIELD ||
2637 new_descriptors->GetDetails(modify_index).type() == FIELD);
2638
2639 Handle<Map> split_map(root_map->FindLastMatchMap(
2640 root_nof, old_nof, *new_descriptors), isolate);
2641 int split_nof = split_map->NumberOfOwnDescriptors();
2642 DCHECK_NE(old_nof, split_nof);
2643
2644 split_map->DeprecateTarget(
2645 old_descriptors->GetKey(split_nof), *new_descriptors);
2646
2647 if (FLAG_trace_generalization) {
2648 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2649 PropertyDetails new_details = new_descriptors->GetDetails(modify_index);
2650 Handle<HeapType> old_field_type = (old_details.type() == FIELD)
2651 ? handle(old_descriptors->GetFieldType(modify_index), isolate)
2652 : HeapType::Constant(handle(old_descriptors->GetValue(modify_index),
2653 isolate), isolate);
2654 Handle<HeapType> new_field_type = (new_details.type() == FIELD)
2655 ? handle(new_descriptors->GetFieldType(modify_index), isolate)
2656 : HeapType::Constant(handle(new_descriptors->GetValue(modify_index),
2657 isolate), isolate);
2658 old_map->PrintGeneralization(
2659 stdout, "", modify_index, split_nof, old_nof,
2660 old_details.type() == CONSTANT && store_mode == FORCE_FIELD,
2661 old_details.representation(), new_details.representation(),
2662 *old_field_type, *new_field_type);
2663 }
2664
2665 // Add missing transitions.
2666 Handle<Map> new_map = split_map;
2667 for (int i = split_nof; i < old_nof; ++i) {
2668 new_map = CopyInstallDescriptors(new_map, i, new_descriptors);
2669 }
2670 new_map->set_owns_descriptors(true);
2671 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00002672}
2673
2674
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002675// Generalize the representation of all FIELD descriptors.
2676Handle<Map> Map::GeneralizeAllFieldRepresentations(
2677 Handle<Map> map) {
2678 Handle<DescriptorArray> descriptors(map->instance_descriptors());
2679 for (int i = 0; i < map->NumberOfOwnDescriptors(); ++i) {
2680 if (descriptors->GetDetails(i).type() == FIELD) {
2681 map = GeneralizeRepresentation(map, i, Representation::Tagged(),
2682 HeapType::Any(map->GetIsolate()),
2683 FORCE_FIELD);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002684 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002685 }
2686 return map;
2687}
2688
2689
2690// static
2691MaybeHandle<Map> Map::TryUpdate(Handle<Map> map) {
2692 Handle<Map> proto_map(map);
2693 while (proto_map->prototype()->IsJSObject()) {
2694 Handle<JSObject> holder(JSObject::cast(proto_map->prototype()));
2695 proto_map = Handle<Map>(holder->map());
2696 if (proto_map->is_deprecated() && JSObject::TryMigrateInstance(holder)) {
2697 proto_map = Handle<Map>(holder->map());
2698 }
2699 }
2700 return TryUpdateInternal(map);
2701}
2702
2703
2704// static
2705Handle<Map> Map::Update(Handle<Map> map) {
2706 if (!map->is_deprecated()) return map;
2707 return GeneralizeRepresentation(map, 0, Representation::None(),
2708 HeapType::None(map->GetIsolate()),
2709 ALLOW_AS_CONSTANT);
2710}
2711
2712
2713// static
2714MaybeHandle<Map> Map::TryUpdateInternal(Handle<Map> old_map) {
2715 DisallowHeapAllocation no_allocation;
2716 DisallowDeoptimization no_deoptimization(old_map->GetIsolate());
2717
2718 if (!old_map->is_deprecated()) return old_map;
2719
2720 // Check the state of the root map.
2721 Map* root_map = old_map->FindRootMap();
2722 if (!old_map->EquivalentToForTransition(root_map)) return MaybeHandle<Map>();
2723 int root_nof = root_map->NumberOfOwnDescriptors();
2724
2725 int old_nof = old_map->NumberOfOwnDescriptors();
2726 DescriptorArray* old_descriptors = old_map->instance_descriptors();
2727
2728 Map* new_map = root_map;
2729 for (int i = root_nof; i < old_nof; ++i) {
2730 int j = new_map->SearchTransition(old_descriptors->GetKey(i));
2731 if (j == TransitionArray::kNotFound) return MaybeHandle<Map>();
2732 new_map = new_map->GetTransition(j);
2733 DescriptorArray* new_descriptors = new_map->instance_descriptors();
2734
2735 PropertyDetails new_details = new_descriptors->GetDetails(i);
2736 PropertyDetails old_details = old_descriptors->GetDetails(i);
2737 if (old_details.attributes() != new_details.attributes() ||
2738 !old_details.representation().fits_into(new_details.representation())) {
2739 return MaybeHandle<Map>();
2740 }
2741 PropertyType new_type = new_details.type();
2742 PropertyType old_type = old_details.type();
2743 Object* new_value = new_descriptors->GetValue(i);
2744 Object* old_value = old_descriptors->GetValue(i);
2745 switch (new_type) {
2746 case FIELD:
2747 if ((old_type == FIELD &&
2748 !HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) ||
2749 (old_type == CONSTANT &&
2750 !HeapType::cast(new_value)->NowContains(old_value)) ||
2751 (old_type == CALLBACKS &&
2752 !HeapType::Any()->Is(HeapType::cast(new_value)))) {
2753 return MaybeHandle<Map>();
2754 }
2755 break;
2756
2757 case CONSTANT:
2758 case CALLBACKS:
2759 if (old_type != new_type || old_value != new_value) {
2760 return MaybeHandle<Map>();
2761 }
2762 break;
2763
2764 case NORMAL:
2765 UNREACHABLE();
2766 }
2767 }
2768 if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
2769 return handle(new_map);
2770}
2771
2772
2773MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
2774 Handle<Object> value) {
2775 // TODO(rossberg): Support symbols in the API.
2776 if (it->name()->IsSymbol()) return value;
2777
2778 Handle<String> name_string = Handle<String>::cast(it->name());
2779 Handle<JSObject> holder = it->GetHolder<JSObject>();
2780 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
2781 if (interceptor->setter()->IsUndefined()) return MaybeHandle<Object>();
2782
2783 LOG(it->isolate(),
2784 ApiNamedPropertyAccess("interceptor-named-set", *holder, *name_string));
2785 PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder,
2786 *holder);
2787 v8::NamedPropertySetterCallback setter =
2788 v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
2789 v8::Handle<v8::Value> result = args.Call(
2790 setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value));
2791 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
2792 if (!result.IsEmpty()) return value;
2793
2794 return MaybeHandle<Object>();
2795}
2796
2797
2798MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
2799 Handle<Name> name, Handle<Object> value,
2800 StrictMode strict_mode,
2801 StoreFromKeyed store_mode) {
2802 LookupIterator it(object, name);
2803 return SetProperty(&it, value, strict_mode, store_mode);
2804}
2805
2806
2807MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
2808 Handle<Object> value,
2809 StrictMode strict_mode,
2810 StoreFromKeyed store_mode) {
2811 // Make sure that the top context does not change when doing callbacks or
2812 // interceptor calls.
2813 AssertNoContextChange ncc(it->isolate());
2814
2815 bool done = false;
2816 for (; it->IsFound(); it->Next()) {
2817 switch (it->state()) {
2818 case LookupIterator::NOT_FOUND:
2819 UNREACHABLE();
2820
2821 case LookupIterator::ACCESS_CHECK:
2822 // TODO(verwaest): Remove the distinction. This is mostly bogus since we
2823 // don't know whether we'll want to fetch attributes or call a setter
2824 // until we find the property.
2825 if (it->HasAccess(v8::ACCESS_SET)) break;
2826 return JSObject::SetPropertyWithFailedAccessCheck(it, value,
2827 strict_mode);
2828
2829 case LookupIterator::JSPROXY:
2830 if (it->HolderIsReceiverOrHiddenPrototype()) {
2831 return JSProxy::SetPropertyWithHandler(it->GetHolder<JSProxy>(),
2832 it->GetReceiver(), it->name(),
2833 value, strict_mode);
2834 } else {
2835 // TODO(verwaest): Use the MaybeHandle to indicate result.
2836 bool has_result = false;
2837 MaybeHandle<Object> maybe_result =
2838 JSProxy::SetPropertyViaPrototypesWithHandler(
2839 it->GetHolder<JSProxy>(), it->GetReceiver(), it->name(),
2840 value, strict_mode, &has_result);
2841 if (has_result) return maybe_result;
2842 done = true;
2843 }
2844 break;
2845
2846 case LookupIterator::INTERCEPTOR:
2847 if (it->HolderIsReceiverOrHiddenPrototype()) {
2848 MaybeHandle<Object> maybe_result =
2849 JSObject::SetPropertyWithInterceptor(it, value);
2850 if (!maybe_result.is_null()) return maybe_result;
2851 if (it->isolate()->has_pending_exception()) return maybe_result;
2852 } else {
2853 Maybe<PropertyAttributes> maybe_attributes =
2854 JSObject::GetPropertyAttributesWithInterceptor(
2855 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
2856 if (!maybe_attributes.has_value) return MaybeHandle<Object>();
2857 done = maybe_attributes.value != ABSENT;
2858 if (done && (maybe_attributes.value & READ_ONLY) != 0) {
2859 return WriteToReadOnlyProperty(it, value, strict_mode);
2860 }
2861 }
2862 break;
2863
2864 case LookupIterator::ACCESSOR:
2865 if (it->property_details().IsReadOnly()) {
2866 return WriteToReadOnlyProperty(it, value, strict_mode);
2867 }
2868 if (it->HolderIsReceiverOrHiddenPrototype() ||
2869 !it->GetAccessors()->IsDeclaredAccessorInfo()) {
2870 return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
2871 it->GetHolder<JSObject>(),
2872 it->GetAccessors(), strict_mode);
2873 }
2874 done = true;
2875 break;
2876
2877 case LookupIterator::DATA:
2878 if (it->property_details().IsReadOnly()) {
2879 return WriteToReadOnlyProperty(it, value, strict_mode);
2880 }
2881 if (it->HolderIsReceiverOrHiddenPrototype()) {
2882 return SetDataProperty(it, value);
2883 }
2884 done = true;
2885 break;
2886
2887 case LookupIterator::TRANSITION:
2888 done = true;
2889 break;
2890 }
2891
2892 if (done) break;
2893 }
2894
2895 // If the receiver is the JSGlobalObject, the store was contextual. In case
2896 // the property did not exist yet on the global object itself, we have to
2897 // throw a reference error in strict mode.
2898 if (it->GetReceiver()->IsJSGlobalObject() && strict_mode == STRICT) {
2899 Handle<Object> args[1] = {it->name()};
2900 THROW_NEW_ERROR(it->isolate(),
2901 NewReferenceError("not_defined", HandleVector(args, 1)),
2902 Object);
2903 }
2904
2905 return AddDataProperty(it, value, NONE, strict_mode, store_mode);
2906}
2907
2908
2909MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it,
2910 Handle<Object> value,
2911 StrictMode strict_mode) {
2912 if (strict_mode != STRICT) return value;
2913
2914 Handle<Object> args[] = {it->name(), it->GetReceiver()};
2915 THROW_NEW_ERROR(it->isolate(),
2916 NewTypeError("strict_read_only_property",
2917 HandleVector(args, arraysize(args))),
2918 Object);
2919}
2920
2921
2922Handle<Object> Object::SetDataProperty(LookupIterator* it,
2923 Handle<Object> value) {
2924 // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
2925 // have own properties.
2926 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
2927
2928 // Store on the holder which may be hidden behind the receiver.
2929 DCHECK(it->HolderIsReceiverOrHiddenPrototype());
2930
2931 // Old value for the observation change record.
2932 // Fetch before transforming the object since the encoding may become
2933 // incompatible with what's cached in |it|.
2934 bool is_observed =
2935 receiver->map()->is_observed() &&
2936 !it->name().is_identical_to(it->factory()->hidden_string());
2937 MaybeHandle<Object> maybe_old;
2938 if (is_observed) maybe_old = it->GetDataValue();
2939
2940 // Possibly migrate to the most up-to-date map that will be able to store
2941 // |value| under it->name().
2942 it->PrepareForDataProperty(value);
2943
2944 // Write the property value.
2945 it->WriteDataValue(value);
2946
2947 // Send the change record if there are observers.
2948 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
2949 JSObject::EnqueueChangeRecord(receiver, "update", it->name(),
2950 maybe_old.ToHandleChecked());
2951 }
2952
2953 return value;
2954}
2955
2956
2957MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
2958 Handle<Object> value,
2959 PropertyAttributes attributes,
2960 StrictMode strict_mode,
2961 StoreFromKeyed store_mode) {
2962 DCHECK(!it->GetReceiver()->IsJSProxy());
2963 if (!it->GetReceiver()->IsJSObject()) {
2964 // TODO(verwaest): Throw a TypeError with a more specific message.
2965 return WriteToReadOnlyProperty(it, value, strict_mode);
2966 }
2967
2968 Handle<JSObject> receiver = it->GetStoreTarget();
2969
2970 // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
2971 // instead. If the prototype is Null, the proxy is detached.
2972 if (receiver->IsJSGlobalProxy()) return value;
2973
2974 // Possibly migrate to the most up-to-date map that will be able to store
2975 // |value| under it->name() with |attributes|.
2976 it->PrepareTransitionToDataProperty(value, attributes, store_mode);
2977 if (it->state() != LookupIterator::TRANSITION) {
2978 if (strict_mode == SLOPPY) return value;
2979
2980 Handle<Object> args[1] = {it->name()};
2981 THROW_NEW_ERROR(it->isolate(),
2982 NewTypeError("object_not_extensible",
2983 HandleVector(args, arraysize(args))),
2984 Object);
2985 }
2986 it->ApplyTransitionToDataProperty();
2987
2988 // TODO(verwaest): Encapsulate dictionary handling better.
2989 if (receiver->map()->is_dictionary_map()) {
2990 // TODO(verwaest): Probably should ensure this is done beforehand.
2991 it->InternalizeName();
2992 JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
2993 } else {
2994 // Write the property value.
2995 it->WriteDataValue(value);
2996 }
2997
2998 // Send the change record if there are observers.
2999 if (receiver->map()->is_observed() &&
3000 !it->name().is_identical_to(it->factory()->hidden_string())) {
3001 JSObject::EnqueueChangeRecord(receiver, "add", it->name(),
3002 it->factory()->the_hole_value());
3003 }
3004
3005 return value;
3006}
3007
3008
3009MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
3010 Handle<JSObject> object,
3011 uint32_t index,
3012 Handle<Object> value,
3013 bool* found,
3014 StrictMode strict_mode) {
3015 Isolate *isolate = object->GetIsolate();
3016 for (PrototypeIterator iter(isolate, object); !iter.IsAtEnd();
3017 iter.Advance()) {
3018 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
3019 return JSProxy::SetPropertyViaPrototypesWithHandler(
3020 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), object,
3021 isolate->factory()->Uint32ToString(index), // name
3022 value, strict_mode, found);
3023 }
3024 Handle<JSObject> js_proto =
3025 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
3026 if (!js_proto->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003027 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00003028 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003029 Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary());
Steve Blocka7e24c12009-10-30 11:49:00 +00003030 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00003031 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003032 PropertyDetails details = dictionary->DetailsAt(entry);
3033 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01003034 *found = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003035 Handle<Object> structure(dictionary->ValueAt(entry), isolate);
3036 return SetElementWithCallback(object, structure, index, value, js_proto,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003037 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003038 }
3039 }
3040 }
Steve Block1e0659c2011-05-24 12:43:12 +01003041 *found = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003042 return isolate->factory()->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003043}
3044
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003045
3046void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
3047 // Only supports adding slack to owned descriptors.
3048 DCHECK(map->owns_descriptors());
3049
3050 Handle<DescriptorArray> descriptors(map->instance_descriptors());
3051 int old_size = map->NumberOfOwnDescriptors();
3052 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
3053
3054 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
3055 descriptors, old_size, slack);
3056
3057 if (old_size == 0) {
3058 map->set_instance_descriptors(*new_descriptors);
3059 return;
3060 }
3061
3062 // If the source descriptors had an enum cache we copy it. This ensures
3063 // that the maps to which we push the new descriptor array back can rely
3064 // on a cache always being available once it is set. If the map has more
3065 // enumerated descriptors than available in the original cache, the cache
3066 // will be lazily replaced by the extended cache when needed.
3067 if (descriptors->HasEnumCache()) {
3068 new_descriptors->CopyEnumCacheFrom(*descriptors);
3069 }
3070
3071 // Replace descriptors by new_descriptors in all maps that share it.
3072 map->GetHeap()->incremental_marking()->RecordWrites(*descriptors);
3073
3074 Map* walk_map;
3075 for (Object* current = map->GetBackPointer();
3076 !current->IsUndefined();
3077 current = walk_map->GetBackPointer()) {
3078 walk_map = Map::cast(current);
3079 if (walk_map->instance_descriptors() != *descriptors) break;
3080 walk_map->set_instance_descriptors(*new_descriptors);
3081 }
3082
3083 map->set_instance_descriptors(*new_descriptors);
3084}
3085
3086
3087template<class T>
3088static int AppendUniqueCallbacks(NeanderArray* callbacks,
3089 Handle<typename T::Array> array,
3090 int valid_descriptors) {
3091 int nof_callbacks = callbacks->length();
3092
3093 Isolate* isolate = array->GetIsolate();
3094 // Ensure the keys are unique names before writing them into the
3095 // instance descriptor. Since it may cause a GC, it has to be done before we
3096 // temporarily put the heap in an invalid state while appending descriptors.
3097 for (int i = 0; i < nof_callbacks; ++i) {
3098 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3099 if (entry->name()->IsUniqueName()) continue;
3100 Handle<String> key =
3101 isolate->factory()->InternalizeString(
3102 Handle<String>(String::cast(entry->name())));
3103 entry->set_name(*key);
3104 }
3105
3106 // Fill in new callback descriptors. Process the callbacks from
3107 // back to front so that the last callback with a given name takes
3108 // precedence over previously added callbacks with that name.
3109 for (int i = nof_callbacks - 1; i >= 0; i--) {
3110 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3111 Handle<Name> key(Name::cast(entry->name()));
3112 // Check if a descriptor with this name already exists before writing.
3113 if (!T::Contains(key, entry, valid_descriptors, array)) {
3114 T::Insert(key, entry, valid_descriptors, array);
3115 valid_descriptors++;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003116 }
3117 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003118
3119 return valid_descriptors;
3120}
3121
3122struct DescriptorArrayAppender {
3123 typedef DescriptorArray Array;
3124 static bool Contains(Handle<Name> key,
3125 Handle<AccessorInfo> entry,
3126 int valid_descriptors,
3127 Handle<DescriptorArray> array) {
3128 DisallowHeapAllocation no_gc;
3129 return array->Search(*key, valid_descriptors) != DescriptorArray::kNotFound;
3130 }
3131 static void Insert(Handle<Name> key,
3132 Handle<AccessorInfo> entry,
3133 int valid_descriptors,
3134 Handle<DescriptorArray> array) {
3135 DisallowHeapAllocation no_gc;
3136 CallbacksDescriptor desc(key, entry, entry->property_attributes());
3137 array->Append(&desc);
3138 }
3139};
3140
3141
3142struct FixedArrayAppender {
3143 typedef FixedArray Array;
3144 static bool Contains(Handle<Name> key,
3145 Handle<AccessorInfo> entry,
3146 int valid_descriptors,
3147 Handle<FixedArray> array) {
3148 for (int i = 0; i < valid_descriptors; i++) {
3149 if (*key == AccessorInfo::cast(array->get(i))->name()) return true;
3150 }
3151 return false;
3152 }
3153 static void Insert(Handle<Name> key,
3154 Handle<AccessorInfo> entry,
3155 int valid_descriptors,
3156 Handle<FixedArray> array) {
3157 DisallowHeapAllocation no_gc;
3158 array->set(valid_descriptors, *entry);
3159 }
3160};
3161
3162
3163void Map::AppendCallbackDescriptors(Handle<Map> map,
3164 Handle<Object> descriptors) {
3165 int nof = map->NumberOfOwnDescriptors();
3166 Handle<DescriptorArray> array(map->instance_descriptors());
3167 NeanderArray callbacks(descriptors);
3168 DCHECK(array->NumberOfSlackDescriptors() >= callbacks.length());
3169 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
3170 map->SetNumberOfOwnDescriptors(nof);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003171}
3172
Steve Blocka7e24c12009-10-30 11:49:00 +00003173
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003174int AccessorInfo::AppendUnique(Handle<Object> descriptors,
3175 Handle<FixedArray> array,
3176 int valid_descriptors) {
3177 NeanderArray callbacks(descriptors);
3178 DCHECK(array->length() >= callbacks.length() + valid_descriptors);
3179 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
3180 array,
3181 valid_descriptors);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003182}
3183
3184
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003185static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003186 DCHECK(!map.is_null());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003187 for (int i = 0; i < maps->length(); ++i) {
3188 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
3189 }
3190 return false;
3191}
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003192
Ben Murdoch85b71792012-04-11 18:30:58 +01003193
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003194template <class T>
3195static Handle<T> MaybeNull(T* p) {
3196 if (p == NULL) return Handle<T>::null();
3197 return Handle<T>(p);
3198}
3199
3200
3201Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003202 ElementsKind kind = elements_kind();
3203 Handle<Map> transitioned_map = Handle<Map>::null();
3204 Handle<Map> current_map(this);
3205 bool packed = IsFastPackedElementsKind(kind);
3206 if (IsTransitionableFastElementsKind(kind)) {
3207 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
3208 kind = GetNextMoreGeneralFastElementsKind(kind, false);
3209 Handle<Map> maybe_transitioned_map =
3210 MaybeNull(current_map->LookupElementsTransitionMap(kind));
3211 if (maybe_transitioned_map.is_null()) break;
3212 if (ContainsMap(candidates, maybe_transitioned_map) &&
3213 (packed || !IsFastPackedElementsKind(kind))) {
3214 transitioned_map = maybe_transitioned_map;
3215 if (!IsFastPackedElementsKind(kind)) packed = false;
3216 }
3217 current_map = maybe_transitioned_map;
Ben Murdoch85b71792012-04-11 18:30:58 +01003218 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003219 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003220 return transitioned_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003221}
Ben Murdoch85b71792012-04-11 18:30:58 +01003222
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003223
3224static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
3225 Map* current_map = map;
3226 int target_kind =
3227 IsFastElementsKind(to_kind) || IsExternalArrayElementsKind(to_kind)
3228 ? to_kind
3229 : TERMINAL_FAST_ELEMENTS_KIND;
3230
3231 // Support for legacy API: SetIndexedPropertiesTo{External,Pixel}Data
3232 // allows to change elements from arbitrary kind to any ExternalArray
3233 // elements kind. Satisfy its requirements, checking whether we already
3234 // have the cached transition.
3235 if (IsExternalArrayElementsKind(to_kind) &&
3236 !IsFixedTypedArrayElementsKind(map->elements_kind())) {
3237 if (map->HasElementsTransition()) {
3238 Map* next_map = map->elements_transition_map();
3239 if (next_map->elements_kind() == to_kind) return next_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003240 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003241 return map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003242 }
3243
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003244 ElementsKind kind = map->elements_kind();
3245 while (kind != target_kind) {
3246 kind = GetNextTransitionElementsKind(kind);
3247 if (!current_map->HasElementsTransition()) return current_map;
3248 current_map = current_map->elements_transition_map();
3249 }
3250
3251 if (to_kind != kind && current_map->HasElementsTransition()) {
3252 DCHECK(to_kind == DICTIONARY_ELEMENTS);
3253 Map* next_map = current_map->elements_transition_map();
3254 if (next_map->elements_kind() == to_kind) return next_map;
3255 }
3256
3257 DCHECK(current_map->elements_kind() == target_kind);
3258 return current_map;
3259}
3260
3261
3262Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
3263 Map* to_map = FindClosestElementsTransition(this, to_kind);
3264 if (to_map->elements_kind() == to_kind) return to_map;
3265 return NULL;
3266}
3267
3268
3269bool Map::IsMapInArrayPrototypeChain() {
3270 Isolate* isolate = GetIsolate();
3271 if (isolate->initial_array_prototype()->map() == this) {
3272 return true;
3273 }
3274
3275 if (isolate->initial_object_prototype()->map() == this) {
3276 return true;
3277 }
3278
3279 return false;
3280}
3281
3282
3283static Handle<Map> AddMissingElementsTransitions(Handle<Map> map,
3284 ElementsKind to_kind) {
3285 DCHECK(IsTransitionElementsKind(map->elements_kind()));
3286
3287 Handle<Map> current_map = map;
3288
3289 ElementsKind kind = map->elements_kind();
3290 if (!map->is_prototype_map()) {
3291 while (kind != to_kind && !IsTerminalElementsKind(kind)) {
3292 kind = GetNextTransitionElementsKind(kind);
3293 current_map =
3294 Map::CopyAsElementsKind(current_map, kind, INSERT_TRANSITION);
3295 }
3296 }
3297
3298 // In case we are exiting the fast elements kind system, just add the map in
3299 // the end.
3300 if (kind != to_kind) {
3301 current_map = Map::CopyAsElementsKind(
3302 current_map, to_kind, INSERT_TRANSITION);
3303 }
3304
3305 DCHECK(current_map->elements_kind() == to_kind);
3306 return current_map;
3307}
3308
3309
3310Handle<Map> Map::TransitionElementsTo(Handle<Map> map,
3311 ElementsKind to_kind) {
3312 ElementsKind from_kind = map->elements_kind();
3313 if (from_kind == to_kind) return map;
3314
3315 Isolate* isolate = map->GetIsolate();
3316 Context* native_context = isolate->context()->native_context();
3317 Object* maybe_array_maps = native_context->js_array_maps();
3318 if (maybe_array_maps->IsFixedArray()) {
3319 DisallowHeapAllocation no_gc;
3320 FixedArray* array_maps = FixedArray::cast(maybe_array_maps);
3321 if (array_maps->get(from_kind) == *map) {
3322 Object* maybe_transitioned_map = array_maps->get(to_kind);
3323 if (maybe_transitioned_map->IsMap()) {
3324 return handle(Map::cast(maybe_transitioned_map));
Ben Murdoch85b71792012-04-11 18:30:58 +01003325 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00003326 }
3327 }
3328
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003329 return TransitionElementsToSlow(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003330}
3331
3332
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003333Handle<Map> Map::TransitionElementsToSlow(Handle<Map> map,
3334 ElementsKind to_kind) {
3335 ElementsKind from_kind = map->elements_kind();
3336
3337 if (from_kind == to_kind) {
3338 return map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003339 }
3340
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003341 bool allow_store_transition =
3342 // Only remember the map transition if there is not an already existing
3343 // non-matching element transition.
3344 !map->IsUndefined() && !map->is_dictionary_map() &&
3345 IsTransitionElementsKind(from_kind);
3346
3347 // Only store fast element maps in ascending generality.
3348 if (IsFastElementsKind(to_kind)) {
3349 allow_store_transition &=
3350 IsTransitionableFastElementsKind(from_kind) &&
3351 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003352 }
3353
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003354 if (!allow_store_transition) {
3355 return Map::CopyAsElementsKind(map, to_kind, OMIT_TRANSITION);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003356 }
3357
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003358 return Map::AsElementsKind(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003359}
3360
3361
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003362// static
3363Handle<Map> Map::AsElementsKind(Handle<Map> map, ElementsKind kind) {
3364 Handle<Map> closest_map(FindClosestElementsTransition(*map, kind));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003365
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003366 if (closest_map->elements_kind() == kind) {
3367 return closest_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003368 }
3369
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003370 return AddMissingElementsTransitions(closest_map, kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003371}
3372
3373
3374Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3375 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003376 Handle<Map> map(object->map());
3377 return Map::TransitionElementsTo(map, to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003378}
3379
3380
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003381Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
3382 Handle<Name> name) {
3383 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003384
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003385 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3386 if (name->IsSymbol()) return maybe(false);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003387
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003388 Handle<Object> args[] = { name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003389 Handle<Object> result;
3390 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3391 isolate, result, CallTrap(proxy, "has", isolate->derived_has_trap(),
3392 arraysize(args), args),
3393 Maybe<bool>());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003394
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003395 return maybe(result->BooleanValue());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003396}
3397
3398
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003399MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
3400 Handle<Object> receiver,
3401 Handle<Name> name,
3402 Handle<Object> value,
3403 StrictMode strict_mode) {
3404 Isolate* isolate = proxy->GetIsolate();
3405
3406 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3407 if (name->IsSymbol()) return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003408
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003409 Handle<Object> args[] = { receiver, name, value };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003410 RETURN_ON_EXCEPTION(
3411 isolate,
3412 CallTrap(proxy,
3413 "set",
3414 isolate->derived_set_trap(),
3415 arraysize(args),
3416 args),
3417 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003418
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003419 return value;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003420}
3421
3422
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003423MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
3424 Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
3425 Handle<Object> value, StrictMode strict_mode, bool* done) {
3426 Isolate* isolate = proxy->GetIsolate();
3427 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003428
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003429 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3430 if (name->IsSymbol()) {
3431 *done = false;
3432 return isolate->factory()->the_hole_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003433 }
3434
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003435 *done = true; // except where redefined...
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003436 Handle<Object> args[] = { name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003437 Handle<Object> result;
3438 ASSIGN_RETURN_ON_EXCEPTION(
3439 isolate, result,
3440 CallTrap(proxy,
3441 "getPropertyDescriptor",
3442 Handle<Object>(),
3443 arraysize(args),
3444 args),
3445 Object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003446
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003447 if (result->IsUndefined()) {
3448 *done = false;
3449 return isolate->factory()->the_hole_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003450 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003451
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003452 // Emulate [[GetProperty]] semantics for proxies.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003453 Handle<Object> argv[] = { result };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003454 Handle<Object> desc;
3455 ASSIGN_RETURN_ON_EXCEPTION(
3456 isolate, desc,
3457 Execution::Call(isolate,
3458 isolate->to_complete_property_descriptor(),
3459 result,
3460 arraysize(argv),
3461 argv),
3462 Object);
3463
3464 // [[GetProperty]] requires to check that all properties are configurable.
3465 Handle<String> configurable_name =
3466 isolate->factory()->InternalizeOneByteString(
3467 STATIC_CHAR_VECTOR("configurable_"));
3468 Handle<Object> configurable =
3469 Object::GetProperty(desc, configurable_name).ToHandleChecked();
3470 DCHECK(configurable->IsBoolean());
3471 if (configurable->IsFalse()) {
3472 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3473 STATIC_CHAR_VECTOR("getPropertyDescriptor"));
3474 Handle<Object> args[] = { handler, trap, name };
3475 THROW_NEW_ERROR(isolate, NewTypeError("proxy_prop_not_configurable",
3476 HandleVector(args, arraysize(args))),
3477 Object);
3478 }
3479 DCHECK(configurable->IsTrue());
3480
3481 // Check for DataDescriptor.
3482 Handle<String> hasWritable_name =
3483 isolate->factory()->InternalizeOneByteString(
3484 STATIC_CHAR_VECTOR("hasWritable_"));
3485 Handle<Object> hasWritable =
3486 Object::GetProperty(desc, hasWritable_name).ToHandleChecked();
3487 DCHECK(hasWritable->IsBoolean());
3488 if (hasWritable->IsTrue()) {
3489 Handle<String> writable_name = isolate->factory()->InternalizeOneByteString(
3490 STATIC_CHAR_VECTOR("writable_"));
3491 Handle<Object> writable =
3492 Object::GetProperty(desc, writable_name).ToHandleChecked();
3493 DCHECK(writable->IsBoolean());
3494 *done = writable->IsFalse();
3495 if (!*done) return isolate->factory()->the_hole_value();
3496 if (strict_mode == SLOPPY) return value;
3497 Handle<Object> args[] = { name, receiver };
3498 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
3499 HandleVector(args, arraysize(args))),
3500 Object);
3501 }
3502
3503 // We have an AccessorDescriptor.
3504 Handle<String> set_name =
3505 isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("set_"));
3506 Handle<Object> setter = Object::GetProperty(desc, set_name).ToHandleChecked();
3507 if (!setter->IsUndefined()) {
3508 // TODO(rossberg): nicer would be to cast to some JSCallable here...
3509 return SetPropertyWithDefinedSetter(
3510 receiver, Handle<JSReceiver>::cast(setter), value);
3511 }
3512
3513 if (strict_mode == SLOPPY) return value;
3514 Handle<Object> args2[] = { name, proxy };
3515 THROW_NEW_ERROR(isolate, NewTypeError("no_setter_in_callback",
3516 HandleVector(args2, arraysize(args2))),
3517 Object);
3518}
3519
3520
3521MaybeHandle<Object> JSProxy::DeletePropertyWithHandler(
3522 Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
3523 Isolate* isolate = proxy->GetIsolate();
3524
3525 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3526 if (name->IsSymbol()) return isolate->factory()->false_value();
3527
3528 Handle<Object> args[] = { name };
3529 Handle<Object> result;
3530 ASSIGN_RETURN_ON_EXCEPTION(
3531 isolate, result,
3532 CallTrap(proxy,
3533 "delete",
3534 Handle<Object>(),
3535 arraysize(args),
3536 args),
3537 Object);
3538
3539 bool result_bool = result->BooleanValue();
3540 if (mode == STRICT_DELETION && !result_bool) {
3541 Handle<Object> handler(proxy->handler(), isolate);
3542 Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
3543 STATIC_CHAR_VECTOR("delete"));
3544 Handle<Object> args[] = { handler, trap_name };
3545 THROW_NEW_ERROR(isolate, NewTypeError("handler_failed",
3546 HandleVector(args, arraysize(args))),
3547 Object);
3548 }
3549 return isolate->factory()->ToBoolean(result_bool);
3550}
3551
3552
3553MaybeHandle<Object> JSProxy::DeleteElementWithHandler(
3554 Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
3555 Isolate* isolate = proxy->GetIsolate();
3556 Handle<String> name = isolate->factory()->Uint32ToString(index);
3557 return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
3558}
3559
3560
3561Maybe<PropertyAttributes> JSProxy::GetPropertyAttributesWithHandler(
3562 Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name) {
3563 Isolate* isolate = proxy->GetIsolate();
3564 HandleScope scope(isolate);
3565
3566 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3567 if (name->IsSymbol()) return maybe(ABSENT);
3568
3569 Handle<Object> args[] = { name };
3570 Handle<Object> result;
3571 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3572 isolate, result,
3573 proxy->CallTrap(proxy, "getPropertyDescriptor", Handle<Object>(),
3574 arraysize(args), args),
3575 Maybe<PropertyAttributes>());
3576
3577 if (result->IsUndefined()) return maybe(ABSENT);
3578
3579 Handle<Object> argv[] = { result };
3580 Handle<Object> desc;
3581 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
3582 isolate, desc,
3583 Execution::Call(isolate, isolate->to_complete_property_descriptor(),
3584 result, arraysize(argv), argv),
3585 Maybe<PropertyAttributes>());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003586
3587 // Convert result to PropertyAttributes.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003588 Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
3589 STATIC_CHAR_VECTOR("enumerable_"));
3590 Handle<Object> enumerable;
3591 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, enumerable,
3592 Object::GetProperty(desc, enum_n),
3593 Maybe<PropertyAttributes>());
3594 Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
3595 STATIC_CHAR_VECTOR("configurable_"));
3596 Handle<Object> configurable;
3597 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, configurable,
3598 Object::GetProperty(desc, conf_n),
3599 Maybe<PropertyAttributes>());
3600 Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
3601 STATIC_CHAR_VECTOR("writable_"));
3602 Handle<Object> writable;
3603 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, writable,
3604 Object::GetProperty(desc, writ_n),
3605 Maybe<PropertyAttributes>());
3606 if (!writable->BooleanValue()) {
3607 Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
3608 STATIC_CHAR_VECTOR("set_"));
3609 Handle<Object> setter;
3610 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, setter,
3611 Object::GetProperty(desc, set_n),
3612 Maybe<PropertyAttributes>());
3613 writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
3614 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003615
3616 if (configurable->IsFalse()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003617 Handle<Object> handler(proxy->handler(), isolate);
3618 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
3619 STATIC_CHAR_VECTOR("getPropertyDescriptor"));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003620 Handle<Object> args[] = { handler, trap, name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003621 Handle<Object> error;
3622 MaybeHandle<Object> maybe_error = isolate->factory()->NewTypeError(
3623 "proxy_prop_not_configurable", HandleVector(args, arraysize(args)));
3624 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
3625 return maybe(NONE);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003626 }
3627
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003628 int attributes = NONE;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003629 if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3630 if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3631 if (!writable->BooleanValue()) attributes |= READ_ONLY;
3632 return maybe(static_cast<PropertyAttributes>(attributes));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003633}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003634
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003635
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003636Maybe<PropertyAttributes> JSProxy::GetElementAttributeWithHandler(
3637 Handle<JSProxy> proxy, Handle<JSReceiver> receiver, uint32_t index) {
3638 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003639 Handle<String> name = isolate->factory()->Uint32ToString(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003640 return GetPropertyAttributesWithHandler(proxy, receiver, name);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003641}
3642
3643
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003644void JSProxy::Fix(Handle<JSProxy> proxy) {
3645 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003646
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003647 // Save identity hash.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003648 Handle<Object> hash(proxy->GetIdentityHash(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003649
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003650 if (proxy->IsJSFunctionProxy()) {
3651 isolate->factory()->BecomeJSFunction(proxy);
Ben Murdoch589d6972011-11-30 16:04:58 +00003652 // Code will be set on the JavaScript side.
3653 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003654 isolate->factory()->BecomeJSObject(proxy);
Ben Murdoch589d6972011-11-30 16:04:58 +00003655 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003656 DCHECK(proxy->IsJSObject());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003657
3658 // Inherit identity, if it was present.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003659 if (hash->IsSmi()) {
3660 JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
3661 Handle<Smi>::cast(hash));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003662 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003663}
3664
3665
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003666MaybeHandle<Object> JSProxy::CallTrap(Handle<JSProxy> proxy,
3667 const char* name,
3668 Handle<Object> derived,
3669 int argc,
3670 Handle<Object> argv[]) {
3671 Isolate* isolate = proxy->GetIsolate();
3672 Handle<Object> handler(proxy->handler(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003673
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003674 Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
3675 Handle<Object> trap;
3676 ASSIGN_RETURN_ON_EXCEPTION(
3677 isolate, trap,
3678 Object::GetPropertyOrElement(handler, trap_name),
3679 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003680
3681 if (trap->IsUndefined()) {
3682 if (derived.is_null()) {
3683 Handle<Object> args[] = { handler, trap_name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003684 THROW_NEW_ERROR(isolate,
3685 NewTypeError("handler_trap_missing",
3686 HandleVector(args, arraysize(args))),
3687 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003688 }
3689 trap = Handle<Object>(derived);
3690 }
3691
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003692 return Execution::Call(isolate, trap, handler, argc, argv);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003693}
3694
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003695
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003696void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
3697 DCHECK(object->map()->inobject_properties() == map->inobject_properties());
3698 ElementsKind obj_kind = object->map()->elements_kind();
3699 ElementsKind map_kind = map->elements_kind();
3700 if (map_kind != obj_kind) {
3701 ElementsKind to_kind = map_kind;
3702 if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
3703 IsDictionaryElementsKind(obj_kind)) {
3704 to_kind = obj_kind;
John Reck59135872010-11-02 12:39:01 -07003705 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003706 if (IsDictionaryElementsKind(to_kind)) {
3707 NormalizeElements(object);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003708 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003709 TransitionElementsKind(object, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003710 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003711 map = Map::AsElementsKind(map, to_kind);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003712 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003713 JSObject::MigrateToMap(object, map);
3714}
3715
3716
3717void JSObject::MigrateInstance(Handle<JSObject> object) {
3718 Handle<Map> original_map(object->map());
3719 Handle<Map> map = Map::Update(original_map);
3720 map->set_migration_target(true);
3721 MigrateToMap(object, map);
3722 if (FLAG_trace_migration) {
3723 object->PrintInstanceMigration(stdout, *original_map, *map);
3724 }
3725}
3726
3727
3728// static
3729bool JSObject::TryMigrateInstance(Handle<JSObject> object) {
3730 Isolate* isolate = object->GetIsolate();
3731 DisallowDeoptimization no_deoptimization(isolate);
3732 Handle<Map> original_map(object->map(), isolate);
3733 Handle<Map> new_map;
3734 if (!Map::TryUpdate(original_map).ToHandle(&new_map)) {
3735 return false;
3736 }
3737 JSObject::MigrateToMap(object, new_map);
3738 if (FLAG_trace_migration) {
3739 object->PrintInstanceMigration(stdout, *original_map, object->map());
3740 }
3741 return true;
3742}
3743
3744
3745void JSObject::MigrateToNewProperty(Handle<JSObject> object,
3746 Handle<Map> map,
3747 Handle<Object> value) {
3748 JSObject::MigrateToMap(object, map);
3749 if (map->GetLastDescriptorDetails().type() != FIELD) return;
3750 object->WriteToField(map->LastAdded(), *value);
3751}
3752
3753
3754void JSObject::WriteToField(int descriptor, Object* value) {
3755 DisallowHeapAllocation no_gc;
3756
3757 DescriptorArray* desc = map()->instance_descriptors();
3758 PropertyDetails details = desc->GetDetails(descriptor);
3759
3760 DCHECK(details.type() == FIELD);
3761
3762 FieldIndex index = FieldIndex::ForDescriptor(map(), descriptor);
3763 if (details.representation().IsDouble()) {
3764 // Nothing more to be done.
3765 if (value->IsUninitialized()) return;
3766 HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
3767 DCHECK(box->IsMutableHeapNumber());
3768 box->set_value(value->Number());
3769 } else {
3770 FastPropertyAtPut(index, value);
3771 }
3772}
3773
3774
3775void JSObject::AddProperty(Handle<JSObject> object, Handle<Name> name,
3776 Handle<Object> value,
3777 PropertyAttributes attributes) {
3778 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
3779 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
3780#ifdef DEBUG
3781 uint32_t index;
3782 DCHECK(!object->IsJSProxy());
3783 DCHECK(!name->AsArrayIndex(&index));
3784 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
3785 DCHECK(maybe.has_value);
3786 DCHECK(!it.IsFound());
3787 DCHECK(object->map()->is_extensible() ||
3788 name.is_identical_to(it.isolate()->factory()->hidden_string()));
3789#endif
3790 AddDataProperty(&it, value, attributes, STRICT,
3791 CERTAINLY_NOT_STORE_FROM_KEYED).Check();
3792}
3793
3794
3795// Reconfigures a property to a data property with attributes, even if it is not
3796// reconfigurable.
3797MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
3798 Handle<JSObject> object,
3799 Handle<Name> name,
3800 Handle<Object> value,
3801 PropertyAttributes attributes,
3802 ExecutableAccessorInfoHandling handling) {
3803 DCHECK(!value->IsTheHole());
3804 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
3805 bool is_observed = object->map()->is_observed() &&
3806 *name != it.isolate()->heap()->hidden_string();
3807 for (; it.IsFound(); it.Next()) {
3808 switch (it.state()) {
3809 case LookupIterator::INTERCEPTOR:
3810 case LookupIterator::JSPROXY:
3811 case LookupIterator::NOT_FOUND:
3812 case LookupIterator::TRANSITION:
3813 UNREACHABLE();
3814
3815 case LookupIterator::ACCESS_CHECK:
3816 if (!it.isolate()->MayNamedAccess(object, name, v8::ACCESS_SET)) {
3817 return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
3818 }
3819 break;
3820
3821 case LookupIterator::ACCESSOR: {
3822 PropertyDetails details = it.property_details();
3823 Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
3824 // Ensure the context isn't changed after calling into accessors.
3825 AssertNoContextChange ncc(it.isolate());
3826
3827 Handle<Object> accessors = it.GetAccessors();
3828
3829 if (is_observed && accessors->IsAccessorInfo()) {
3830 ASSIGN_RETURN_ON_EXCEPTION(
3831 it.isolate(), old_value,
3832 GetPropertyWithAccessor(it.GetReceiver(), it.name(),
3833 it.GetHolder<JSObject>(), accessors),
3834 Object);
3835 }
3836
3837 // Special handling for ExecutableAccessorInfo, which behaves like a
3838 // data property.
3839 if (handling == DONT_FORCE_FIELD &&
3840 accessors->IsExecutableAccessorInfo()) {
3841 Handle<Object> result;
3842 ASSIGN_RETURN_ON_EXCEPTION(
3843 it.isolate(), result,
3844 JSObject::SetPropertyWithAccessor(it.GetReceiver(), it.name(),
3845 value, it.GetHolder<JSObject>(),
3846 accessors, STRICT),
3847 Object);
3848 DCHECK(result->SameValue(*value));
3849
3850 if (details.attributes() == attributes) {
3851 // Regular property update if the attributes match.
3852 if (is_observed && !old_value->SameValue(*value)) {
3853 // If we are setting the prototype of a function and are
3854 // observed, don't send change records because the prototype
3855 // handles that itself.
3856 if (!object->IsJSFunction() ||
3857 !Name::Equals(it.isolate()->factory()->prototype_string(),
3858 name) ||
3859 !Handle<JSFunction>::cast(object)->should_have_prototype()) {
3860 EnqueueChangeRecord(object, "update", name, old_value);
3861 }
3862 }
3863 return value;
3864 }
3865
3866 // Reconfigure the accessor if attributes mismatch.
3867 Handle<ExecutableAccessorInfo> new_data = Accessors::CloneAccessor(
3868 it.isolate(), Handle<ExecutableAccessorInfo>::cast(accessors));
3869 new_data->set_property_attributes(attributes);
3870 // By clearing the setter we don't have to introduce a lookup to
3871 // the setter, simply make it unavailable to reflect the
3872 // attributes.
3873 if (attributes & READ_ONLY) new_data->clear_setter();
3874 SetPropertyCallback(object, name, new_data, attributes);
3875 if (is_observed) {
3876 if (old_value->SameValue(*value)) {
3877 old_value = it.isolate()->factory()->the_hole_value();
3878 }
3879 EnqueueChangeRecord(object, "reconfigure", name, old_value);
3880 }
3881 return value;
3882 }
3883
3884 it.ReconfigureDataProperty(value, attributes);
3885 it.PrepareForDataProperty(value);
3886 it.WriteDataValue(value);
3887
3888 if (is_observed) {
3889 if (old_value->SameValue(*value)) {
3890 old_value = it.isolate()->factory()->the_hole_value();
3891 }
3892 EnqueueChangeRecord(object, "reconfigure", name, old_value);
3893 }
3894
Iain Merrick75681382010-08-19 15:07:18 +01003895 return value;
3896 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003897
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003898 case LookupIterator::DATA: {
3899 PropertyDetails details = it.property_details();
3900 Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
3901 // Regular property update if the attributes match.
3902 if (details.attributes() == attributes) {
3903 return SetDataProperty(&it, value);
3904 }
3905 // Reconfigure the data property if the attributes mismatch.
3906 if (is_observed) old_value = it.GetDataValue();
Steve Blocka7e24c12009-10-30 11:49:00 +00003907
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003908 it.ReconfigureDataProperty(value, attributes);
3909 it.PrepareForDataProperty(value);
3910 it.WriteDataValue(value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003911
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003912 if (is_observed) {
3913 if (old_value->SameValue(*value)) {
3914 old_value = it.isolate()->factory()->the_hole_value();
3915 }
3916 EnqueueChangeRecord(object, "reconfigure", name, old_value);
3917 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01003918
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003919 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00003920 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003921 }
3922 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003923
3924 return AddDataProperty(&it, value, attributes, STRICT,
3925 CERTAINLY_NOT_STORE_FROM_KEYED);
Steve Blocka7e24c12009-10-30 11:49:00 +00003926}
3927
3928
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003929Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
3930 Handle<JSObject> holder,
3931 Handle<Object> receiver,
3932 Handle<Name> name) {
3933 // TODO(rossberg): Support symbols in the API.
3934 if (name->IsSymbol()) return maybe(ABSENT);
3935
3936 Isolate* isolate = holder->GetIsolate();
3937 HandleScope scope(isolate);
Steve Block44f0eee2011-05-26 01:26:41 +01003938
Steve Blocka7e24c12009-10-30 11:49:00 +00003939 // Make sure that the top context does not change when doing
3940 // callbacks or interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003941 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003942
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003943 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
3944 PropertyCallbackArguments args(
3945 isolate, interceptor->data(), *receiver, *holder);
Steve Blocka7e24c12009-10-30 11:49:00 +00003946 if (!interceptor->query()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003947 v8::NamedPropertyQueryCallback query =
3948 v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01003949 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003950 ApiNamedPropertyAccess("interceptor-named-has", *holder, *name));
3951 v8::Handle<v8::Integer> result =
3952 args.Call(query, v8::Utils::ToLocal(Handle<String>::cast(name)));
Steve Blocka7e24c12009-10-30 11:49:00 +00003953 if (!result.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003954 DCHECK(result->IsInt32());
3955 return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
Steve Blocka7e24c12009-10-30 11:49:00 +00003956 }
3957 } else if (!interceptor->getter()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003958 v8::NamedPropertyGetterCallback getter =
3959 v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01003960 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003961 ApiNamedPropertyAccess("interceptor-named-get-has", *holder, *name));
3962 v8::Handle<v8::Value> result =
3963 args.Call(getter, v8::Utils::ToLocal(Handle<String>::cast(name)));
3964 if (!result.IsEmpty()) return maybe(DONT_ENUM);
Steve Blocka7e24c12009-10-30 11:49:00 +00003965 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003966
3967 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
3968 return maybe(ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +00003969}
3970
3971
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003972Maybe<PropertyAttributes> JSReceiver::GetOwnPropertyAttributes(
3973 Handle<JSReceiver> object, Handle<Name> name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003974 // Check whether the name is an array index.
3975 uint32_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003976 if (object->IsJSObject() && name->AsArrayIndex(&index)) {
3977 return GetOwnElementAttribute(object, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003978 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003979 LookupIterator it(object, name, LookupIterator::HIDDEN);
3980 return GetPropertyAttributes(&it);
Steve Blocka7e24c12009-10-30 11:49:00 +00003981}
3982
3983
Ben Murdochb8a8cc12014-11-26 15:28:44 +00003984Maybe<PropertyAttributes> JSReceiver::GetPropertyAttributes(
3985 LookupIterator* it) {
3986 for (; it->IsFound(); it->Next()) {
3987 switch (it->state()) {
3988 case LookupIterator::NOT_FOUND:
3989 case LookupIterator::TRANSITION:
3990 UNREACHABLE();
3991 case LookupIterator::JSPROXY:
3992 return JSProxy::GetPropertyAttributesWithHandler(
3993 it->GetHolder<JSProxy>(), it->GetReceiver(), it->name());
3994 case LookupIterator::INTERCEPTOR: {
3995 Maybe<PropertyAttributes> result =
3996 JSObject::GetPropertyAttributesWithInterceptor(
3997 it->GetHolder<JSObject>(), it->GetReceiver(), it->name());
3998 if (!result.has_value) return result;
3999 if (result.value != ABSENT) return result;
4000 break;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004001 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004002 case LookupIterator::ACCESS_CHECK:
4003 if (it->HasAccess(v8::ACCESS_HAS)) break;
4004 return JSObject::GetPropertyAttributesWithFailedAccessCheck(it);
4005 case LookupIterator::ACCESSOR:
4006 case LookupIterator::DATA:
4007 return maybe(it->property_details().attributes());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004008 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004009 }
4010 return maybe(ABSENT);
4011}
4012
4013
4014Maybe<PropertyAttributes> JSObject::GetElementAttributeWithReceiver(
4015 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4016 bool check_prototype) {
4017 Isolate* isolate = object->GetIsolate();
4018
4019 // Check access rights if needed.
4020 if (object->IsAccessCheckNeeded()) {
4021 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
4022 isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
4023 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<PropertyAttributes>());
4024 return maybe(ABSENT);
4025 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004026 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004027
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004028 if (object->IsJSGlobalProxy()) {
4029 PrototypeIterator iter(isolate, object);
4030 if (iter.IsAtEnd()) return maybe(ABSENT);
4031 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4032 return JSObject::GetElementAttributeWithReceiver(
4033 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4034 index, check_prototype);
John Reck59135872010-11-02 12:39:01 -07004035 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004036
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004037 // Check for lookup interceptor except when bootstrapping.
4038 if (object->HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4039 return JSObject::GetElementAttributeWithInterceptor(
4040 object, receiver, index, check_prototype);
4041 }
4042
4043 return GetElementAttributeWithoutInterceptor(
4044 object, receiver, index, check_prototype);
4045}
4046
4047
4048Maybe<PropertyAttributes> JSObject::GetElementAttributeWithInterceptor(
4049 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4050 bool check_prototype) {
4051 Isolate* isolate = object->GetIsolate();
4052 HandleScope scope(isolate);
4053
4054 // Make sure that the top context does not change when doing
4055 // callbacks or interceptor calls.
4056 AssertNoContextChange ncc(isolate);
4057
4058 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
4059 PropertyCallbackArguments args(
4060 isolate, interceptor->data(), *receiver, *object);
4061 if (!interceptor->query()->IsUndefined()) {
4062 v8::IndexedPropertyQueryCallback query =
4063 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
4064 LOG(isolate,
4065 ApiIndexedPropertyAccess("interceptor-indexed-has", *object, index));
4066 v8::Handle<v8::Integer> result = args.Call(query, index);
4067 if (!result.IsEmpty())
4068 return maybe(static_cast<PropertyAttributes>(result->Int32Value()));
4069 } else if (!interceptor->getter()->IsUndefined()) {
4070 v8::IndexedPropertyGetterCallback getter =
4071 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
4072 LOG(isolate,
4073 ApiIndexedPropertyAccess(
4074 "interceptor-indexed-get-has", *object, index));
4075 v8::Handle<v8::Value> result = args.Call(getter, index);
4076 if (!result.IsEmpty()) return maybe(NONE);
4077 }
4078
4079 return GetElementAttributeWithoutInterceptor(
4080 object, receiver, index, check_prototype);
4081}
4082
4083
4084Maybe<PropertyAttributes> JSObject::GetElementAttributeWithoutInterceptor(
4085 Handle<JSObject> object, Handle<JSReceiver> receiver, uint32_t index,
4086 bool check_prototype) {
4087 PropertyAttributes attr = object->GetElementsAccessor()->GetAttributes(
4088 receiver, object, index);
4089 if (attr != ABSENT) return maybe(attr);
4090
4091 // Handle [] on String objects.
4092 if (object->IsStringObjectWithCharacterAt(index)) {
4093 return maybe(static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE));
4094 }
4095
4096 if (!check_prototype) return maybe(ABSENT);
4097
4098 PrototypeIterator iter(object->GetIsolate(), object);
4099 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
4100 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
4101 return JSProxy::GetElementAttributeWithHandler(
4102 Handle<JSProxy>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4103 index);
4104 }
4105 if (iter.IsAtEnd()) return maybe(ABSENT);
4106 return GetElementAttributeWithReceiver(
4107 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), receiver,
4108 index, true);
4109}
4110
4111
4112Handle<NormalizedMapCache> NormalizedMapCache::New(Isolate* isolate) {
4113 Handle<FixedArray> array(
4114 isolate->factory()->NewFixedArray(kEntries, TENURED));
4115 return Handle<NormalizedMapCache>::cast(array);
4116}
4117
4118
4119MaybeHandle<Map> NormalizedMapCache::Get(Handle<Map> fast_map,
4120 PropertyNormalizationMode mode) {
4121 DisallowHeapAllocation no_gc;
4122 Object* value = FixedArray::get(GetIndex(fast_map));
4123 if (!value->IsMap() ||
4124 !Map::cast(value)->EquivalentToForNormalization(*fast_map, mode)) {
4125 return MaybeHandle<Map>();
4126 }
4127 return handle(Map::cast(value));
4128}
4129
4130
4131void NormalizedMapCache::Set(Handle<Map> fast_map,
4132 Handle<Map> normalized_map) {
4133 DisallowHeapAllocation no_gc;
4134 DCHECK(normalized_map->is_dictionary_map());
4135 FixedArray::set(GetIndex(fast_map), *normalized_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004136}
4137
4138
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004139void NormalizedMapCache::Clear() {
4140 int entries = length();
4141 for (int i = 0; i != entries; i++) {
4142 set_undefined(i);
4143 }
4144}
4145
4146
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004147void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
4148 Handle<Name> name,
4149 Handle<Code> code) {
4150 Handle<Map> map(object->map());
4151 Map::UpdateCodeCache(map, name, code);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004152}
4153
4154
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004155void JSObject::NormalizeProperties(Handle<JSObject> object,
4156 PropertyNormalizationMode mode,
4157 int expected_additional_properties) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004158 if (!object->HasFastProperties()) return;
4159
4160 Handle<Map> map(object->map());
4161 Handle<Map> new_map = Map::Normalize(map, mode);
4162
4163 MigrateFastToSlow(object, new_map, expected_additional_properties);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004164}
4165
4166
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004167void JSObject::MigrateFastToSlow(Handle<JSObject> object,
4168 Handle<Map> new_map,
4169 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004170 // The global object is always normalized.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004171 DCHECK(!object->IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01004172 // JSGlobalProxy must never be normalized
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004173 DCHECK(!object->IsJSGlobalProxy());
Steve Block1e0659c2011-05-24 12:43:12 +01004174
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004175 Isolate* isolate = object->GetIsolate();
4176 HandleScope scope(isolate);
4177 Handle<Map> map(object->map());
Steve Block44f0eee2011-05-26 01:26:41 +01004178
Steve Blocka7e24c12009-10-30 11:49:00 +00004179 // Allocate new content.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004180 int real_size = map->NumberOfOwnDescriptors();
4181 int property_count = real_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00004182 if (expected_additional_properties > 0) {
4183 property_count += expected_additional_properties;
4184 } else {
4185 property_count += 2; // Make space for two more properties.
4186 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004187 Handle<NameDictionary> dictionary =
4188 NameDictionary::New(isolate, property_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004189
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004190 Handle<DescriptorArray> descs(map->instance_descriptors());
4191 for (int i = 0; i < real_size; i++) {
4192 PropertyDetails details = descs->GetDetails(i);
Steve Blocka7e24c12009-10-30 11:49:00 +00004193 switch (details.type()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004194 case CONSTANT: {
4195 Handle<Name> key(descs->GetKey(i));
4196 Handle<Object> value(descs->GetConstant(i), isolate);
4197 PropertyDetails d = PropertyDetails(
4198 details.attributes(), NORMAL, i + 1);
4199 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00004200 break;
4201 }
4202 case FIELD: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004203 Handle<Name> key(descs->GetKey(i));
4204 FieldIndex index = FieldIndex::ForDescriptor(*map, i);
4205 Handle<Object> value(
4206 object->RawFastPropertyAt(index), isolate);
4207 if (details.representation().IsDouble()) {
4208 DCHECK(value->IsMutableHeapNumber());
4209 Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
4210 value = isolate->factory()->NewHeapNumber(old->value());
4211 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004212 PropertyDetails d =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004213 PropertyDetails(details.attributes(), NORMAL, i + 1);
4214 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00004215 break;
4216 }
4217 case CALLBACKS: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004218 Handle<Name> key(descs->GetKey(i));
4219 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
4220 PropertyDetails d = PropertyDetails(
4221 details.attributes(), CALLBACKS, i + 1);
4222 dictionary = NameDictionary::Add(dictionary, key, value, d);
Steve Blocka7e24c12009-10-30 11:49:00 +00004223 break;
4224 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004225 case NORMAL:
Steve Blocka7e24c12009-10-30 11:49:00 +00004226 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004227 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00004228 }
4229 }
4230
4231 // Copy the next enumeration index from instance descriptor.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004232 dictionary->SetNextEnumerationIndex(real_size + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +00004233
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004234 // From here on we cannot fail and we shouldn't GC anymore.
4235 DisallowHeapAllocation no_allocation;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004236
4237 // Resize the object in the heap if necessary.
4238 int new_instance_size = new_map->instance_size();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004239 int instance_size_delta = map->instance_size() - new_instance_size;
4240 DCHECK(instance_size_delta >= 0);
4241
4242 if (instance_size_delta > 0) {
4243 Heap* heap = isolate->heap();
4244 heap->CreateFillerObjectAt(object->address() + new_instance_size,
4245 instance_size_delta);
4246 heap->AdjustLiveBytes(object->address(), -instance_size_delta,
4247 Heap::FROM_MUTATOR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004248 }
4249
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004250 // We are storing the new map using release store after creating a filler for
4251 // the left-over space to avoid races with the sweeper thread.
4252 object->synchronized_set_map(*new_map);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004253
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004254 object->set_properties(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00004255
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004256 isolate->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00004257
4258#ifdef DEBUG
4259 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004260 OFStream os(stdout);
4261 os << "Object properties have been normalized:\n";
4262 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00004263 }
4264#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004265}
4266
4267
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004268void JSObject::MigrateSlowToFast(Handle<JSObject> object,
4269 int unused_property_fields) {
4270 if (object->HasFastProperties()) return;
4271 DCHECK(!object->IsGlobalObject());
4272 Isolate* isolate = object->GetIsolate();
4273 Factory* factory = isolate->factory();
4274 Handle<NameDictionary> dictionary(object->property_dictionary());
4275
4276 // Make sure we preserve dictionary representation if there are too many
4277 // descriptors.
4278 int number_of_elements = dictionary->NumberOfElements();
4279 if (number_of_elements > kMaxNumberOfDescriptors) return;
4280
4281 if (number_of_elements != dictionary->NextEnumerationIndex()) {
4282 NameDictionary::DoGenerateNewEnumerationIndices(dictionary);
4283 }
4284
4285 int instance_descriptor_length = 0;
4286 int number_of_fields = 0;
4287
4288 // Compute the length of the instance descriptor.
4289 int capacity = dictionary->Capacity();
4290 for (int i = 0; i < capacity; i++) {
4291 Object* k = dictionary->KeyAt(i);
4292 if (dictionary->IsKey(k)) {
4293 Object* value = dictionary->ValueAt(i);
4294 PropertyType type = dictionary->DetailsAt(i).type();
4295 DCHECK(type != FIELD);
4296 instance_descriptor_length++;
4297 if (type == NORMAL && !value->IsJSFunction()) {
4298 number_of_fields += 1;
4299 }
4300 }
4301 }
4302
4303 int inobject_props = object->map()->inobject_properties();
4304
4305 // Allocate new map.
4306 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
4307 new_map->set_dictionary_map(false);
4308
4309 if (instance_descriptor_length == 0) {
4310 DisallowHeapAllocation no_gc;
4311 DCHECK_LE(unused_property_fields, inobject_props);
4312 // Transform the object.
4313 new_map->set_unused_property_fields(inobject_props);
4314 object->synchronized_set_map(*new_map);
4315 object->set_properties(isolate->heap()->empty_fixed_array());
4316 // Check that it really works.
4317 DCHECK(object->HasFastProperties());
4318 return;
4319 }
4320
4321 // Allocate the instance descriptor.
4322 Handle<DescriptorArray> descriptors = DescriptorArray::Allocate(
4323 isolate, instance_descriptor_length);
4324
4325 int number_of_allocated_fields =
4326 number_of_fields + unused_property_fields - inobject_props;
4327 if (number_of_allocated_fields < 0) {
4328 // There is enough inobject space for all fields (including unused).
4329 number_of_allocated_fields = 0;
4330 unused_property_fields = inobject_props - number_of_fields;
4331 }
4332
4333 // Allocate the fixed array for the fields.
4334 Handle<FixedArray> fields = factory->NewFixedArray(
4335 number_of_allocated_fields);
4336
4337 // Fill in the instance descriptor and the fields.
4338 int current_offset = 0;
4339 for (int i = 0; i < capacity; i++) {
4340 Object* k = dictionary->KeyAt(i);
4341 if (dictionary->IsKey(k)) {
4342 Object* value = dictionary->ValueAt(i);
4343 Handle<Name> key;
4344 if (k->IsSymbol()) {
4345 key = handle(Symbol::cast(k));
4346 } else {
4347 // Ensure the key is a unique name before writing into the
4348 // instance descriptor.
4349 key = factory->InternalizeString(handle(String::cast(k)));
4350 }
4351
4352 PropertyDetails details = dictionary->DetailsAt(i);
4353 int enumeration_index = details.dictionary_index();
4354 PropertyType type = details.type();
4355
4356 if (value->IsJSFunction()) {
4357 ConstantDescriptor d(key,
4358 handle(value, isolate),
4359 details.attributes());
4360 descriptors->Set(enumeration_index - 1, &d);
4361 } else if (type == NORMAL) {
4362 if (current_offset < inobject_props) {
4363 object->InObjectPropertyAtPut(current_offset,
4364 value,
4365 UPDATE_WRITE_BARRIER);
4366 } else {
4367 int offset = current_offset - inobject_props;
4368 fields->set(offset, value);
4369 }
4370 FieldDescriptor d(key,
4371 current_offset++,
4372 details.attributes(),
4373 // TODO(verwaest): value->OptimalRepresentation();
4374 Representation::Tagged());
4375 descriptors->Set(enumeration_index - 1, &d);
4376 } else if (type == CALLBACKS) {
4377 CallbacksDescriptor d(key,
4378 handle(value, isolate),
4379 details.attributes());
4380 descriptors->Set(enumeration_index - 1, &d);
4381 } else {
4382 UNREACHABLE();
4383 }
4384 }
4385 }
4386 DCHECK(current_offset == number_of_fields);
4387
4388 descriptors->Sort();
4389
4390 DisallowHeapAllocation no_gc;
4391 new_map->InitializeDescriptors(*descriptors);
4392 new_map->set_unused_property_fields(unused_property_fields);
4393
4394 // Transform the object.
4395 object->synchronized_set_map(*new_map);
4396
4397 object->set_properties(*fields);
4398 DCHECK(object->IsJSObject());
4399
4400 // Check that it really works.
4401 DCHECK(object->HasFastProperties());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004402}
4403
4404
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004405void JSObject::ResetElements(Handle<JSObject> object) {
4406 Isolate* isolate = object->GetIsolate();
4407 CHECK(object->map() != isolate->heap()->sloppy_arguments_elements_map());
4408 if (object->map()->has_dictionary_elements()) {
4409 Handle<SeededNumberDictionary> new_elements =
4410 SeededNumberDictionary::New(isolate, 0);
4411 object->set_elements(*new_elements);
4412 } else {
4413 object->set_elements(object->map()->GetInitialElements());
4414 }
4415}
4416
4417
4418static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
4419 Handle<FixedArrayBase> array,
4420 int length,
4421 Handle<SeededNumberDictionary> dictionary) {
4422 Isolate* isolate = array->GetIsolate();
4423 Factory* factory = isolate->factory();
4424 bool has_double_elements = array->IsFixedDoubleArray();
4425 for (int i = 0; i < length; i++) {
4426 Handle<Object> value;
4427 if (has_double_elements) {
4428 Handle<FixedDoubleArray> double_array =
4429 Handle<FixedDoubleArray>::cast(array);
4430 if (double_array->is_the_hole(i)) {
4431 value = factory->the_hole_value();
4432 } else {
4433 value = factory->NewHeapNumber(double_array->get_scalar(i));
4434 }
4435 } else {
4436 value = handle(Handle<FixedArray>::cast(array)->get(i), isolate);
4437 }
4438 if (!value->IsTheHole()) {
4439 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
4440 dictionary =
4441 SeededNumberDictionary::AddNumberEntry(dictionary, i, value, details);
4442 }
4443 }
4444 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00004445}
4446
4447
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004448Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4449 Handle<JSObject> object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004450 DCHECK(!object->HasExternalArrayElements() &&
4451 !object->HasFixedTypedArrayElements());
4452 Isolate* isolate = object->GetIsolate();
Steve Block8defd9f2010-07-08 12:39:36 +01004453
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004454 // Find the backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004455 Handle<FixedArrayBase> array(FixedArrayBase::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004456 bool is_arguments =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004457 (array->map() == isolate->heap()->sloppy_arguments_elements_map());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004458 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004459 array = handle(FixedArrayBase::cast(
4460 Handle<FixedArray>::cast(array)->get(1)));
John Reck59135872010-11-02 12:39:01 -07004461 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004462 if (array->IsDictionary()) return Handle<SeededNumberDictionary>::cast(array);
Steve Blocka7e24c12009-10-30 11:49:00 +00004463
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004464 DCHECK(object->HasFastSmiOrObjectElements() ||
4465 object->HasFastDoubleElements() ||
4466 object->HasFastArgumentsElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004467 // Compute the effective length and allocate a new backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004468 int length = object->IsJSArray()
4469 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004470 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004471 int old_capacity = 0;
4472 int used_elements = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004473 object->GetElementsCapacityAndUsage(&old_capacity, &used_elements);
4474 Handle<SeededNumberDictionary> dictionary =
4475 SeededNumberDictionary::New(isolate, used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004476
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004477 dictionary = CopyFastElementsToDictionary(array, length, dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00004478
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004479 // Switch to using the dictionary as the backing storage for elements.
4480 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004481 FixedArray::cast(object->elements())->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004482 } else {
4483 // Set the new map first to satify the elements type assert in
4484 // set_elements().
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004485 Handle<Map> new_map =
4486 JSObject::GetElementsTransitionMap(object, DICTIONARY_ELEMENTS);
4487
4488 JSObject::MigrateToMap(object, new_map);
4489 object->set_elements(*dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004490 }
4491
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004492 isolate->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00004493
4494#ifdef DEBUG
4495 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004496 OFStream os(stdout);
4497 os << "Object elements have been normalized:\n";
4498 object->Print(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00004499 }
4500#endif
4501
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004502 DCHECK(object->HasDictionaryElements() ||
4503 object->HasDictionaryArgumentsElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004504 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00004505}
4506
4507
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004508static Smi* GenerateIdentityHash(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004509 int hash_value;
4510 int attempts = 0;
4511 do {
4512 // Generate a random 32-bit hash value but limit range to fit
4513 // within a smi.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004514 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004515 attempts++;
4516 } while (hash_value == 0 && attempts < 30);
4517 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
4518
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004519 return Smi::FromInt(hash_value);
4520}
4521
4522
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004523void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
4524 DCHECK(!object->IsJSGlobalProxy());
4525 Isolate* isolate = object->GetIsolate();
4526 SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004527}
4528
4529
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004530template<typename ProxyType>
4531static Handle<Smi> GetOrCreateIdentityHashHelper(Handle<ProxyType> proxy) {
4532 Isolate* isolate = proxy->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004533
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004534 Handle<Object> maybe_hash(proxy->hash(), isolate);
4535 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004536
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004537 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4538 proxy->set_hash(*hash);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004539 return hash;
4540}
4541
4542
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004543Object* JSObject::GetIdentityHash() {
4544 DisallowHeapAllocation no_gc;
4545 Isolate* isolate = GetIsolate();
4546 if (IsJSGlobalProxy()) {
4547 return JSGlobalProxy::cast(this)->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004548 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004549 Object* stored_value =
4550 GetHiddenProperty(isolate->factory()->identity_hash_string());
4551 return stored_value->IsSmi()
4552 ? stored_value
4553 : isolate->heap()->undefined_value();
4554}
4555
4556
4557Handle<Smi> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
4558 if (object->IsJSGlobalProxy()) {
4559 return GetOrCreateIdentityHashHelper(Handle<JSGlobalProxy>::cast(object));
4560 }
4561
4562 Isolate* isolate = object->GetIsolate();
4563
4564 Handle<Object> maybe_hash(object->GetIdentityHash(), isolate);
4565 if (maybe_hash->IsSmi()) return Handle<Smi>::cast(maybe_hash);
4566
4567 Handle<Smi> hash(GenerateIdentityHash(isolate), isolate);
4568 SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004569 return hash;
4570}
4571
4572
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004573Object* JSProxy::GetIdentityHash() {
4574 return this->hash();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004575}
4576
4577
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004578Handle<Smi> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
4579 return GetOrCreateIdentityHashHelper(proxy);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004580}
4581
4582
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004583Object* JSObject::GetHiddenProperty(Handle<Name> key) {
4584 DisallowHeapAllocation no_gc;
4585 DCHECK(key->IsUniqueName());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004586 if (IsJSGlobalProxy()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004587 // JSGlobalProxies store their hash internally.
4588 DCHECK(*key != GetHeap()->identity_hash_string());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004589 // For a proxy, use the prototype as target object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004590 PrototypeIterator iter(GetIsolate(), this);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004591 // If the proxy is detached, return undefined.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004592 if (iter.IsAtEnd()) return GetHeap()->the_hole_value();
4593 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
4594 return JSObject::cast(iter.GetCurrent())->GetHiddenProperty(key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004595 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004596 DCHECK(!IsJSGlobalProxy());
4597 Object* inline_value = GetHiddenPropertiesHashTable();
4598
4599 if (inline_value->IsSmi()) {
4600 // Handle inline-stored identity hash.
4601 if (*key == GetHeap()->identity_hash_string()) {
4602 return inline_value;
4603 } else {
4604 return GetHeap()->the_hole_value();
4605 }
4606 }
4607
4608 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
4609
4610 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4611 Object* entry = hashtable->Lookup(key);
4612 return entry;
4613}
4614
4615
4616Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
4617 Handle<Name> key,
4618 Handle<Object> value) {
4619 Isolate* isolate = object->GetIsolate();
4620
4621 DCHECK(key->IsUniqueName());
4622 if (object->IsJSGlobalProxy()) {
4623 // JSGlobalProxies store their hash internally.
4624 DCHECK(*key != *isolate->factory()->identity_hash_string());
4625 // For a proxy, use the prototype as target object.
4626 PrototypeIterator iter(isolate, object);
4627 // If the proxy is detached, return undefined.
4628 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
4629 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4630 return SetHiddenProperty(
4631 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key,
4632 value);
4633 }
4634 DCHECK(!object->IsJSGlobalProxy());
4635
4636 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
4637
4638 // If there is no backing store yet, store the identity hash inline.
4639 if (value->IsSmi() &&
4640 *key == *isolate->factory()->identity_hash_string() &&
4641 (inline_value->IsUndefined() || inline_value->IsSmi())) {
4642 return JSObject::SetHiddenPropertiesHashTable(object, value);
4643 }
4644
4645 Handle<ObjectHashTable> hashtable =
4646 GetOrCreateHiddenPropertiesHashtable(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004647
4648 // If it was found, check if the key is already in the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004649 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
4650 value);
4651 if (*new_table != *hashtable) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004652 // If adding the key expanded the dictionary (i.e., Add returned a new
4653 // dictionary), store it back to the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004654 SetHiddenPropertiesHashTable(object, new_table);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004655 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004656
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004657 // Return this to mark success.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004658 return object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004659}
4660
4661
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004662void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
4663 Isolate* isolate = object->GetIsolate();
4664 DCHECK(key->IsUniqueName());
4665
4666 if (object->IsJSGlobalProxy()) {
4667 PrototypeIterator iter(isolate, object);
4668 if (iter.IsAtEnd()) return;
4669 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4670 return DeleteHiddenProperty(
4671 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), key);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004672 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004673
4674 Object* inline_value = object->GetHiddenPropertiesHashTable();
4675
4676 // We never delete (inline-stored) identity hashes.
4677 DCHECK(*key != *isolate->factory()->identity_hash_string());
4678 if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
4679
4680 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
4681 bool was_present = false;
4682 ObjectHashTable::Remove(hashtable, key, &was_present);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004683}
4684
4685
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004686bool JSObject::HasHiddenProperties(Handle<JSObject> object) {
4687 Handle<Name> hidden = object->GetIsolate()->factory()->hidden_string();
4688 LookupIterator it(object, hidden, LookupIterator::OWN_SKIP_INTERCEPTOR);
4689 Maybe<PropertyAttributes> maybe = GetPropertyAttributes(&it);
4690 // Cannot get an exception since the hidden_string isn't accessible to JS.
4691 DCHECK(maybe.has_value);
4692 return maybe.value != ABSENT;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004693}
4694
4695
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004696Object* JSObject::GetHiddenPropertiesHashTable() {
4697 DCHECK(!IsJSGlobalProxy());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004698 if (HasFastProperties()) {
4699 // If the object has fast properties, check whether the first slot
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004700 // in the descriptor array matches the hidden string. Since the
4701 // hidden strings hash code is zero (and no other name has hash
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004702 // code zero) it will always occupy the first entry if present.
4703 DescriptorArray* descriptors = this->map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004704 if (descriptors->number_of_descriptors() > 0) {
4705 int sorted_index = descriptors->GetSortedKeyIndex(0);
4706 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
4707 sorted_index < map()->NumberOfOwnDescriptors()) {
4708 DCHECK(descriptors->GetType(sorted_index) == FIELD);
4709 DCHECK(descriptors->GetDetails(sorted_index).representation().
4710 IsCompatibleForLoad(Representation::Tagged()));
4711 FieldIndex index = FieldIndex::ForDescriptor(this->map(),
4712 sorted_index);
4713 return this->RawFastPropertyAt(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004714 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004715 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004716 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004717 } else {
4718 return GetHeap()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004719 }
4720 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004721 Isolate* isolate = GetIsolate();
4722 LookupIterator it(handle(this), isolate->factory()->hidden_string(),
4723 LookupIterator::OWN_SKIP_INTERCEPTOR);
4724 // Access check is always skipped for the hidden string anyways.
4725 return *GetDataProperty(&it);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004726 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004727}
4728
4729Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
4730 Handle<JSObject> object) {
4731 Isolate* isolate = object->GetIsolate();
4732
4733 static const int kInitialCapacity = 4;
4734 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
4735 if (inline_value->IsHashTable()) {
4736 return Handle<ObjectHashTable>::cast(inline_value);
4737 }
4738
4739 Handle<ObjectHashTable> hashtable = ObjectHashTable::New(
4740 isolate, kInitialCapacity, USE_CUSTOM_MINIMUM_CAPACITY);
4741
4742 if (inline_value->IsSmi()) {
4743 // We were storing the identity hash inline and now allocated an actual
4744 // dictionary. Put the identity hash into the new dictionary.
4745 hashtable = ObjectHashTable::Put(hashtable,
4746 isolate->factory()->identity_hash_string(),
4747 inline_value);
4748 }
4749
4750 SetHiddenPropertiesHashTable(object, hashtable);
4751 return hashtable;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004752}
4753
4754
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004755Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
4756 Handle<Object> value) {
4757 DCHECK(!object->IsJSGlobalProxy());
4758 Isolate* isolate = object->GetIsolate();
4759 Handle<Name> name = isolate->factory()->hidden_string();
4760 SetOwnPropertyIgnoreAttributes(object, name, value, DONT_ENUM).Assert();
4761 return object;
4762}
4763
4764
4765MaybeHandle<Object> JSObject::DeletePropertyWithInterceptor(
4766 Handle<JSObject> holder, Handle<JSObject> receiver, Handle<Name> name) {
4767 Isolate* isolate = holder->GetIsolate();
4768
4769 // TODO(rossberg): Support symbols in the API.
4770 if (name->IsSymbol()) return MaybeHandle<Object>();
4771
4772 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
4773 if (interceptor->deleter()->IsUndefined()) return MaybeHandle<Object>();
4774
4775 v8::NamedPropertyDeleterCallback deleter =
4776 v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
4777 LOG(isolate,
4778 ApiNamedPropertyAccess("interceptor-named-delete", *holder, *name));
4779 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver,
4780 *holder);
4781 v8::Handle<v8::Boolean> result =
4782 args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name)));
4783 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4784 if (result.IsEmpty()) return MaybeHandle<Object>();
4785
4786 DCHECK(result->IsBoolean());
4787 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4788 result_internal->VerifyApiCallResultType();
4789 // Rebox CustomArguments::kReturnValueOffset before returning.
4790 return handle(*result_internal, isolate);
4791}
4792
4793
4794MaybeHandle<Object> JSObject::DeleteElementWithInterceptor(
4795 Handle<JSObject> object,
4796 uint32_t index) {
4797 Isolate* isolate = object->GetIsolate();
4798 Factory* factory = isolate->factory();
4799
4800 // Make sure that the top context does not change when doing
4801 // callbacks or interceptor calls.
4802 AssertNoContextChange ncc(isolate);
4803
4804 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
4805 if (interceptor->deleter()->IsUndefined()) return factory->false_value();
4806 v8::IndexedPropertyDeleterCallback deleter =
4807 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
4808 LOG(isolate,
4809 ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
4810 PropertyCallbackArguments args(
4811 isolate, interceptor->data(), *object, *object);
4812 v8::Handle<v8::Boolean> result = args.Call(deleter, index);
4813 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4814 if (!result.IsEmpty()) {
4815 DCHECK(result->IsBoolean());
4816 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4817 result_internal->VerifyApiCallResultType();
4818 // Rebox CustomArguments::kReturnValueOffset before returning.
4819 return handle(*result_internal, isolate);
4820 }
4821 MaybeHandle<Object> delete_result = object->GetElementsAccessor()->Delete(
4822 object, index, NORMAL_DELETION);
4823 return delete_result;
4824}
4825
4826
4827MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
4828 uint32_t index,
4829 DeleteMode mode) {
4830 Isolate* isolate = object->GetIsolate();
4831 Factory* factory = isolate->factory();
4832
4833 // Check access rights if needed.
4834 if (object->IsAccessCheckNeeded() &&
4835 !isolate->MayIndexedAccess(object, index, v8::ACCESS_DELETE)) {
4836 isolate->ReportFailedAccessCheck(object, v8::ACCESS_DELETE);
4837 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
4838 return factory->false_value();
4839 }
4840
4841 if (object->IsStringObjectWithCharacterAt(index)) {
4842 if (mode == STRICT_DELETION) {
4843 // Deleting a non-configurable property in strict mode.
4844 Handle<Object> name = factory->NewNumberFromUint(index);
4845 Handle<Object> args[2] = { name, object };
4846 THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
4847 HandleVector(args, 2)),
4848 Object);
4849 }
4850 return factory->false_value();
4851 }
4852
4853 if (object->IsJSGlobalProxy()) {
4854 PrototypeIterator iter(isolate, object);
4855 if (iter.IsAtEnd()) return factory->false_value();
4856 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
4857 return DeleteElement(
4858 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
4859 mode);
4860 }
4861
4862 Handle<Object> old_value;
4863 bool should_enqueue_change_record = false;
4864 if (object->map()->is_observed()) {
4865 Maybe<bool> maybe = HasOwnElement(object, index);
4866 if (!maybe.has_value) return MaybeHandle<Object>();
4867 should_enqueue_change_record = maybe.value;
4868 if (should_enqueue_change_record) {
4869 if (!GetOwnElementAccessorPair(object, index).is_null()) {
4870 old_value = Handle<Object>::cast(factory->the_hole_value());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004871 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004872 old_value = Object::GetElement(
4873 isolate, object, index).ToHandleChecked();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004874 }
4875 }
4876 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004877
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004878 // Skip interceptor if forcing deletion.
4879 MaybeHandle<Object> maybe_result;
4880 if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
4881 maybe_result = DeleteElementWithInterceptor(object, index);
4882 } else {
4883 maybe_result = object->GetElementsAccessor()->Delete(object, index, mode);
John Reck59135872010-11-02 12:39:01 -07004884 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004885 Handle<Object> result;
4886 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
Steve Blocka7e24c12009-10-30 11:49:00 +00004887
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004888 if (should_enqueue_change_record) {
4889 Maybe<bool> maybe = HasOwnElement(object, index);
4890 if (!maybe.has_value) return MaybeHandle<Object>();
4891 if (!maybe.value) {
4892 Handle<String> name = factory->Uint32ToString(index);
4893 EnqueueChangeRecord(object, "delete", name, old_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00004894 }
4895 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004896
4897 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004898}
4899
4900
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004901MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
4902 Handle<Name> name,
4903 DeleteMode delete_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004904 // ECMA-262, 3rd, 8.6.2.5
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004905 DCHECK(name->IsName());
Steve Blocka7e24c12009-10-30 11:49:00 +00004906
4907 uint32_t index = 0;
4908 if (name->AsArrayIndex(&index)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004909 return DeleteElement(object, index, delete_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004910 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004911
4912 // Skip interceptors on FORCE_DELETION.
4913 LookupIterator::Configuration config =
4914 delete_mode == FORCE_DELETION ? LookupIterator::HIDDEN_SKIP_INTERCEPTOR
4915 : LookupIterator::HIDDEN;
4916
4917 LookupIterator it(object, name, config);
4918
4919 bool is_observed = object->map()->is_observed() &&
4920 *name != it.isolate()->heap()->hidden_string();
4921 Handle<Object> old_value = it.isolate()->factory()->the_hole_value();
4922
4923 for (; it.IsFound(); it.Next()) {
4924 switch (it.state()) {
4925 case LookupIterator::JSPROXY:
4926 case LookupIterator::NOT_FOUND:
4927 case LookupIterator::TRANSITION:
4928 UNREACHABLE();
4929 case LookupIterator::ACCESS_CHECK:
4930 if (it.HasAccess(v8::ACCESS_DELETE)) break;
4931 it.isolate()->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
4932 v8::ACCESS_DELETE);
4933 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it.isolate(), Object);
4934 return it.isolate()->factory()->false_value();
4935 case LookupIterator::INTERCEPTOR: {
4936 MaybeHandle<Object> maybe_result =
4937 JSObject::DeletePropertyWithInterceptor(it.GetHolder<JSObject>(),
4938 object, it.name());
4939 // Delete with interceptor succeeded. Return result.
4940 if (!maybe_result.is_null()) return maybe_result;
4941 // An exception was thrown in the interceptor. Propagate.
4942 if (it.isolate()->has_pending_exception()) return maybe_result;
4943 break;
4944 }
4945 case LookupIterator::DATA:
4946 if (is_observed) {
4947 old_value = it.GetDataValue();
4948 }
4949 // Fall through.
4950 case LookupIterator::ACCESSOR: {
4951 if (delete_mode != FORCE_DELETION && !it.IsConfigurable()) {
4952 // Fail if the property is not configurable.
4953 if (delete_mode == STRICT_DELETION) {
4954 Handle<Object> args[2] = {name, object};
4955 THROW_NEW_ERROR(it.isolate(),
4956 NewTypeError("strict_delete_property",
4957 HandleVector(args, arraysize(args))),
4958 Object);
4959 }
4960 return it.isolate()->factory()->false_value();
4961 }
4962
4963 PropertyNormalizationMode mode = object->map()->is_prototype_map()
4964 ? KEEP_INOBJECT_PROPERTIES
4965 : CLEAR_INOBJECT_PROPERTIES;
4966 Handle<JSObject> holder = it.GetHolder<JSObject>();
4967 // TODO(verwaest): Remove this temporary compatibility hack when blink
4968 // tests are updated.
4969 if (!holder.is_identical_to(object) &&
4970 !(object->IsJSGlobalProxy() && holder->IsJSGlobalObject())) {
4971 return it.isolate()->factory()->true_value();
4972 }
4973 NormalizeProperties(holder, mode, 0);
4974 Handle<Object> result =
4975 DeleteNormalizedProperty(holder, name, delete_mode);
4976 ReoptimizeIfPrototype(holder);
4977
4978 if (is_observed) {
4979 EnqueueChangeRecord(object, "delete", name, old_value);
4980 }
4981
4982 return result;
4983 }
4984 }
4985 }
4986
4987 return it.isolate()->factory()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004988}
4989
4990
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004991MaybeHandle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
4992 uint32_t index,
4993 DeleteMode mode) {
4994 if (object->IsJSProxy()) {
4995 return JSProxy::DeleteElementWithHandler(
4996 Handle<JSProxy>::cast(object), index, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004997 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00004998 return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004999}
5000
5001
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005002MaybeHandle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
5003 Handle<Name> name,
5004 DeleteMode mode) {
5005 if (object->IsJSProxy()) {
5006 return JSProxy::DeletePropertyWithHandler(
5007 Handle<JSProxy>::cast(object), name, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005008 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005009 return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005010}
5011
5012
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005013bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5014 ElementsKind kind,
5015 Object* object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005016 DCHECK(IsFastObjectElementsKind(kind) ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005017 kind == DICTIONARY_ELEMENTS);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005018 if (IsFastObjectElementsKind(kind)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005019 int length = IsJSArray()
5020 ? Smi::cast(JSArray::cast(this)->length())->value()
5021 : elements->length();
5022 for (int i = 0; i < length; ++i) {
5023 Object* element = elements->get(i);
5024 if (!element->IsTheHole() && element == object) return true;
5025 }
5026 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +00005027 Object* key =
5028 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005029 if (!key->IsUndefined()) return true;
5030 }
5031 return false;
5032}
5033
5034
Steve Blocka7e24c12009-10-30 11:49:00 +00005035// Check whether this object references another object.
5036bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01005037 Map* map_of_this = map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005038 Heap* heap = GetHeap();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005039 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +00005040
5041 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01005042 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005043 return true;
5044 }
5045
5046 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01005047 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005048 return true;
5049 }
5050
5051 // Check if the object is among the named properties.
5052 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01005053 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005054 return true;
5055 }
5056
5057 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005058 ElementsKind kind = GetElementsKind();
5059 switch (kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005060 // Raw pixels and external arrays do not reference other
5061 // objects.
5062#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
5063 case EXTERNAL_##TYPE##_ELEMENTS: \
5064 case TYPE##_ELEMENTS: \
Steve Blocka7e24c12009-10-30 11:49:00 +00005065 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005066
5067 TYPED_ARRAYS(TYPED_ARRAY_CASE)
5068#undef TYPED_ARRAY_CASE
5069
5070 case FAST_DOUBLE_ELEMENTS:
5071 case FAST_HOLEY_DOUBLE_ELEMENTS:
5072 break;
5073 case FAST_SMI_ELEMENTS:
5074 case FAST_HOLEY_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005075 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005076 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005077 case FAST_HOLEY_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00005078 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005079 FixedArray* elements = FixedArray::cast(this->elements());
5080 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00005081 break;
5082 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005083 case SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005084 FixedArray* parameter_map = FixedArray::cast(elements());
5085 // Check the mapped parameters.
5086 int length = parameter_map->length();
5087 for (int i = 2; i < length; ++i) {
5088 Object* value = parameter_map->get(i);
5089 if (!value->IsTheHole() && value == obj) return true;
5090 }
5091 // Check the arguments.
5092 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005093 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5094 FAST_HOLEY_ELEMENTS;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005095 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00005096 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005097 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005098 }
5099
Steve Block6ded16b2010-05-10 14:33:55 +01005100 // For functions check the context.
5101 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005102 // Get the constructor function for arguments array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005103 Map* arguments_map =
5104 heap->isolate()->context()->native_context()->sloppy_arguments_map();
Steve Blocka7e24c12009-10-30 11:49:00 +00005105 JSFunction* arguments_function =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005106 JSFunction::cast(arguments_map->constructor());
Steve Blocka7e24c12009-10-30 11:49:00 +00005107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005108 // Get the context and don't check if it is the native context.
Steve Blocka7e24c12009-10-30 11:49:00 +00005109 JSFunction* f = JSFunction::cast(this);
5110 Context* context = f->context();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005111 if (context->IsNativeContext()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005112 return false;
5113 }
5114
5115 // Check the non-special context slots.
5116 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5117 // Only check JS objects.
5118 if (context->get(i)->IsJSObject()) {
5119 JSObject* ctxobj = JSObject::cast(context->get(i));
5120 // If it is an arguments array check the content.
5121 if (ctxobj->map()->constructor() == arguments_function) {
5122 if (ctxobj->ReferencesObject(obj)) {
5123 return true;
5124 }
5125 } else if (ctxobj == obj) {
5126 return true;
5127 }
5128 }
5129 }
5130
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005131 // Check the context extension (if any) if it can have references.
5132 if (context->has_extension() && !context->IsCatchContext()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005133 // With harmony scoping, a JSFunction may have a global context.
5134 // TODO(mvstanton): walk into the ScopeInfo.
5135 if (FLAG_harmony_scoping && context->IsGlobalContext()) {
5136 return false;
5137 }
5138
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005139 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00005140 }
5141 }
5142
5143 // No references to object.
5144 return false;
5145}
5146
5147
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005148MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
5149 Isolate* isolate = object->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005150
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005151 if (!object->map()->is_extensible()) return object;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005152
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005153 if (object->IsAccessCheckNeeded() &&
5154 !isolate->MayNamedAccess(
5155 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5156 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5157 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5158 return isolate->factory()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005159 }
5160
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005161 if (object->IsJSGlobalProxy()) {
5162 PrototypeIterator iter(isolate, object);
5163 if (iter.IsAtEnd()) return object;
5164 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
5165 return PreventExtensions(
5166 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
Steve Block1e0659c2011-05-24 12:43:12 +01005167 }
5168
Ben Murdoch257744e2011-11-30 15:57:28 +00005169 // It's not possible to seal objects with external array elements
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005170 if (object->HasExternalArrayElements() ||
5171 object->HasFixedTypedArrayElements()) {
5172 THROW_NEW_ERROR(isolate,
5173 NewTypeError("cant_prevent_ext_external_array_elements",
5174 HandleVector(&object, 1)),
5175 Object);
Ben Murdoch257744e2011-11-30 15:57:28 +00005176 }
5177
Steve Block8defd9f2010-07-08 12:39:36 +01005178 // If there are fast elements we normalize.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005179 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
5180 DCHECK(object->HasDictionaryElements() ||
5181 object->HasDictionaryArgumentsElements());
5182
Steve Block8defd9f2010-07-08 12:39:36 +01005183 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005184 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01005185
5186 // Do a map transition, other objects with this map may still
5187 // be extensible.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005188 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
5189 Handle<Map> new_map = Map::Copy(handle(object->map()));
5190
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005191 new_map->set_is_extensible(false);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005192 JSObject::MigrateToMap(object, new_map);
5193 DCHECK(!object->map()->is_extensible());
5194
5195 if (object->map()->is_observed()) {
5196 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
5197 isolate->factory()->the_hole_value());
5198 }
5199 return object;
5200}
5201
5202
5203template<typename Dictionary>
5204static void FreezeDictionary(Dictionary* dictionary) {
5205 int capacity = dictionary->Capacity();
5206 for (int i = 0; i < capacity; i++) {
5207 Object* k = dictionary->KeyAt(i);
5208 if (dictionary->IsKey(k) &&
5209 !(k->IsSymbol() && Symbol::cast(k)->is_private())) {
5210 PropertyDetails details = dictionary->DetailsAt(i);
5211 int attrs = DONT_DELETE;
5212 // READ_ONLY is an invalid attribute for JS setters/getters.
5213 if (details.type() == CALLBACKS) {
5214 Object* v = dictionary->ValueAt(i);
5215 if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
5216 if (!v->IsAccessorPair()) attrs |= READ_ONLY;
5217 } else {
5218 attrs |= READ_ONLY;
5219 }
5220 details = details.CopyAddAttributes(
5221 static_cast<PropertyAttributes>(attrs));
5222 dictionary->DetailsAtPut(i, details);
5223 }
5224 }
5225}
5226
5227
5228MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
5229 // Freezing sloppy arguments should be handled elsewhere.
5230 DCHECK(!object->HasSloppyArgumentsElements());
5231 DCHECK(!object->map()->is_observed());
5232
5233 if (object->map()->is_frozen()) return object;
5234
5235 Isolate* isolate = object->GetIsolate();
5236 if (object->IsAccessCheckNeeded() &&
5237 !isolate->MayNamedAccess(
5238 object, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5239 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
5240 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
5241 return isolate->factory()->false_value();
5242 }
5243
5244 if (object->IsJSGlobalProxy()) {
5245 PrototypeIterator iter(isolate, object);
5246 if (iter.IsAtEnd()) return object;
5247 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
5248 return Freeze(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)));
5249 }
5250
5251 // It's not possible to freeze objects with external array elements
5252 if (object->HasExternalArrayElements() ||
5253 object->HasFixedTypedArrayElements()) {
5254 THROW_NEW_ERROR(isolate,
5255 NewTypeError("cant_prevent_ext_external_array_elements",
5256 HandleVector(&object, 1)),
5257 Object);
5258 }
5259
5260 Handle<SeededNumberDictionary> new_element_dictionary;
5261 if (!object->elements()->IsDictionary()) {
5262 int length = object->IsJSArray()
5263 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5264 : object->elements()->length();
5265 if (length > 0) {
5266 int capacity = 0;
5267 int used = 0;
5268 object->GetElementsCapacityAndUsage(&capacity, &used);
5269 new_element_dictionary = SeededNumberDictionary::New(isolate, used);
5270
5271 // Move elements to a dictionary; avoid calling NormalizeElements to avoid
5272 // unnecessary transitions.
5273 new_element_dictionary = CopyFastElementsToDictionary(
5274 handle(object->elements()), length, new_element_dictionary);
5275 } else {
5276 // No existing elements, use a pre-allocated empty backing store
5277 new_element_dictionary =
5278 isolate->factory()->empty_slow_element_dictionary();
5279 }
5280 }
5281
5282 Handle<Map> old_map(object->map(), isolate);
5283 int transition_index = old_map->SearchTransition(
5284 isolate->heap()->frozen_symbol());
5285 if (transition_index != TransitionArray::kNotFound) {
5286 Handle<Map> transition_map(old_map->GetTransition(transition_index));
5287 DCHECK(transition_map->has_dictionary_elements());
5288 DCHECK(transition_map->is_frozen());
5289 DCHECK(!transition_map->is_extensible());
5290 JSObject::MigrateToMap(object, transition_map);
5291 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5292 // Create a new descriptor array with fully-frozen properties
5293 Handle<Map> new_map = Map::CopyForFreeze(old_map);
5294 JSObject::MigrateToMap(object, new_map);
5295 } else {
5296 DCHECK(old_map->is_dictionary_map() || !old_map->is_prototype_map());
5297 // Slow path: need to normalize properties for safety
5298 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
5299
5300 // Create a new map, since other objects with this map may be extensible.
5301 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
5302 Handle<Map> new_map = Map::Copy(handle(object->map()));
5303 new_map->freeze();
5304 new_map->set_is_extensible(false);
5305 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
5306 JSObject::MigrateToMap(object, new_map);
5307
5308 // Freeze dictionary-mode properties
5309 FreezeDictionary(object->property_dictionary());
5310 }
5311
5312 DCHECK(object->map()->has_dictionary_elements());
5313 if (!new_element_dictionary.is_null()) {
5314 object->set_elements(*new_element_dictionary);
5315 }
5316
5317 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
5318 SeededNumberDictionary* dictionary = object->element_dictionary();
5319 // Make sure we never go back to the fast case
5320 dictionary->set_requires_slow_elements();
5321 // Freeze all elements in the dictionary
5322 FreezeDictionary(dictionary);
5323 }
5324
5325 return object;
5326}
5327
5328
5329void JSObject::SetObserved(Handle<JSObject> object) {
5330 DCHECK(!object->IsJSGlobalProxy());
5331 DCHECK(!object->IsJSGlobalObject());
5332 Isolate* isolate = object->GetIsolate();
5333 Handle<Map> new_map;
5334 Handle<Map> old_map(object->map(), isolate);
5335 DCHECK(!old_map->is_observed());
5336 int transition_index = old_map->SearchTransition(
5337 isolate->heap()->observed_symbol());
5338 if (transition_index != TransitionArray::kNotFound) {
5339 new_map = handle(old_map->GetTransition(transition_index), isolate);
5340 DCHECK(new_map->is_observed());
5341 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
5342 new_map = Map::CopyForObserved(old_map);
5343 } else {
5344 new_map = Map::Copy(old_map);
5345 new_map->set_is_observed();
5346 }
5347 JSObject::MigrateToMap(object, new_map);
5348}
5349
5350
5351Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object,
5352 Representation representation,
5353 FieldIndex index) {
5354 Isolate* isolate = object->GetIsolate();
5355 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
5356 return Object::WrapForRead(isolate, raw_value, representation);
5357}
5358
5359
5360template<class ContextObject>
5361class JSObjectWalkVisitor {
5362 public:
5363 JSObjectWalkVisitor(ContextObject* site_context, bool copying,
5364 JSObject::DeepCopyHints hints)
5365 : site_context_(site_context),
5366 copying_(copying),
5367 hints_(hints) {}
5368
5369 MUST_USE_RESULT MaybeHandle<JSObject> StructureWalk(Handle<JSObject> object);
5370
5371 protected:
5372 MUST_USE_RESULT inline MaybeHandle<JSObject> VisitElementOrProperty(
5373 Handle<JSObject> object,
5374 Handle<JSObject> value) {
5375 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5376 MaybeHandle<JSObject> copy_of_value = StructureWalk(value);
5377 site_context()->ExitScope(current_site, value);
5378 return copy_of_value;
5379 }
5380
5381 inline ContextObject* site_context() { return site_context_; }
5382 inline Isolate* isolate() { return site_context()->isolate(); }
5383
5384 inline bool copying() const { return copying_; }
5385
5386 private:
5387 ContextObject* site_context_;
5388 const bool copying_;
5389 const JSObject::DeepCopyHints hints_;
5390};
5391
5392
5393template <class ContextObject>
5394MaybeHandle<JSObject> JSObjectWalkVisitor<ContextObject>::StructureWalk(
5395 Handle<JSObject> object) {
5396 Isolate* isolate = this->isolate();
5397 bool copying = this->copying();
5398 bool shallow = hints_ == JSObject::kObjectIsShallow;
5399
5400 if (!shallow) {
5401 StackLimitCheck check(isolate);
5402
5403 if (check.HasOverflowed()) {
5404 isolate->StackOverflow();
5405 return MaybeHandle<JSObject>();
5406 }
5407 }
5408
5409 if (object->map()->is_deprecated()) {
5410 JSObject::MigrateInstance(object);
5411 }
5412
5413 Handle<JSObject> copy;
5414 if (copying) {
5415 Handle<AllocationSite> site_to_pass;
5416 if (site_context()->ShouldCreateMemento(object)) {
5417 site_to_pass = site_context()->current();
5418 }
5419 copy = isolate->factory()->CopyJSObjectWithAllocationSite(
5420 object, site_to_pass);
5421 } else {
5422 copy = object;
5423 }
5424
5425 DCHECK(copying || copy.is_identical_to(object));
5426
5427 ElementsKind kind = copy->GetElementsKind();
5428 if (copying && IsFastSmiOrObjectElementsKind(kind) &&
5429 FixedArray::cast(copy->elements())->map() ==
5430 isolate->heap()->fixed_cow_array_map()) {
5431 isolate->counters()->cow_arrays_created_runtime()->Increment();
5432 }
5433
5434 if (!shallow) {
5435 HandleScope scope(isolate);
5436
5437 // Deep copy own properties.
5438 if (copy->HasFastProperties()) {
5439 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
5440 int limit = copy->map()->NumberOfOwnDescriptors();
5441 for (int i = 0; i < limit; i++) {
5442 PropertyDetails details = descriptors->GetDetails(i);
5443 if (details.type() != FIELD) continue;
5444 FieldIndex index = FieldIndex::ForDescriptor(copy->map(), i);
5445 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
5446 if (value->IsJSObject()) {
5447 ASSIGN_RETURN_ON_EXCEPTION(
5448 isolate, value,
5449 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5450 JSObject);
5451 } else {
5452 Representation representation = details.representation();
5453 value = Object::NewStorageFor(isolate, value, representation);
5454 }
5455 if (copying) {
5456 copy->FastPropertyAtPut(index, *value);
5457 }
5458 }
5459 } else {
5460 Handle<FixedArray> names =
5461 isolate->factory()->NewFixedArray(copy->NumberOfOwnProperties());
5462 copy->GetOwnPropertyNames(*names, 0);
5463 for (int i = 0; i < names->length(); i++) {
5464 DCHECK(names->get(i)->IsString());
5465 Handle<String> key_string(String::cast(names->get(i)));
5466 Maybe<PropertyAttributes> maybe =
5467 JSReceiver::GetOwnPropertyAttributes(copy, key_string);
5468 DCHECK(maybe.has_value);
5469 PropertyAttributes attributes = maybe.value;
5470 // Only deep copy fields from the object literal expression.
5471 // In particular, don't try to copy the length attribute of
5472 // an array.
5473 if (attributes != NONE) continue;
5474 Handle<Object> value =
5475 Object::GetProperty(copy, key_string).ToHandleChecked();
5476 if (value->IsJSObject()) {
5477 Handle<JSObject> result;
5478 ASSIGN_RETURN_ON_EXCEPTION(
5479 isolate, result,
5480 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5481 JSObject);
5482 if (copying) {
5483 // Creating object copy for literals. No strict mode needed.
5484 JSObject::SetProperty(copy, key_string, result, SLOPPY).Assert();
5485 }
5486 }
5487 }
5488 }
5489
5490 // Deep copy own elements.
5491 // Pixel elements cannot be created using an object literal.
5492 DCHECK(!copy->HasExternalArrayElements());
5493 switch (kind) {
5494 case FAST_SMI_ELEMENTS:
5495 case FAST_ELEMENTS:
5496 case FAST_HOLEY_SMI_ELEMENTS:
5497 case FAST_HOLEY_ELEMENTS: {
5498 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
5499 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
5500#ifdef DEBUG
5501 for (int i = 0; i < elements->length(); i++) {
5502 DCHECK(!elements->get(i)->IsJSObject());
5503 }
5504#endif
5505 } else {
5506 for (int i = 0; i < elements->length(); i++) {
5507 Handle<Object> value(elements->get(i), isolate);
5508 DCHECK(value->IsSmi() ||
5509 value->IsTheHole() ||
5510 (IsFastObjectElementsKind(copy->GetElementsKind())));
5511 if (value->IsJSObject()) {
5512 Handle<JSObject> result;
5513 ASSIGN_RETURN_ON_EXCEPTION(
5514 isolate, result,
5515 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5516 JSObject);
5517 if (copying) {
5518 elements->set(i, *result);
5519 }
5520 }
5521 }
5522 }
5523 break;
5524 }
5525 case DICTIONARY_ELEMENTS: {
5526 Handle<SeededNumberDictionary> element_dictionary(
5527 copy->element_dictionary());
5528 int capacity = element_dictionary->Capacity();
5529 for (int i = 0; i < capacity; i++) {
5530 Object* k = element_dictionary->KeyAt(i);
5531 if (element_dictionary->IsKey(k)) {
5532 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
5533 if (value->IsJSObject()) {
5534 Handle<JSObject> result;
5535 ASSIGN_RETURN_ON_EXCEPTION(
5536 isolate, result,
5537 VisitElementOrProperty(copy, Handle<JSObject>::cast(value)),
5538 JSObject);
5539 if (copying) {
5540 element_dictionary->ValueAtPut(i, *result);
5541 }
5542 }
5543 }
5544 }
5545 break;
5546 }
5547 case SLOPPY_ARGUMENTS_ELEMENTS:
5548 UNIMPLEMENTED();
5549 break;
5550
5551
5552#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
5553 case EXTERNAL_##TYPE##_ELEMENTS: \
5554 case TYPE##_ELEMENTS: \
5555
5556 TYPED_ARRAYS(TYPED_ARRAY_CASE)
5557#undef TYPED_ARRAY_CASE
5558
5559 case FAST_DOUBLE_ELEMENTS:
5560 case FAST_HOLEY_DOUBLE_ELEMENTS:
5561 // No contained objects, nothing to do.
5562 break;
5563 }
5564 }
5565
5566 return copy;
5567}
5568
5569
5570MaybeHandle<JSObject> JSObject::DeepWalk(
5571 Handle<JSObject> object,
5572 AllocationSiteCreationContext* site_context) {
5573 JSObjectWalkVisitor<AllocationSiteCreationContext> v(site_context, false,
5574 kNoHints);
5575 MaybeHandle<JSObject> result = v.StructureWalk(object);
5576 Handle<JSObject> for_assert;
5577 DCHECK(!result.ToHandle(&for_assert) || for_assert.is_identical_to(object));
5578 return result;
5579}
5580
5581
5582MaybeHandle<JSObject> JSObject::DeepCopy(
5583 Handle<JSObject> object,
5584 AllocationSiteUsageContext* site_context,
5585 DeepCopyHints hints) {
5586 JSObjectWalkVisitor<AllocationSiteUsageContext> v(site_context, true, hints);
5587 MaybeHandle<JSObject> copy = v.StructureWalk(object);
5588 Handle<JSObject> for_assert;
5589 DCHECK(!copy.ToHandle(&for_assert) || !for_assert.is_identical_to(object));
5590 return copy;
Steve Block8defd9f2010-07-08 12:39:36 +01005591}
5592
5593
Steve Blocka7e24c12009-10-30 11:49:00 +00005594// Tests for the fast common case for property enumeration:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005595// - This object and all prototypes has an enum cache (which means that
5596// it is no proxy, has no interceptors and needs no access checks).
Steve Blockd0582a62009-12-15 09:54:21 +00005597// - This object has no elements.
5598// - No prototype has enumerable properties/elements.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005599bool JSReceiver::IsSimpleEnum() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005600 for (PrototypeIterator iter(GetIsolate(), this,
5601 PrototypeIterator::START_AT_RECEIVER);
5602 !iter.IsAtEnd(); iter.Advance()) {
5603 if (!iter.GetCurrent()->IsJSObject()) return false;
5604 JSObject* curr = JSObject::cast(iter.GetCurrent());
5605 int enum_length = curr->map()->EnumLength();
5606 if (enum_length == kInvalidEnumCacheSentinel) return false;
5607 if (curr->IsAccessCheckNeeded()) return false;
5608 DCHECK(!curr->HasNamedInterceptor());
5609 DCHECK(!curr->HasIndexedInterceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +00005610 if (curr->NumberOfEnumElements() > 0) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005611 if (curr != this && enum_length != 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005612 }
5613 return true;
5614}
5615
5616
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005617static bool FilterKey(Object* key, PropertyAttributes filter) {
5618 if ((filter & SYMBOLIC) && key->IsSymbol()) {
5619 return true;
5620 }
5621
5622 if ((filter & PRIVATE_SYMBOL) &&
5623 key->IsSymbol() && Symbol::cast(key)->is_private()) {
5624 return true;
5625 }
5626
5627 if ((filter & STRING) && !key->IsSymbol()) {
5628 return true;
5629 }
5630
5631 return false;
5632}
5633
5634
5635int Map::NumberOfDescribedProperties(DescriptorFlag which,
5636 PropertyAttributes filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005637 int result = 0;
5638 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005639 int limit = which == ALL_DESCRIPTORS
5640 ? descs->number_of_descriptors()
5641 : NumberOfOwnDescriptors();
5642 for (int i = 0; i < limit; i++) {
5643 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
5644 !FilterKey(descs->GetKey(i), filter)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005645 result++;
5646 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005647 }
5648 return result;
5649}
5650
5651
Steve Blocka7e24c12009-10-30 11:49:00 +00005652int Map::NextFreePropertyIndex() {
5653 int max_index = -1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005654 int number_of_own_descriptors = NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00005655 DescriptorArray* descs = instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005656 for (int i = 0; i < number_of_own_descriptors; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005657 if (descs->GetType(i) == FIELD) {
5658 int current_index = descs->GetFieldIndex(i);
5659 if (current_index > max_index) max_index = current_index;
5660 }
5661 }
5662 return max_index + 1;
5663}
5664
5665
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005666static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
5667 int len = array->length();
5668 for (int i = 0; i < len; i++) {
5669 Object* e = array->get(i);
5670 if (!(e->IsString() || e->IsNumber())) return false;
5671 }
5672 return true;
5673}
5674
5675
5676static Handle<FixedArray> ReduceFixedArrayTo(
5677 Handle<FixedArray> array, int length) {
5678 DCHECK(array->length() >= length);
5679 if (array->length() == length) return array;
5680
5681 Handle<FixedArray> new_array =
5682 array->GetIsolate()->factory()->NewFixedArray(length);
5683 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i));
5684 return new_array;
5685}
5686
5687
5688static Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object,
5689 bool cache_result) {
5690 Isolate* isolate = object->GetIsolate();
5691 if (object->HasFastProperties()) {
5692 int own_property_count = object->map()->EnumLength();
5693 // If the enum length of the given map is set to kInvalidEnumCache, this
5694 // means that the map itself has never used the present enum cache. The
5695 // first step to using the cache is to set the enum length of the map by
5696 // counting the number of own descriptors that are not DONT_ENUM or
5697 // SYMBOLIC.
5698 if (own_property_count == kInvalidEnumCacheSentinel) {
5699 own_property_count = object->map()->NumberOfDescribedProperties(
5700 OWN_DESCRIPTORS, DONT_SHOW);
5701 } else {
5702 DCHECK(own_property_count == object->map()->NumberOfDescribedProperties(
5703 OWN_DESCRIPTORS, DONT_SHOW));
Steve Blocka7e24c12009-10-30 11:49:00 +00005704 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005705
5706 if (object->map()->instance_descriptors()->HasEnumCache()) {
5707 DescriptorArray* desc = object->map()->instance_descriptors();
5708 Handle<FixedArray> keys(desc->GetEnumCache(), isolate);
5709
5710 // In case the number of properties required in the enum are actually
5711 // present, we can reuse the enum cache. Otherwise, this means that the
5712 // enum cache was generated for a previous (smaller) version of the
5713 // Descriptor Array. In that case we regenerate the enum cache.
5714 if (own_property_count <= keys->length()) {
5715 if (cache_result) object->map()->SetEnumLength(own_property_count);
5716 isolate->counters()->enum_cache_hits()->Increment();
5717 return ReduceFixedArrayTo(keys, own_property_count);
5718 }
5719 }
5720
5721 Handle<Map> map(object->map());
5722
5723 if (map->instance_descriptors()->IsEmpty()) {
5724 isolate->counters()->enum_cache_hits()->Increment();
5725 if (cache_result) map->SetEnumLength(0);
5726 return isolate->factory()->empty_fixed_array();
5727 }
5728
5729 isolate->counters()->enum_cache_misses()->Increment();
5730
5731 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(
5732 own_property_count);
5733 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(
5734 own_property_count);
5735
5736 Handle<DescriptorArray> descs =
5737 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate);
5738
5739 int size = map->NumberOfOwnDescriptors();
5740 int index = 0;
5741
5742 for (int i = 0; i < size; i++) {
5743 PropertyDetails details = descs->GetDetails(i);
5744 Object* key = descs->GetKey(i);
5745 if (!(details.IsDontEnum() || key->IsSymbol())) {
5746 storage->set(index, key);
5747 if (!indices.is_null()) {
5748 if (details.type() != FIELD) {
5749 indices = Handle<FixedArray>();
5750 } else {
5751 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
5752 int load_by_field_index = field_index.GetLoadByFieldIndex();
5753 indices->set(index, Smi::FromInt(load_by_field_index));
5754 }
5755 }
5756 index++;
5757 }
5758 }
5759 DCHECK(index == storage->length());
5760
5761 Handle<FixedArray> bridge_storage =
5762 isolate->factory()->NewFixedArray(
5763 DescriptorArray::kEnumCacheBridgeLength);
5764 DescriptorArray* desc = object->map()->instance_descriptors();
5765 desc->SetEnumCache(*bridge_storage,
5766 *storage,
5767 indices.is_null() ? Object::cast(Smi::FromInt(0))
5768 : Object::cast(*indices));
5769 if (cache_result) {
5770 object->map()->SetEnumLength(own_property_count);
5771 }
5772 return storage;
5773 } else {
5774 Handle<NameDictionary> dictionary(object->property_dictionary());
5775 int length = dictionary->NumberOfEnumElements();
5776 if (length == 0) {
5777 return Handle<FixedArray>(isolate->heap()->empty_fixed_array());
5778 }
5779 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
5780 dictionary->CopyEnumKeysTo(*storage);
5781 return storage;
Steve Blocka7e24c12009-10-30 11:49:00 +00005782 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005783}
5784
5785
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005786MaybeHandle<FixedArray> JSReceiver::GetKeys(Handle<JSReceiver> object,
5787 KeyCollectionType type) {
5788 USE(ContainsOnlyValidKeys);
5789 Isolate* isolate = object->GetIsolate();
5790 Handle<FixedArray> content = isolate->factory()->empty_fixed_array();
5791 Handle<JSFunction> arguments_function(
5792 JSFunction::cast(isolate->sloppy_arguments_map()->constructor()));
Steve Blocka7e24c12009-10-30 11:49:00 +00005793
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005794 // Only collect keys if access is permitted.
5795 for (PrototypeIterator iter(isolate, object,
5796 PrototypeIterator::START_AT_RECEIVER);
5797 !iter.IsAtEnd(); iter.Advance()) {
5798 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
5799 Handle<JSProxy> proxy(JSProxy::cast(*PrototypeIterator::GetCurrent(iter)),
5800 isolate);
5801 Handle<Object> args[] = { proxy };
5802 Handle<Object> names;
5803 ASSIGN_RETURN_ON_EXCEPTION(
5804 isolate, names,
5805 Execution::Call(isolate,
5806 isolate->proxy_enumerate(),
5807 object,
5808 arraysize(args),
5809 args),
5810 FixedArray);
5811 ASSIGN_RETURN_ON_EXCEPTION(
5812 isolate, content,
5813 FixedArray::AddKeysFromArrayLike(
5814 content, Handle<JSObject>::cast(names)),
5815 FixedArray);
5816 break;
5817 }
Steve Block44f0eee2011-05-26 01:26:41 +01005818
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005819 Handle<JSObject> current =
5820 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
5821
5822 // Check access rights if required.
5823 if (current->IsAccessCheckNeeded() &&
5824 !isolate->MayNamedAccess(
5825 current, isolate->factory()->undefined_value(), v8::ACCESS_KEYS)) {
5826 isolate->ReportFailedAccessCheck(current, v8::ACCESS_KEYS);
5827 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, FixedArray);
5828 break;
5829 }
5830
5831 // Compute the element keys.
5832 Handle<FixedArray> element_keys =
5833 isolate->factory()->NewFixedArray(current->NumberOfEnumElements());
5834 current->GetEnumElementKeys(*element_keys);
5835 ASSIGN_RETURN_ON_EXCEPTION(
5836 isolate, content,
5837 FixedArray::UnionOfKeys(content, element_keys),
5838 FixedArray);
5839 DCHECK(ContainsOnlyValidKeys(content));
5840
5841 // Add the element keys from the interceptor.
5842 if (current->HasIndexedInterceptor()) {
5843 Handle<JSObject> result;
5844 if (JSObject::GetKeysForIndexedInterceptor(
5845 current, object).ToHandle(&result)) {
5846 ASSIGN_RETURN_ON_EXCEPTION(
5847 isolate, content,
5848 FixedArray::AddKeysFromArrayLike(content, result),
5849 FixedArray);
5850 }
5851 DCHECK(ContainsOnlyValidKeys(content));
5852 }
5853
5854 // We can cache the computed property keys if access checks are
5855 // not needed and no interceptors are involved.
5856 //
5857 // We do not use the cache if the object has elements and
5858 // therefore it does not make sense to cache the property names
5859 // for arguments objects. Arguments objects will always have
5860 // elements.
5861 // Wrapped strings have elements, but don't have an elements
5862 // array or dictionary. So the fast inline test for whether to
5863 // use the cache says yes, so we should not create a cache.
5864 bool cache_enum_keys =
5865 ((current->map()->constructor() != *arguments_function) &&
5866 !current->IsJSValue() &&
5867 !current->IsAccessCheckNeeded() &&
5868 !current->HasNamedInterceptor() &&
5869 !current->HasIndexedInterceptor());
5870 // Compute the property keys and cache them if possible.
5871 ASSIGN_RETURN_ON_EXCEPTION(
5872 isolate, content,
5873 FixedArray::UnionOfKeys(
5874 content, GetEnumPropertyKeys(current, cache_enum_keys)),
5875 FixedArray);
5876 DCHECK(ContainsOnlyValidKeys(content));
5877
5878 // Add the property keys from the interceptor.
5879 if (current->HasNamedInterceptor()) {
5880 Handle<JSObject> result;
5881 if (JSObject::GetKeysForNamedInterceptor(
5882 current, object).ToHandle(&result)) {
5883 ASSIGN_RETURN_ON_EXCEPTION(
5884 isolate, content,
5885 FixedArray::AddKeysFromArrayLike(content, result),
5886 FixedArray);
5887 }
5888 DCHECK(ContainsOnlyValidKeys(content));
5889 }
5890
5891 // If we only want own properties we bail out after the first
5892 // iteration.
5893 if (type == OWN_ONLY) break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005894 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005895 return content;
Steve Blocka7e24c12009-10-30 11:49:00 +00005896}
5897
5898
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005899// Try to update an accessor in an elements dictionary. Return true if the
5900// update succeeded, and false otherwise.
5901static bool UpdateGetterSetterInDictionary(
5902 SeededNumberDictionary* dictionary,
5903 uint32_t index,
5904 Object* getter,
5905 Object* setter,
5906 PropertyAttributes attributes) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005907 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00005908 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005909 Object* result = dictionary->ValueAt(entry);
5910 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005911 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005912 DCHECK(details.IsConfigurable());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005913 if (details.attributes() != attributes) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005914 dictionary->DetailsAtPut(
5915 entry,
5916 PropertyDetails(attributes, CALLBACKS, index));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005917 }
5918 AccessorPair::cast(result)->SetComponents(getter, setter);
5919 return true;
5920 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005921 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005922 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005923}
5924
5925
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005926void JSObject::DefineElementAccessor(Handle<JSObject> object,
5927 uint32_t index,
5928 Handle<Object> getter,
5929 Handle<Object> setter,
5930 PropertyAttributes attributes) {
5931 switch (object->GetElementsKind()) {
5932 case FAST_SMI_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005933 case FAST_ELEMENTS:
5934 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005935 case FAST_HOLEY_SMI_ELEMENTS:
5936 case FAST_HOLEY_ELEMENTS:
5937 case FAST_HOLEY_DOUBLE_ELEMENTS:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005938 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005939
5940#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
5941 case EXTERNAL_##TYPE##_ELEMENTS: \
5942 case TYPE##_ELEMENTS: \
5943
5944 TYPED_ARRAYS(TYPED_ARRAY_CASE)
5945#undef TYPED_ARRAY_CASE
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005946 // Ignore getters and setters on pixel and external array elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005947 return;
5948
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005949 case DICTIONARY_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005950 if (UpdateGetterSetterInDictionary(object->element_dictionary(),
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005951 index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005952 *getter,
5953 *setter,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005954 attributes)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005955 return;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005956 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005957 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005958 case SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005959 // Ascertain whether we have read-only properties or an existing
5960 // getter/setter pair in an arguments elements dictionary backing
5961 // store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005962 FixedArray* parameter_map = FixedArray::cast(object->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005963 uint32_t length = parameter_map->length();
5964 Object* probe =
5965 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
5966 if (probe == NULL || probe->IsTheHole()) {
5967 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
5968 if (arguments->IsDictionary()) {
5969 SeededNumberDictionary* dictionary =
5970 SeededNumberDictionary::cast(arguments);
5971 if (UpdateGetterSetterInDictionary(dictionary,
5972 index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005973 *getter,
5974 *setter,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005975 attributes)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005976 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005977 }
5978 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005979 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005980 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00005981 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005982 }
5983
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005984 Isolate* isolate = object->GetIsolate();
5985 Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
5986 accessors->SetComponents(*getter, *setter);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005987
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005988 SetElementCallback(object, index, accessors, attributes);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01005989}
5990
5991
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005992bool Map::DictionaryElementsInPrototypeChainOnly() {
5993 if (IsDictionaryElementsKind(elements_kind())) {
5994 return false;
5995 }
5996
5997 for (PrototypeIterator iter(this); !iter.IsAtEnd(); iter.Advance()) {
5998 if (iter.GetCurrent()->IsJSProxy()) {
5999 // Be conservative, don't walk into proxies.
6000 return true;
6001 }
6002
6003 if (IsDictionaryElementsKind(
6004 JSObject::cast(iter.GetCurrent())->map()->elements_kind())) {
6005 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00006006 }
6007 }
6008
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006009 return false;
Leon Clarkef7060e22010-06-03 12:02:55 +01006010}
6011
6012
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006013void JSObject::SetElementCallback(Handle<JSObject> object,
6014 uint32_t index,
6015 Handle<Object> structure,
6016 PropertyAttributes attributes) {
6017 Heap* heap = object->GetHeap();
6018 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01006019
6020 // Normalize elements to make this operation simple.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006021 bool had_dictionary_elements = object->HasDictionaryElements();
6022 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6023 DCHECK(object->HasDictionaryElements() ||
6024 object->HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01006025 // Update the dictionary with the new CALLBACKS property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006026 dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6027 details);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006028 dictionary->set_requires_slow_elements();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006029
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006030 // Update the dictionary backing store on the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006031 if (object->elements()->map() == heap->sloppy_arguments_elements_map()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006032 // Also delete any parameter alias.
6033 //
6034 // TODO(kmillikin): when deleting the last parameter alias we could
6035 // switch to a direct backing store without the parameter map. This
6036 // would allow GC of the context.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006037 FixedArray* parameter_map = FixedArray::cast(object->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006038 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006039 parameter_map->set(index + 2, heap->the_hole_value());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006040 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006041 parameter_map->set(1, *dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006042 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006043 object->set_elements(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +00006044
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006045 if (!had_dictionary_elements) {
6046 // KeyedStoreICs (at least the non-generic ones) need a reset.
6047 heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
6048 }
6049 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006050}
6051
6052
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006053void JSObject::SetPropertyCallback(Handle<JSObject> object,
6054 Handle<Name> name,
6055 Handle<Object> structure,
6056 PropertyAttributes attributes) {
6057 PropertyNormalizationMode mode = object->map()->is_prototype_map()
6058 ? KEEP_INOBJECT_PROPERTIES
6059 : CLEAR_INOBJECT_PROPERTIES;
Leon Clarkef7060e22010-06-03 12:02:55 +01006060 // Normalize object to make this operation simple.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006061 NormalizeProperties(object, mode, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +01006062
6063 // For the global object allocate a new map to invalidate the global inline
6064 // caches which have a global property cell reference directly in the code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006065 if (object->IsGlobalObject()) {
6066 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
6067 DCHECK(new_map->is_dictionary_map());
6068 JSObject::MigrateToMap(object, new_map);
6069
Ben Murdochb0fe1622011-05-05 13:52:32 +01006070 // When running crankshaft, changing the map is not enough. We
6071 // need to deoptimize all functions that rely on this global
6072 // object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006073 Deoptimizer::DeoptimizeGlobalObject(*object);
Leon Clarkef7060e22010-06-03 12:02:55 +01006074 }
6075
6076 // Update the dictionary with the new CALLBACKS property.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006077 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
6078 SetNormalizedProperty(object, name, structure, details);
Leon Clarkef7060e22010-06-03 12:02:55 +01006079
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006080 ReoptimizeIfPrototype(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006081}
6082
6083
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006084MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
6085 Handle<Name> name,
6086 Handle<Object> getter,
6087 Handle<Object> setter,
6088 PropertyAttributes attributes) {
6089 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006090 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006091 if (object->IsAccessCheckNeeded() &&
6092 !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6093 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6094 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6095 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006096 }
6097
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006098 if (object->IsJSGlobalProxy()) {
6099 PrototypeIterator iter(isolate, object);
6100 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
6101 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
6102 DefineAccessor(Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
6103 name, getter, setter, attributes);
6104 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006105 }
6106
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006107 // Make sure that the top context does not change when doing callbacks or
6108 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006109 AssertNoContextChange ncc(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006110
6111 // Try to flatten before operating on the string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006112 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006113
6114 uint32_t index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006115 bool is_element = name->AsArrayIndex(&index);
6116
6117 Handle<Object> old_value = isolate->factory()->the_hole_value();
6118 bool is_observed = object->map()->is_observed() &&
6119 *name != isolate->heap()->hidden_string();
6120 bool preexists = false;
6121 if (is_observed) {
6122 if (is_element) {
6123 Maybe<bool> maybe = HasOwnElement(object, index);
6124 // Workaround for a GCC 4.4.3 bug which leads to "‘preexists’ may be used
6125 // uninitialized in this function".
6126 if (!maybe.has_value) {
6127 DCHECK(false);
6128 return isolate->factory()->undefined_value();
6129 }
6130 preexists = maybe.value;
6131 if (preexists && GetOwnElementAccessorPair(object, index).is_null()) {
6132 old_value =
6133 Object::GetElement(isolate, object, index).ToHandleChecked();
6134 }
6135 } else {
6136 LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
6137 CHECK(GetPropertyAttributes(&it).has_value);
6138 preexists = it.IsFound();
6139 if (preexists && (it.state() == LookupIterator::DATA ||
6140 it.GetAccessors()->IsAccessorInfo())) {
6141 old_value = GetProperty(&it).ToHandleChecked();
6142 }
6143 }
6144 }
6145
6146 if (is_element) {
6147 DefineElementAccessor(object, index, getter, setter, attributes);
6148 } else {
6149 DCHECK(getter->IsSpecFunction() || getter->IsUndefined() ||
6150 getter->IsNull());
6151 DCHECK(setter->IsSpecFunction() || setter->IsUndefined() ||
6152 setter->IsNull());
6153 // At least one of the accessors needs to be a new value.
6154 DCHECK(!getter->IsNull() || !setter->IsNull());
6155 LookupIterator it(object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
6156 if (it.state() == LookupIterator::ACCESS_CHECK) {
6157 // We already did an access check before. We do have access.
6158 it.Next();
6159 }
6160 if (!getter->IsNull()) {
6161 it.TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes);
6162 }
6163 if (!setter->IsNull()) {
6164 it.TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes);
6165 }
6166 }
6167
6168 if (is_observed) {
6169 const char* type = preexists ? "reconfigure" : "add";
6170 EnqueueChangeRecord(object, type, name, old_value);
6171 }
6172
6173 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006174}
6175
6176
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006177MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6178 Handle<AccessorInfo> info) {
6179 Isolate* isolate = object->GetIsolate();
6180 Factory* factory = isolate->factory();
6181 Handle<Name> name(Name::cast(info->name()));
6182
Leon Clarkef7060e22010-06-03 12:02:55 +01006183 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006184 if (object->IsAccessCheckNeeded() &&
6185 !isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
6186 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
6187 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6188 return factory->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01006189 }
6190
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006191 if (object->IsJSGlobalProxy()) {
6192 PrototypeIterator iter(isolate, object);
6193 if (iter.IsAtEnd()) return object;
6194 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
6195 return SetAccessor(
6196 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), info);
Leon Clarkef7060e22010-06-03 12:02:55 +01006197 }
6198
6199 // Make sure that the top context does not change when doing callbacks or
6200 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006201 AssertNoContextChange ncc(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01006202
6203 // Try to flatten before operating on the string.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006204 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
Leon Clarkef7060e22010-06-03 12:02:55 +01006205
6206 uint32_t index = 0;
6207 bool is_element = name->AsArrayIndex(&index);
6208
6209 if (is_element) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006210 if (object->IsJSArray()) return factory->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01006211
6212 // Accessors overwrite previous callbacks (cf. with getters/setters).
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006213 switch (object->GetElementsKind()) {
6214 case FAST_SMI_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01006215 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006216 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006217 case FAST_HOLEY_SMI_ELEMENTS:
6218 case FAST_HOLEY_ELEMENTS:
6219 case FAST_HOLEY_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01006220 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006221
6222#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
6223 case EXTERNAL_##TYPE##_ELEMENTS: \
6224 case TYPE##_ELEMENTS: \
6225
6226 TYPED_ARRAYS(TYPED_ARRAY_CASE)
6227#undef TYPED_ARRAY_CASE
Leon Clarkef7060e22010-06-03 12:02:55 +01006228 // Ignore getters and setters on pixel and external array
6229 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006230 return factory->undefined_value();
6231
Leon Clarkef7060e22010-06-03 12:02:55 +01006232 case DICTIONARY_ELEMENTS:
6233 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006234 case SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006235 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01006236 break;
6237 }
6238
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006239 SetElementCallback(object, index, info, info->property_attributes());
Leon Clarkef7060e22010-06-03 12:02:55 +01006240 } else {
6241 // Lookup the name.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006242 LookupIterator it(object, name, LookupIterator::HIDDEN_SKIP_INTERCEPTOR);
6243 CHECK(GetPropertyAttributes(&it).has_value);
Leon Clarkef7060e22010-06-03 12:02:55 +01006244 // ES5 forbids turning a property into an accessor if it's not
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006245 // configurable. See 8.6.1 (Table 5).
6246 if (it.IsFound() && (it.IsReadOnly() || !it.IsConfigurable())) {
6247 return factory->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01006248 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006249
6250 SetPropertyCallback(object, name, info, info->property_attributes());
Leon Clarkef7060e22010-06-03 12:02:55 +01006251 }
6252
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006253 return object;
Leon Clarkef7060e22010-06-03 12:02:55 +01006254}
6255
6256
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006257MaybeHandle<Object> JSObject::GetAccessor(Handle<JSObject> object,
6258 Handle<Name> name,
6259 AccessorComponent component) {
6260 Isolate* isolate = object->GetIsolate();
Steve Block44f0eee2011-05-26 01:26:41 +01006261
Steve Blocka7e24c12009-10-30 11:49:00 +00006262 // Make sure that the top context does not change when doing callbacks or
6263 // interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006264 AssertNoContextChange ncc(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006265
6266 // Make the lookup and include prototypes.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006267 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00006268 if (name->AsArrayIndex(&index)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006269 for (PrototypeIterator iter(isolate, object,
6270 PrototypeIterator::START_AT_RECEIVER);
6271 !iter.IsAtEnd(); iter.Advance()) {
6272 Handle<Object> current = PrototypeIterator::GetCurrent(iter);
6273 // Check access rights if needed.
6274 if (current->IsAccessCheckNeeded() &&
6275 !isolate->MayNamedAccess(Handle<JSObject>::cast(current), name,
6276 v8::ACCESS_HAS)) {
6277 isolate->ReportFailedAccessCheck(Handle<JSObject>::cast(current),
6278 v8::ACCESS_HAS);
6279 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6280 return isolate->factory()->undefined_value();
6281 }
6282
6283 if (current->IsJSObject() &&
6284 Handle<JSObject>::cast(current)->HasDictionaryElements()) {
6285 JSObject* js_object = JSObject::cast(*current);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006286 SeededNumberDictionary* dictionary = js_object->element_dictionary();
Steve Blocka7e24c12009-10-30 11:49:00 +00006287 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +00006288 if (entry != SeededNumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006289 Object* element = dictionary->ValueAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006290 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6291 element->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006292 return handle(AccessorPair::cast(element)->GetComponent(component),
6293 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006294 }
6295 }
6296 }
6297 }
6298 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006299 LookupIterator it(object, name,
6300 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR);
6301 for (; it.IsFound(); it.Next()) {
6302 switch (it.state()) {
6303 case LookupIterator::INTERCEPTOR:
6304 case LookupIterator::NOT_FOUND:
6305 case LookupIterator::TRANSITION:
6306 UNREACHABLE();
6307
6308 case LookupIterator::ACCESS_CHECK:
6309 if (it.HasAccess(v8::ACCESS_HAS)) continue;
6310 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>(),
6311 v8::ACCESS_HAS);
6312 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
6313 return isolate->factory()->undefined_value();
6314
6315 case LookupIterator::JSPROXY:
6316 return isolate->factory()->undefined_value();
6317
6318 case LookupIterator::DATA:
6319 continue;
6320 case LookupIterator::ACCESSOR: {
6321 Handle<Object> maybe_pair = it.GetAccessors();
6322 if (maybe_pair->IsAccessorPair()) {
6323 return handle(
6324 AccessorPair::cast(*maybe_pair)->GetComponent(component),
6325 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006326 }
6327 }
6328 }
6329 }
6330 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006331 return isolate->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006332}
6333
6334
6335Object* JSObject::SlowReverseLookup(Object* value) {
6336 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006337 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00006338 DescriptorArray* descs = map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006339 for (int i = 0; i < number_of_own_descriptors; i++) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006340 if (descs->GetType(i) == FIELD) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006341 Object* property =
6342 RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
6343 if (descs->GetDetails(i).representation().IsDouble()) {
6344 DCHECK(property->IsMutableHeapNumber());
6345 if (value->IsNumber() && property->Number() == value->Number()) {
6346 return descs->GetKey(i);
6347 }
6348 } else if (property == value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006349 return descs->GetKey(i);
6350 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006351 } else if (descs->GetType(i) == CONSTANT) {
6352 if (descs->GetConstant(i) == value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006353 return descs->GetKey(i);
6354 }
6355 }
6356 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01006357 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00006358 } else {
6359 return property_dictionary()->SlowReverseLookup(value);
6360 }
6361}
6362
6363
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006364Handle<Map> Map::RawCopy(Handle<Map> map, int instance_size) {
6365 Handle<Map> result = map->GetIsolate()->factory()->NewMap(
6366 map->instance_type(), instance_size);
6367 result->set_prototype(map->prototype());
6368 result->set_constructor(map->constructor());
6369 result->set_bit_field(map->bit_field());
6370 result->set_bit_field2(map->bit_field2());
6371 int new_bit_field3 = map->bit_field3();
6372 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
6373 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
6374 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
6375 kInvalidEnumCacheSentinel);
6376 new_bit_field3 = Deprecated::update(new_bit_field3, false);
6377 if (!map->is_dictionary_map()) {
6378 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
John Reck59135872010-11-02 12:39:01 -07006379 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006380 new_bit_field3 = ConstructionCount::update(new_bit_field3,
6381 JSFunction::kNoSlackTracking);
6382 result->set_bit_field3(new_bit_field3);
Steve Blocka7e24c12009-10-30 11:49:00 +00006383 return result;
6384}
6385
6386
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006387Handle<Map> Map::Normalize(Handle<Map> fast_map,
6388 PropertyNormalizationMode mode) {
6389 DCHECK(!fast_map->is_dictionary_map());
6390
6391 Isolate* isolate = fast_map->GetIsolate();
6392 Handle<Object> maybe_cache(isolate->native_context()->normalized_map_cache(),
6393 isolate);
6394 bool use_cache = !maybe_cache->IsUndefined();
6395 Handle<NormalizedMapCache> cache;
6396 if (use_cache) cache = Handle<NormalizedMapCache>::cast(maybe_cache);
6397
6398 Handle<Map> new_map;
6399 if (use_cache && cache->Get(fast_map, mode).ToHandle(&new_map)) {
6400#ifdef VERIFY_HEAP
6401 if (FLAG_verify_heap) new_map->DictionaryMapVerify();
6402#endif
6403#ifdef ENABLE_SLOW_DCHECKS
6404 if (FLAG_enable_slow_asserts) {
6405 // The cached map should match newly created normalized map bit-by-bit,
6406 // except for the code cache, which can contain some ics which can be
6407 // applied to the shared map.
6408 Handle<Map> fresh = Map::CopyNormalized(fast_map, mode);
6409
6410 DCHECK(memcmp(fresh->address(),
6411 new_map->address(),
6412 Map::kCodeCacheOffset) == 0);
6413 STATIC_ASSERT(Map::kDependentCodeOffset ==
6414 Map::kCodeCacheOffset + kPointerSize);
6415 int offset = Map::kDependentCodeOffset + kPointerSize;
6416 DCHECK(memcmp(fresh->address() + offset,
6417 new_map->address() + offset,
6418 Map::kSize - offset) == 0);
6419 }
6420#endif
6421 } else {
6422 new_map = Map::CopyNormalized(fast_map, mode);
6423 if (use_cache) {
6424 cache->Set(fast_map, new_map);
6425 isolate->counters()->normalized_maps()->Increment();
6426 }
6427 }
6428 fast_map->NotifyLeafMapLayoutChange();
6429 return new_map;
6430}
6431
6432
6433Handle<Map> Map::CopyNormalized(Handle<Map> map,
6434 PropertyNormalizationMode mode) {
6435 int new_instance_size = map->instance_size();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006436 if (mode == CLEAR_INOBJECT_PROPERTIES) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006437 new_instance_size -= map->inobject_properties() * kPointerSize;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006438 }
6439
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006440 Handle<Map> result = RawCopy(map, new_instance_size);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006441
6442 if (mode != CLEAR_INOBJECT_PROPERTIES) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006443 result->set_inobject_properties(map->inobject_properties());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006444 }
6445
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006446 result->set_dictionary_map(true);
6447 result->set_migration_target(false);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006448
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006449#ifdef VERIFY_HEAP
6450 if (FLAG_verify_heap) result->DictionaryMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006451#endif
6452
6453 return result;
6454}
6455
6456
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006457Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
6458 Handle<Map> result = RawCopy(map, map->instance_size());
6459
6460 // Please note instance_type and instance_size are set when allocated.
6461 result->set_inobject_properties(map->inobject_properties());
6462 result->set_unused_property_fields(map->unused_property_fields());
6463
6464 result->set_pre_allocated_property_fields(
6465 map->pre_allocated_property_fields());
6466 result->ClearCodeCache(map->GetHeap());
6467 map->NotifyLeafMapLayoutChange();
6468 return result;
6469}
6470
6471
6472Handle<Map> Map::ShareDescriptor(Handle<Map> map,
6473 Handle<DescriptorArray> descriptors,
6474 Descriptor* descriptor) {
6475 // Sanity check. This path is only to be taken if the map owns its descriptor
6476 // array, implying that its NumberOfOwnDescriptors equals the number of
6477 // descriptors in the descriptor array.
6478 DCHECK(map->NumberOfOwnDescriptors() ==
6479 map->instance_descriptors()->number_of_descriptors());
6480
6481 Handle<Map> result = CopyDropDescriptors(map);
6482 Handle<Name> name = descriptor->GetKey();
6483
6484 // Ensure there's space for the new descriptor in the shared descriptor array.
6485 if (descriptors->NumberOfSlackDescriptors() == 0) {
6486 int old_size = descriptors->number_of_descriptors();
6487 if (old_size == 0) {
6488 descriptors = DescriptorArray::Allocate(map->GetIsolate(), 0, 1);
6489 } else {
6490 EnsureDescriptorSlack(map, old_size < 4 ? 1 : old_size / 2);
6491 descriptors = handle(map->instance_descriptors());
6492 }
John Reck59135872010-11-02 12:39:01 -07006493 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006494
6495 {
6496 DisallowHeapAllocation no_gc;
6497 descriptors->Append(descriptor);
6498 result->InitializeDescriptors(*descriptors);
John Reck59135872010-11-02 12:39:01 -07006499 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006500
6501 DCHECK(result->NumberOfOwnDescriptors() == map->NumberOfOwnDescriptors() + 1);
6502 ConnectTransition(map, result, name, SIMPLE_TRANSITION);
6503
6504 return result;
6505}
6506
6507
6508void Map::ConnectTransition(Handle<Map> parent, Handle<Map> child,
6509 Handle<Name> name, SimpleTransitionFlag flag) {
6510 parent->set_owns_descriptors(false);
6511 if (parent->is_prototype_map()) {
6512 DCHECK(child->is_prototype_map());
6513 } else {
6514 Handle<TransitionArray> transitions =
6515 TransitionArray::CopyInsert(parent, name, child, flag);
6516 parent->set_transitions(*transitions);
6517 child->SetBackPointer(*parent);
6518 }
6519}
6520
6521
6522Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
6523 Handle<DescriptorArray> descriptors,
6524 TransitionFlag flag,
6525 MaybeHandle<Name> maybe_name,
6526 SimpleTransitionFlag simple_flag) {
6527 DCHECK(descriptors->IsSortedNoDuplicates());
6528
6529 Handle<Map> result = CopyDropDescriptors(map);
6530 result->InitializeDescriptors(*descriptors);
6531
6532 if (!map->is_prototype_map()) {
6533 if (flag == INSERT_TRANSITION && map->CanHaveMoreTransitions()) {
6534 Handle<Name> name;
6535 CHECK(maybe_name.ToHandle(&name));
6536 ConnectTransition(map, result, name, simple_flag);
6537 } else {
6538 int length = descriptors->number_of_descriptors();
6539 for (int i = 0; i < length; i++) {
6540 descriptors->SetRepresentation(i, Representation::Tagged());
6541 if (descriptors->GetDetails(i).type() == FIELD) {
6542 descriptors->SetValue(i, HeapType::Any());
6543 }
6544 }
6545 }
6546 }
6547
6548 return result;
6549}
6550
6551
6552// Since this method is used to rewrite an existing transition tree, it can
6553// always insert transitions without checking.
6554Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
6555 int new_descriptor,
6556 Handle<DescriptorArray> descriptors) {
6557 DCHECK(descriptors->IsSortedNoDuplicates());
6558
6559 Handle<Map> result = CopyDropDescriptors(map);
6560
6561 result->InitializeDescriptors(*descriptors);
6562 result->SetNumberOfOwnDescriptors(new_descriptor + 1);
6563
6564 int unused_property_fields = map->unused_property_fields();
6565 if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
6566 unused_property_fields = map->unused_property_fields() - 1;
6567 if (unused_property_fields < 0) {
6568 unused_property_fields += JSObject::kFieldsAdded;
6569 }
6570 }
6571
6572 result->set_unused_property_fields(unused_property_fields);
6573
6574 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
6575 ConnectTransition(map, result, name, SIMPLE_TRANSITION);
6576
6577 return result;
6578}
6579
6580
6581Handle<Map> Map::CopyAsElementsKind(Handle<Map> map, ElementsKind kind,
6582 TransitionFlag flag) {
6583 if (flag == INSERT_TRANSITION) {
6584 DCHECK(!map->HasElementsTransition() ||
6585 ((map->elements_transition_map()->elements_kind() ==
6586 DICTIONARY_ELEMENTS ||
6587 IsExternalArrayElementsKind(
6588 map->elements_transition_map()->elements_kind())) &&
6589 (kind == DICTIONARY_ELEMENTS ||
6590 IsExternalArrayElementsKind(kind))));
6591 DCHECK(!IsFastElementsKind(kind) ||
6592 IsMoreGeneralElementsKindTransition(map->elements_kind(), kind));
6593 DCHECK(kind != map->elements_kind());
6594 }
6595
6596 bool insert_transition =
6597 flag == INSERT_TRANSITION && !map->HasElementsTransition();
6598
6599 if (insert_transition && map->owns_descriptors()) {
6600 // In case the map owned its own descriptors, share the descriptors and
6601 // transfer ownership to the new map.
6602 Handle<Map> new_map = CopyDropDescriptors(map);
6603
6604 ConnectElementsTransition(map, new_map);
6605
6606 new_map->set_elements_kind(kind);
6607 new_map->InitializeDescriptors(map->instance_descriptors());
6608 return new_map;
6609 }
6610
6611 // In case the map did not own its own descriptors, a split is forced by
6612 // copying the map; creating a new descriptor array cell.
6613 // Create a new free-floating map only if we are not allowed to store it.
6614 Handle<Map> new_map = Copy(map);
6615
6616 new_map->set_elements_kind(kind);
6617
6618 if (insert_transition) {
6619 ConnectElementsTransition(map, new_map);
6620 }
6621
Steve Block8defd9f2010-07-08 12:39:36 +01006622 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00006623}
6624
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006625
6626Handle<Map> Map::CopyForObserved(Handle<Map> map) {
6627 DCHECK(!map->is_observed());
6628
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006629 Isolate* isolate = map->GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006630
6631 // In case the map owned its own descriptors, share the descriptors and
6632 // transfer ownership to the new map.
6633 Handle<Map> new_map;
6634 if (map->owns_descriptors()) {
6635 new_map = CopyDropDescriptors(map);
6636 } else {
6637 DCHECK(!map->is_prototype_map());
6638 new_map = Copy(map);
6639 }
6640
6641 new_map->set_is_observed();
6642 if (map->owns_descriptors()) {
6643 new_map->InitializeDescriptors(map->instance_descriptors());
6644 }
6645
6646 Handle<Name> name = isolate->factory()->observed_symbol();
6647 ConnectTransition(map, new_map, name, FULL_TRANSITION);
6648
6649 return new_map;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006650}
Steve Blocka7e24c12009-10-30 11:49:00 +00006651
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006652
6653Handle<Map> Map::Copy(Handle<Map> map) {
6654 Handle<DescriptorArray> descriptors(map->instance_descriptors());
6655 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
6656 Handle<DescriptorArray> new_descriptors =
6657 DescriptorArray::CopyUpTo(descriptors, number_of_own_descriptors);
6658 return CopyReplaceDescriptors(
6659 map, new_descriptors, OMIT_TRANSITION, MaybeHandle<Name>());
6660}
6661
6662
6663Handle<Map> Map::Create(Isolate* isolate, int inobject_properties) {
6664 Handle<Map> copy = Copy(handle(isolate->object_function()->initial_map()));
6665
6666 // Check that we do not overflow the instance size when adding the extra
6667 // inobject properties. If the instance size overflows, we allocate as many
6668 // properties as we can as inobject properties.
6669 int max_extra_properties =
6670 (JSObject::kMaxInstanceSize - JSObject::kHeaderSize) >> kPointerSizeLog2;
6671
6672 if (inobject_properties > max_extra_properties) {
6673 inobject_properties = max_extra_properties;
6674 }
6675
6676 int new_instance_size =
6677 JSObject::kHeaderSize + kPointerSize * inobject_properties;
6678
6679 // Adjust the map with the extra inobject properties.
6680 copy->set_inobject_properties(inobject_properties);
6681 copy->set_unused_property_fields(inobject_properties);
6682 copy->set_instance_size(new_instance_size);
6683 copy->set_visitor_id(StaticVisitorBase::GetVisitorId(*copy));
6684 return copy;
6685}
6686
6687
6688Handle<Map> Map::CopyForFreeze(Handle<Map> map) {
6689 int num_descriptors = map->NumberOfOwnDescriptors();
6690 Isolate* isolate = map->GetIsolate();
6691 Handle<DescriptorArray> new_desc = DescriptorArray::CopyUpToAddAttributes(
6692 handle(map->instance_descriptors(), isolate), num_descriptors, FROZEN);
6693 Handle<Map> new_map = CopyReplaceDescriptors(
6694 map, new_desc, INSERT_TRANSITION, isolate->factory()->frozen_symbol());
6695 new_map->freeze();
6696 new_map->set_is_extensible(false);
6697 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
6698 return new_map;
6699}
6700
6701
6702bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
6703 PropertyDetails details = GetDetails(descriptor);
6704 switch (details.type()) {
6705 case FIELD:
6706 return value->FitsRepresentation(details.representation()) &&
6707 GetFieldType(descriptor)->NowContains(value);
6708
6709 case CONSTANT:
6710 DCHECK(GetConstant(descriptor) != value ||
6711 value->FitsRepresentation(details.representation()));
6712 return GetConstant(descriptor) == value;
6713
6714 case CALLBACKS:
6715 return false;
6716
6717 case NORMAL:
6718 UNREACHABLE();
6719 break;
6720 }
6721
6722 UNREACHABLE();
6723 return false;
6724}
6725
6726
6727Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
6728 Handle<Object> value) {
6729 // Dictionaries can store any property value.
6730 if (map->is_dictionary_map()) return map;
6731
6732 // Migrate to the newest map before storing the property.
6733 map = Update(map);
6734
6735 Handle<DescriptorArray> descriptors(map->instance_descriptors());
6736
6737 if (descriptors->CanHoldValue(descriptor, *value)) return map;
6738
6739 Isolate* isolate = map->GetIsolate();
6740 Representation representation = value->OptimalRepresentation();
6741 Handle<HeapType> type = value->OptimalType(isolate, representation);
6742
6743 return GeneralizeRepresentation(map, descriptor, representation, type,
6744 FORCE_FIELD);
6745}
6746
6747
6748Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
6749 Handle<Object> value,
6750 PropertyAttributes attributes,
6751 StoreFromKeyed store_mode) {
6752 // Dictionary maps can always have additional data properties.
6753 if (map->is_dictionary_map()) return map;
6754
6755 // Migrate to the newest map before storing the property.
6756 map = Update(map);
6757
6758 int index = map->SearchTransition(*name);
6759 if (index != TransitionArray::kNotFound) {
6760 Handle<Map> transition(map->GetTransition(index));
6761 int descriptor = transition->LastAdded();
6762
6763 // TODO(verwaest): Handle attributes better.
6764 DescriptorArray* descriptors = transition->instance_descriptors();
6765 if (descriptors->GetDetails(descriptor).attributes() != attributes) {
6766 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
John Reck59135872010-11-02 12:39:01 -07006767 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006768
6769 return Map::PrepareForDataProperty(transition, descriptor, value);
6770 }
6771
6772 TransitionFlag flag = INSERT_TRANSITION;
6773 MaybeHandle<Map> maybe_map;
6774 if (value->IsJSFunction()) {
6775 maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
6776 } else if (!map->TooManyFastProperties(store_mode)) {
6777 Isolate* isolate = name->GetIsolate();
6778 Representation representation = value->OptimalRepresentation();
6779 Handle<HeapType> type = value->OptimalType(isolate, representation);
6780 maybe_map =
6781 Map::CopyWithField(map, name, type, attributes, representation, flag);
6782 }
6783
6784 Handle<Map> result;
6785 if (!maybe_map.ToHandle(&result)) {
6786 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
6787 }
6788
6789 return result;
6790}
6791
6792
6793Handle<Map> Map::ReconfigureDataProperty(Handle<Map> map, int descriptor,
6794 PropertyAttributes attributes) {
6795 // Dictionaries have to be reconfigured in-place.
6796 DCHECK(!map->is_dictionary_map());
6797
6798 // For now, give up on transitioning and just create a unique map.
6799 // TODO(verwaest/ishell): Cache transitions with different attributes.
6800 return CopyGeneralizeAllRepresentations(map, descriptor, FORCE_FIELD,
6801 attributes, "attributes mismatch");
6802}
6803
6804
6805Handle<Map> Map::TransitionToAccessorProperty(Handle<Map> map,
6806 Handle<Name> name,
6807 AccessorComponent component,
6808 Handle<Object> accessor,
6809 PropertyAttributes attributes) {
6810 Isolate* isolate = name->GetIsolate();
6811
6812 // Dictionary maps can always have additional data properties.
6813 if (map->is_dictionary_map()) {
6814 // For global objects, property cells are inlined. We need to change the
6815 // map.
6816 if (map->IsGlobalObjectMap()) return Copy(map);
6817 return map;
6818 }
6819
6820 // Migrate to the newest map before transitioning to the new property.
6821 map = Update(map);
6822
6823 PropertyNormalizationMode mode = map->is_prototype_map()
6824 ? KEEP_INOBJECT_PROPERTIES
6825 : CLEAR_INOBJECT_PROPERTIES;
6826
6827 int index = map->SearchTransition(*name);
6828 if (index != TransitionArray::kNotFound) {
6829 Handle<Map> transition(map->GetTransition(index));
6830 DescriptorArray* descriptors = transition->instance_descriptors();
6831 // Fast path, assume that we're modifying the last added descriptor.
6832 int descriptor = transition->LastAdded();
6833 if (descriptors->GetKey(descriptor) != *name) {
6834 // If not, search for the descriptor.
6835 descriptor = descriptors->SearchWithCache(*name, *transition);
6836 }
6837
6838 if (descriptors->GetDetails(descriptor).type() != CALLBACKS) {
6839 return Map::Normalize(map, mode);
6840 }
6841
6842 // TODO(verwaest): Handle attributes better.
6843 if (descriptors->GetDetails(descriptor).attributes() != attributes) {
6844 return Map::Normalize(map, mode);
6845 }
6846
6847 Handle<Object> maybe_pair(descriptors->GetValue(descriptor), isolate);
6848 if (!maybe_pair->IsAccessorPair()) {
6849 return Map::Normalize(map, mode);
6850 }
6851
6852 Handle<AccessorPair> pair = Handle<AccessorPair>::cast(maybe_pair);
6853 if (pair->get(component) != *accessor) {
6854 return Map::Normalize(map, mode);
6855 }
6856
6857 return transition;
6858 }
6859
6860 Handle<AccessorPair> pair;
6861 DescriptorArray* old_descriptors = map->instance_descriptors();
6862 int descriptor = old_descriptors->SearchWithCache(*name, *map);
6863 if (descriptor != DescriptorArray::kNotFound) {
6864 PropertyDetails old_details = old_descriptors->GetDetails(descriptor);
6865 if (old_details.type() != CALLBACKS) {
6866 return Map::Normalize(map, mode);
6867 }
6868
6869 if (old_details.attributes() != attributes) {
6870 return Map::Normalize(map, mode);
6871 }
6872
6873 Handle<Object> maybe_pair(old_descriptors->GetValue(descriptor), isolate);
6874 if (!maybe_pair->IsAccessorPair()) {
6875 return Map::Normalize(map, mode);
6876 }
6877
6878 Object* current = Handle<AccessorPair>::cast(maybe_pair)->get(component);
6879 if (current == *accessor) return map;
6880
6881 if (!current->IsTheHole()) {
6882 return Map::Normalize(map, mode);
6883 }
6884
6885 pair = AccessorPair::Copy(Handle<AccessorPair>::cast(maybe_pair));
6886 } else if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors ||
6887 map->TooManyFastProperties(CERTAINLY_NOT_STORE_FROM_KEYED)) {
6888 return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
6889 } else {
6890 pair = isolate->factory()->NewAccessorPair();
6891 }
6892
6893 pair->set(component, *accessor);
6894 TransitionFlag flag = INSERT_TRANSITION;
6895 CallbacksDescriptor new_desc(name, pair, attributes);
6896 return Map::CopyInsertDescriptor(map, &new_desc, flag);
6897}
6898
6899
6900Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
6901 Descriptor* descriptor,
6902 TransitionFlag flag) {
6903 Handle<DescriptorArray> descriptors(map->instance_descriptors());
6904
6905 // Ensure the key is unique.
6906 descriptor->KeyToUniqueName();
6907
6908 if (flag == INSERT_TRANSITION &&
6909 map->owns_descriptors() &&
6910 map->CanHaveMoreTransitions()) {
6911 return ShareDescriptor(map, descriptors, descriptor);
6912 }
6913
6914 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
6915 descriptors, map->NumberOfOwnDescriptors(), 1);
6916 new_descriptors->Append(descriptor);
6917
6918 return CopyReplaceDescriptors(
6919 map, new_descriptors, flag, descriptor->GetKey(), SIMPLE_TRANSITION);
6920}
6921
6922
6923Handle<Map> Map::CopyInsertDescriptor(Handle<Map> map,
6924 Descriptor* descriptor,
6925 TransitionFlag flag) {
6926 Handle<DescriptorArray> old_descriptors(map->instance_descriptors());
6927
6928 // Ensure the key is unique.
6929 descriptor->KeyToUniqueName();
6930
6931 // We replace the key if it is already present.
6932 int index = old_descriptors->SearchWithCache(*descriptor->GetKey(), *map);
6933 if (index != DescriptorArray::kNotFound) {
6934 return CopyReplaceDescriptor(map, old_descriptors, descriptor, index, flag);
6935 }
6936 return CopyAddDescriptor(map, descriptor, flag);
6937}
6938
6939
6940Handle<DescriptorArray> DescriptorArray::CopyUpTo(
6941 Handle<DescriptorArray> desc,
6942 int enumeration_index,
6943 int slack) {
6944 return DescriptorArray::CopyUpToAddAttributes(
6945 desc, enumeration_index, NONE, slack);
6946}
6947
6948
6949Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
6950 Handle<DescriptorArray> desc,
6951 int enumeration_index,
6952 PropertyAttributes attributes,
6953 int slack) {
6954 if (enumeration_index + slack == 0) {
6955 return desc->GetIsolate()->factory()->empty_descriptor_array();
6956 }
6957
6958 int size = enumeration_index;
6959
6960 Handle<DescriptorArray> descriptors =
6961 DescriptorArray::Allocate(desc->GetIsolate(), size, slack);
6962 DescriptorArray::WhitenessWitness witness(*descriptors);
6963
6964 if (attributes != NONE) {
6965 for (int i = 0; i < size; ++i) {
6966 Object* value = desc->GetValue(i);
6967 Name* key = desc->GetKey(i);
6968 PropertyDetails details = desc->GetDetails(i);
6969 // Bulk attribute changes never affect private properties.
6970 if (!key->IsSymbol() || !Symbol::cast(key)->is_private()) {
6971 int mask = DONT_DELETE | DONT_ENUM;
6972 // READ_ONLY is an invalid attribute for JS setters/getters.
6973 if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
6974 mask |= READ_ONLY;
6975 }
6976 details = details.CopyAddAttributes(
6977 static_cast<PropertyAttributes>(attributes & mask));
6978 }
6979 Descriptor inner_desc(
6980 handle(key), handle(value, desc->GetIsolate()), details);
6981 descriptors->Set(i, &inner_desc, witness);
6982 }
6983 } else {
6984 for (int i = 0; i < size; ++i) {
6985 descriptors->CopyFrom(i, *desc, witness);
6986 }
6987 }
6988
6989 if (desc->number_of_descriptors() != enumeration_index) descriptors->Sort();
6990
6991 return descriptors;
6992}
6993
6994
6995Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
6996 Handle<DescriptorArray> descriptors,
6997 Descriptor* descriptor,
6998 int insertion_index,
6999 TransitionFlag flag) {
7000 // Ensure the key is unique.
7001 descriptor->KeyToUniqueName();
7002
7003 Handle<Name> key = descriptor->GetKey();
7004 DCHECK(*key == descriptors->GetKey(insertion_index));
7005
7006 Handle<DescriptorArray> new_descriptors = DescriptorArray::CopyUpTo(
7007 descriptors, map->NumberOfOwnDescriptors());
7008
7009 new_descriptors->Replace(insertion_index, descriptor);
7010
7011 SimpleTransitionFlag simple_flag =
7012 (insertion_index == descriptors->number_of_descriptors() - 1)
7013 ? SIMPLE_TRANSITION
7014 : FULL_TRANSITION;
7015 return CopyReplaceDescriptors(map, new_descriptors, flag, key, simple_flag);
7016}
7017
7018
7019void Map::UpdateCodeCache(Handle<Map> map,
7020 Handle<Name> name,
7021 Handle<Code> code) {
7022 Isolate* isolate = map->GetIsolate();
7023 HandleScope scope(isolate);
7024 // Allocate the code cache if not present.
7025 if (map->code_cache()->IsFixedArray()) {
7026 Handle<Object> result = isolate->factory()->NewCodeCache();
7027 map->set_code_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +01007028 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007029
Steve Block6ded16b2010-05-10 14:33:55 +01007030 // Update the code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007031 Handle<CodeCache> code_cache(CodeCache::cast(map->code_cache()), isolate);
7032 CodeCache::Update(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007033}
7034
7035
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007036Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007037 // Do a lookup if a code cache exists.
7038 if (!code_cache()->IsFixedArray()) {
7039 return CodeCache::cast(code_cache())->Lookup(name, flags);
7040 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007041 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007042 }
7043}
7044
7045
7046int Map::IndexInCodeCache(Object* name, Code* code) {
7047 // Get the internal index if a code cache exists.
7048 if (!code_cache()->IsFixedArray()) {
7049 return CodeCache::cast(code_cache())->GetIndex(name, code);
7050 }
7051 return -1;
7052}
7053
7054
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007055void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
Steve Block6ded16b2010-05-10 14:33:55 +01007056 // No GC is supposed to happen between a call to IndexInCodeCache and
7057 // RemoveFromCodeCache so the code cache must be there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007058 DCHECK(!code_cache()->IsFixedArray());
Steve Block6ded16b2010-05-10 14:33:55 +01007059 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7060}
7061
7062
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007063// An iterator over all map transitions in an descriptor array, reusing the
7064// constructor field of the map while it is running. Negative values in
7065// the constructor field indicate an active map transition iteration. The
7066// original constructor is restored after iterating over all entries.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007067class IntrusiveMapTransitionIterator {
7068 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007069 IntrusiveMapTransitionIterator(
7070 Map* map, TransitionArray* transition_array, Object* constructor)
7071 : map_(map),
7072 transition_array_(transition_array),
7073 constructor_(constructor) { }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007074
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007075 void StartIfNotStarted() {
7076 DCHECK(!(*IteratorField())->IsSmi() || IsIterating());
7077 if (!(*IteratorField())->IsSmi()) {
7078 DCHECK(*IteratorField() == constructor_);
7079 *IteratorField() = Smi::FromInt(-1);
7080 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007081 }
7082
7083 bool IsIterating() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007084 return (*IteratorField())->IsSmi() &&
7085 Smi::cast(*IteratorField())->value() < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007086 }
7087
7088 Map* Next() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007089 DCHECK(IsIterating());
7090 int value = Smi::cast(*IteratorField())->value();
7091 int index = -value - 1;
7092 int number_of_transitions = transition_array_->number_of_transitions();
7093 while (index < number_of_transitions) {
7094 *IteratorField() = Smi::FromInt(value - 1);
7095 return transition_array_->GetTarget(index);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007096 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007097
7098 *IteratorField() = constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007099 return NULL;
7100 }
Ben Murdochc7cc0282012-03-05 14:35:55 +00007101
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007102 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007103 Object** IteratorField() {
7104 return HeapObject::RawField(map_, Map::kConstructorOffset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007105 }
7106
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007107 Map* map_;
7108 TransitionArray* transition_array_;
7109 Object* constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007110};
7111
7112
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007113// An iterator over all prototype transitions, reusing the constructor field
7114// of the map while it is running. Positive values in the constructor field
7115// indicate an active prototype transition iteration. The original constructor
7116// is restored after iterating over all entries.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007117class IntrusivePrototypeTransitionIterator {
7118 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007119 IntrusivePrototypeTransitionIterator(
7120 Map* map, HeapObject* proto_trans, Object* constructor)
7121 : map_(map), proto_trans_(proto_trans), constructor_(constructor) { }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007122
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007123 void StartIfNotStarted() {
7124 if (!(*IteratorField())->IsSmi()) {
7125 DCHECK(*IteratorField() == constructor_);
7126 *IteratorField() = Smi::FromInt(0);
7127 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007128 }
7129
7130 bool IsIterating() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007131 return (*IteratorField())->IsSmi() &&
7132 Smi::cast(*IteratorField())->value() >= 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007133 }
7134
7135 Map* Next() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007136 DCHECK(IsIterating());
7137 int transitionNumber = Smi::cast(*IteratorField())->value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007138 if (transitionNumber < NumberOfTransitions()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007139 *IteratorField() = Smi::FromInt(transitionNumber + 1);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007140 return GetTransition(transitionNumber);
7141 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007142 *IteratorField() = constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007143 return NULL;
7144 }
7145
7146 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007147 Object** IteratorField() {
7148 return HeapObject::RawField(map_, Map::kConstructorOffset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007149 }
7150
7151 int NumberOfTransitions() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007152 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7153 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007154 return Smi::cast(num)->value();
7155 }
7156
7157 Map* GetTransition(int transitionNumber) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007158 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7159 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007160 }
7161
7162 int IndexFor(int transitionNumber) {
7163 return Map::kProtoTransitionHeaderSize +
7164 Map::kProtoTransitionMapOffset +
7165 transitionNumber * Map::kProtoTransitionElementsPerEntry;
7166 }
7167
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007168 Map* map_;
7169 HeapObject* proto_trans_;
7170 Object* constructor_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007171};
7172
7173
7174// To traverse the transition tree iteratively, we have to store two kinds of
7175// information in a map: The parent map in the traversal and which children of a
7176// node have already been visited. To do this without additional memory, we
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007177// temporarily reuse two fields with known values:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007178//
7179// (1) The map of the map temporarily holds the parent, and is restored to the
7180// meta map afterwards.
7181//
7182// (2) The info which children have already been visited depends on which part
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007183// of the map we currently iterate. We use the constructor field of the
7184// map to store the current index. We can do that because the constructor
7185// is the same for all involved maps.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007186//
7187// (a) If we currently follow normal map transitions, we temporarily store
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007188// the current index in the constructor field, and restore it to the
7189// original constructor afterwards. Note that a single descriptor can
7190// have 0, 1, or 2 transitions.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007191//
7192// (b) If we currently follow prototype transitions, we temporarily store
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007193// the current index in the constructor field, and restore it to the
7194// original constructor afterwards.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007195//
7196// Note that the child iterator is just a concatenation of two iterators: One
7197// iterating over map transitions and one iterating over prototype transisitons.
7198class TraversableMap : public Map {
7199 public:
7200 // Record the parent in the traversal within this map. Note that this destroys
7201 // this map's map!
7202 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7203
7204 // Reset the current map's map, returning the parent previously stored in it.
7205 TraversableMap* GetAndResetParent() {
7206 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7207 set_map_no_write_barrier(GetHeap()->meta_map());
7208 return old_parent;
7209 }
7210
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007211 // If we have an unvisited child map, return that one and advance. If we have
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007212 // none, return NULL and restore the overwritten constructor field.
7213 TraversableMap* ChildIteratorNext(Object* constructor) {
7214 if (!HasTransitionArray()) return NULL;
7215
7216 TransitionArray* transition_array = transitions();
7217 if (transition_array->HasPrototypeTransitions()) {
7218 HeapObject* proto_transitions =
7219 transition_array->GetPrototypeTransitions();
7220 IntrusivePrototypeTransitionIterator proto_iterator(this,
7221 proto_transitions,
7222 constructor);
7223 proto_iterator.StartIfNotStarted();
7224 if (proto_iterator.IsIterating()) {
7225 Map* next = proto_iterator.Next();
7226 if (next != NULL) return static_cast<TraversableMap*>(next);
7227 }
7228 }
7229
7230 IntrusiveMapTransitionIterator transition_iterator(this,
7231 transition_array,
7232 constructor);
7233 transition_iterator.StartIfNotStarted();
7234 if (transition_iterator.IsIterating()) {
7235 Map* next = transition_iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007236 if (next != NULL) return static_cast<TraversableMap*>(next);
7237 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007238
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007239 return NULL;
7240 }
7241};
7242
7243
7244// Traverse the transition tree in postorder without using the C++ stack by
7245// doing pointer reversal.
7246void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007247 // Make sure that we do not allocate in the callback.
7248 DisallowHeapAllocation no_allocation;
7249
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007250 TraversableMap* current = static_cast<TraversableMap*>(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007251 // Get the root constructor here to restore it later when finished iterating
7252 // over maps.
7253 Object* root_constructor = constructor();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007254 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007255 TraversableMap* child = current->ChildIteratorNext(root_constructor);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007256 if (child != NULL) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007257 child->SetParent(current);
7258 current = child;
7259 } else {
7260 TraversableMap* parent = current->GetAndResetParent();
7261 callback(current, data);
7262 if (current == this) break;
7263 current = parent;
7264 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007265 }
7266}
7267
7268
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007269void CodeCache::Update(
7270 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007271 // The number of monomorphic stubs for normal load/store/call IC's can grow to
7272 // a large number and therefore they need to go into a hash table. They are
7273 // used to load global properties from cells.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007274 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +01007275 // Make sure that a hash table is allocated for the normal load code cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007276 if (code_cache->normal_type_cache()->IsUndefined()) {
7277 Handle<Object> result =
7278 CodeCacheHashTable::New(code_cache->GetIsolate(),
7279 CodeCacheHashTable::kInitialSize);
7280 code_cache->set_normal_type_cache(*result);
Steve Block6ded16b2010-05-10 14:33:55 +01007281 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007282 UpdateNormalTypeCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007283 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007284 DCHECK(code_cache->default_cache()->IsFixedArray());
7285 UpdateDefaultCache(code_cache, name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007286 }
7287}
7288
7289
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007290void CodeCache::UpdateDefaultCache(
7291 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007292 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00007293 // flags. This allows call constant stubs to overwrite call field
7294 // stubs, etc.
7295 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
7296
7297 // First check whether we can update existing code cache without
7298 // extending it.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007299 Handle<FixedArray> cache = handle(code_cache->default_cache());
Steve Blocka7e24c12009-10-30 11:49:00 +00007300 int length = cache->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007301 {
7302 DisallowHeapAllocation no_alloc;
7303 int deleted_index = -1;
7304 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7305 Object* key = cache->get(i);
7306 if (key->IsNull()) {
7307 if (deleted_index < 0) deleted_index = i;
7308 continue;
7309 }
7310 if (key->IsUndefined()) {
7311 if (deleted_index >= 0) i = deleted_index;
7312 cache->set(i + kCodeCacheEntryNameOffset, *name);
7313 cache->set(i + kCodeCacheEntryCodeOffset, *code);
7314 return;
7315 }
7316 if (name->Equals(Name::cast(key))) {
7317 Code::Flags found =
7318 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
7319 if (Code::RemoveTypeFromFlags(found) == flags) {
7320 cache->set(i + kCodeCacheEntryCodeOffset, *code);
7321 return;
7322 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007323 }
7324 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007325
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007326 // Reached the end of the code cache. If there were deleted
7327 // elements, reuse the space for the first of them.
7328 if (deleted_index >= 0) {
7329 cache->set(deleted_index + kCodeCacheEntryNameOffset, *name);
7330 cache->set(deleted_index + kCodeCacheEntryCodeOffset, *code);
7331 return;
7332 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007333 }
7334
Steve Block6ded16b2010-05-10 14:33:55 +01007335 // Extend the code cache with some new entries (at least one). Must be a
7336 // multiple of the entry size.
7337 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
7338 new_length = new_length - new_length % kCodeCacheEntrySize;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007339 DCHECK((new_length % kCodeCacheEntrySize) == 0);
7340 cache = FixedArray::CopySize(cache, new_length);
Steve Blocka7e24c12009-10-30 11:49:00 +00007341
7342 // Add the (name, code) pair to the new cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007343 cache->set(length + kCodeCacheEntryNameOffset, *name);
7344 cache->set(length + kCodeCacheEntryCodeOffset, *code);
7345 code_cache->set_default_cache(*cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00007346}
7347
7348
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007349void CodeCache::UpdateNormalTypeCache(
7350 Handle<CodeCache> code_cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007351 // Adding a new entry can cause a new cache to be allocated.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007352 Handle<CodeCacheHashTable> cache(
7353 CodeCacheHashTable::cast(code_cache->normal_type_cache()));
7354 Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
7355 code_cache->set_normal_type_cache(*new_cache);
Steve Block6ded16b2010-05-10 14:33:55 +01007356}
7357
7358
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007359Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
7360 Object* result = LookupDefaultCache(name, Code::RemoveTypeFromFlags(flags));
7361 if (result->IsCode()) {
7362 if (Code::cast(result)->flags() == flags) return result;
7363 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007364 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007365 return LookupNormalTypeCache(name, flags);
Steve Block6ded16b2010-05-10 14:33:55 +01007366}
7367
7368
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007369Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007370 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007371 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01007372 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7373 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00007374 // Skip deleted elements.
7375 if (key->IsNull()) continue;
7376 if (key->IsUndefined()) return key;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007377 if (name->Equals(Name::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01007378 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007379 if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007380 return code;
7381 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007382 }
7383 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01007384 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007385}
7386
7387
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007388Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007389 if (!normal_type_cache()->IsUndefined()) {
7390 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7391 return cache->Lookup(name, flags);
7392 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007393 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007394 }
7395}
7396
7397
7398int CodeCache::GetIndex(Object* name, Code* code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007399 if (code->type() == Code::NORMAL) {
Steve Block6ded16b2010-05-10 14:33:55 +01007400 if (normal_type_cache()->IsUndefined()) return -1;
7401 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007402 return cache->GetIndex(Name::cast(name), code->flags());
Steve Block6ded16b2010-05-10 14:33:55 +01007403 }
7404
7405 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00007406 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01007407 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
7408 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00007409 }
7410 return -1;
7411}
7412
7413
Steve Block6ded16b2010-05-10 14:33:55 +01007414void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007415 if (code->type() == Code::NORMAL) {
7416 DCHECK(!normal_type_cache()->IsUndefined());
Steve Block6ded16b2010-05-10 14:33:55 +01007417 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007418 DCHECK(cache->GetIndex(Name::cast(name), code->flags()) == index);
Steve Block6ded16b2010-05-10 14:33:55 +01007419 cache->RemoveByIndex(index);
7420 } else {
7421 FixedArray* array = default_cache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007422 DCHECK(array->length() >= index && array->get(index)->IsCode());
Steve Block6ded16b2010-05-10 14:33:55 +01007423 // Use null instead of undefined for deleted elements to distinguish
7424 // deleted elements from unused elements. This distinction is used
7425 // when looking up in the cache and when updating the cache.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007426 DCHECK_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
Steve Block6ded16b2010-05-10 14:33:55 +01007427 array->set_null(index - 1); // Name.
7428 array->set_null(index); // Code.
7429 }
7430}
7431
7432
7433// The key in the code cache hash table consists of the property name and the
7434// code object. The actual match is on the name and the code flags. If a key
7435// is created using the flags and not a code object it can only be used for
7436// lookup not to create a new entry.
7437class CodeCacheHashTableKey : public HashTableKey {
7438 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007439 CodeCacheHashTableKey(Handle<Name> name, Code::Flags flags)
7440 : name_(name), flags_(flags), code_() { }
Steve Block6ded16b2010-05-10 14:33:55 +01007441
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007442 CodeCacheHashTableKey(Handle<Name> name, Handle<Code> code)
7443 : name_(name), flags_(code->flags()), code_(code) { }
Steve Block6ded16b2010-05-10 14:33:55 +01007444
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007445 bool IsMatch(Object* other) OVERRIDE {
Steve Block6ded16b2010-05-10 14:33:55 +01007446 if (!other->IsFixedArray()) return false;
7447 FixedArray* pair = FixedArray::cast(other);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007448 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +01007449 Code::Flags flags = Code::cast(pair->get(1))->flags();
7450 if (flags != flags_) {
7451 return false;
7452 }
7453 return name_->Equals(name);
7454 }
7455
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007456 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01007457 return name->Hash() ^ flags;
7458 }
7459
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007460 uint32_t Hash() OVERRIDE { return NameFlagsHashHelper(*name_, flags_); }
Steve Block6ded16b2010-05-10 14:33:55 +01007461
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007462 uint32_t HashForObject(Object* obj) OVERRIDE {
Steve Block6ded16b2010-05-10 14:33:55 +01007463 FixedArray* pair = FixedArray::cast(obj);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007464 Name* name = Name::cast(pair->get(0));
Steve Block6ded16b2010-05-10 14:33:55 +01007465 Code* code = Code::cast(pair->get(1));
7466 return NameFlagsHashHelper(name, code->flags());
7467 }
7468
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007469 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
7470 Handle<Code> code = code_.ToHandleChecked();
7471 Handle<FixedArray> pair = isolate->factory()->NewFixedArray(2);
7472 pair->set(0, *name_);
7473 pair->set(1, *code);
Steve Block6ded16b2010-05-10 14:33:55 +01007474 return pair;
7475 }
7476
7477 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007478 Handle<Name> name_;
Steve Block6ded16b2010-05-10 14:33:55 +01007479 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007480 // TODO(jkummerow): We should be able to get by without this.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007481 MaybeHandle<Code> code_;
Steve Block6ded16b2010-05-10 14:33:55 +01007482};
7483
7484
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007485Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
7486 DisallowHeapAllocation no_alloc;
7487 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +01007488 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01007489 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01007490 return get(EntryToIndex(entry) + 1);
7491}
7492
7493
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007494Handle<CodeCacheHashTable> CodeCacheHashTable::Put(
7495 Handle<CodeCacheHashTable> cache, Handle<Name> name, Handle<Code> code) {
Steve Block6ded16b2010-05-10 14:33:55 +01007496 CodeCacheHashTableKey key(name, code);
Steve Block6ded16b2010-05-10 14:33:55 +01007497
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007498 Handle<CodeCacheHashTable> new_cache = EnsureCapacity(cache, 1, &key);
Steve Block6ded16b2010-05-10 14:33:55 +01007499
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007500 int entry = new_cache->FindInsertionEntry(key.Hash());
7501 Handle<Object> k = key.AsHandle(cache->GetIsolate());
Steve Block6ded16b2010-05-10 14:33:55 +01007502
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007503 new_cache->set(EntryToIndex(entry), *k);
7504 new_cache->set(EntryToIndex(entry) + 1, *code);
7505 new_cache->ElementAdded();
7506 return new_cache;
Steve Block6ded16b2010-05-10 14:33:55 +01007507}
7508
7509
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007510int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
7511 DisallowHeapAllocation no_alloc;
7512 CodeCacheHashTableKey key(handle(name), flags);
Steve Block6ded16b2010-05-10 14:33:55 +01007513 int entry = FindEntry(&key);
7514 return (entry == kNotFound) ? -1 : entry;
7515}
7516
7517
7518void CodeCacheHashTable::RemoveByIndex(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007519 DCHECK(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01007520 Heap* heap = GetHeap();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007521 set(EntryToIndex(index), heap->the_hole_value());
7522 set(EntryToIndex(index) + 1, heap->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01007523 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00007524}
7525
7526
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007527void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> code_cache,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007528 MapHandleList* maps,
7529 Code::Flags flags,
7530 Handle<Code> code) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007531 Isolate* isolate = code_cache->GetIsolate();
7532 if (code_cache->cache()->IsUndefined()) {
7533 Handle<PolymorphicCodeCacheHashTable> result =
7534 PolymorphicCodeCacheHashTable::New(
7535 isolate,
7536 PolymorphicCodeCacheHashTable::kInitialSize);
7537 code_cache->set_cache(*result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007538 } else {
7539 // This entry shouldn't be contained in the cache yet.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007540 DCHECK(PolymorphicCodeCacheHashTable::cast(code_cache->cache())
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007541 ->Lookup(maps, flags)->IsUndefined());
7542 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007543 Handle<PolymorphicCodeCacheHashTable> hash_table =
7544 handle(PolymorphicCodeCacheHashTable::cast(code_cache->cache()));
7545 Handle<PolymorphicCodeCacheHashTable> new_cache =
7546 PolymorphicCodeCacheHashTable::Put(hash_table, maps, flags, code);
7547 code_cache->set_cache(*new_cache);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007548}
7549
7550
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007551Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
7552 Code::Flags flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007553 if (!cache()->IsUndefined()) {
7554 PolymorphicCodeCacheHashTable* hash_table =
7555 PolymorphicCodeCacheHashTable::cast(cache());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007556 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007557 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007558 return GetIsolate()->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007559 }
7560}
7561
7562
7563// Despite their name, object of this class are not stored in the actual
7564// hash table; instead they're temporarily used for lookups. It is therefore
7565// safe to have a weak (non-owning) pointer to a MapList as a member field.
7566class PolymorphicCodeCacheHashTableKey : public HashTableKey {
7567 public:
7568 // Callers must ensure that |maps| outlives the newly constructed object.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007569 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007570 : maps_(maps),
7571 code_flags_(code_flags) {}
7572
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007573 bool IsMatch(Object* other) OVERRIDE {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007574 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007575 int other_flags;
7576 FromObject(other, &other_flags, &other_maps);
7577 if (code_flags_ != other_flags) return false;
7578 if (maps_->length() != other_maps.length()) return false;
7579 // Compare just the hashes first because it's faster.
7580 int this_hash = MapsHashHelper(maps_, code_flags_);
7581 int other_hash = MapsHashHelper(&other_maps, other_flags);
7582 if (this_hash != other_hash) return false;
7583
7584 // Full comparison: for each map in maps_, look for an equivalent map in
7585 // other_maps. This implementation is slow, but probably good enough for
7586 // now because the lists are short (<= 4 elements currently).
7587 for (int i = 0; i < maps_->length(); ++i) {
7588 bool match_found = false;
7589 for (int j = 0; j < other_maps.length(); ++j) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007590 if (*(maps_->at(i)) == *(other_maps.at(j))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007591 match_found = true;
7592 break;
7593 }
7594 }
7595 if (!match_found) return false;
7596 }
7597 return true;
7598 }
7599
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007600 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007601 uint32_t hash = code_flags;
7602 for (int i = 0; i < maps->length(); ++i) {
7603 hash ^= maps->at(i)->Hash();
7604 }
7605 return hash;
7606 }
7607
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007608 uint32_t Hash() OVERRIDE {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007609 return MapsHashHelper(maps_, code_flags_);
7610 }
7611
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007612 uint32_t HashForObject(Object* obj) OVERRIDE {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007613 MapHandleList other_maps(kDefaultListAllocationSize);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007614 int other_flags;
7615 FromObject(obj, &other_flags, &other_maps);
7616 return MapsHashHelper(&other_maps, other_flags);
7617 }
7618
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007619 MUST_USE_RESULT Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007620 // The maps in |maps_| must be copied to a newly allocated FixedArray,
7621 // both because the referenced MapList is short-lived, and because C++
7622 // objects can't be stored in the heap anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007623 Handle<FixedArray> list =
7624 isolate->factory()->NewUninitializedFixedArray(maps_->length() + 1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007625 list->set(0, Smi::FromInt(code_flags_));
7626 for (int i = 0; i < maps_->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007627 list->set(i + 1, *maps_->at(i));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007628 }
7629 return list;
7630 }
7631
7632 private:
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007633 static MapHandleList* FromObject(Object* obj,
7634 int* code_flags,
7635 MapHandleList* maps) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007636 FixedArray* list = FixedArray::cast(obj);
7637 maps->Rewind(0);
7638 *code_flags = Smi::cast(list->get(0))->value();
7639 for (int i = 1; i < list->length(); ++i) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007640 maps->Add(Handle<Map>(Map::cast(list->get(i))));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007641 }
7642 return maps;
7643 }
7644
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007645 MapHandleList* maps_; // weak.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007646 int code_flags_;
7647 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
7648};
7649
7650
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007651Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007652 int code_kind) {
7653 DisallowHeapAllocation no_alloc;
7654 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007655 int entry = FindEntry(&key);
7656 if (entry == kNotFound) return GetHeap()->undefined_value();
7657 return get(EntryToIndex(entry) + 1);
7658}
7659
7660
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007661Handle<PolymorphicCodeCacheHashTable> PolymorphicCodeCacheHashTable::Put(
7662 Handle<PolymorphicCodeCacheHashTable> hash_table,
7663 MapHandleList* maps,
7664 int code_kind,
7665 Handle<Code> code) {
7666 PolymorphicCodeCacheHashTableKey key(maps, code_kind);
7667 Handle<PolymorphicCodeCacheHashTable> cache =
7668 EnsureCapacity(hash_table, 1, &key);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007669 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007670
7671 Handle<Object> obj = key.AsHandle(hash_table->GetIsolate());
7672 cache->set(EntryToIndex(entry), *obj);
7673 cache->set(EntryToIndex(entry) + 1, *code);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007674 cache->ElementAdded();
7675 return cache;
7676}
7677
7678
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007679void FixedArray::Shrink(int new_length) {
7680 DCHECK(0 <= new_length && new_length <= length());
7681 if (new_length < length()) {
7682 GetHeap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(
7683 this, length() - new_length);
7684 }
7685}
7686
7687
7688MaybeHandle<FixedArray> FixedArray::AddKeysFromArrayLike(
7689 Handle<FixedArray> content,
7690 Handle<JSObject> array) {
7691 DCHECK(array->IsJSArray() || array->HasSloppyArgumentsElements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007692 ElementsAccessor* accessor = array->GetElementsAccessor();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007693 Handle<FixedArray> result;
7694 ASSIGN_RETURN_ON_EXCEPTION(
7695 array->GetIsolate(), result,
7696 accessor->AddElementsToFixedArray(array, array, content),
7697 FixedArray);
7698
7699#ifdef ENABLE_SLOW_DCHECKS
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007700 if (FLAG_enable_slow_asserts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007701 DisallowHeapAllocation no_allocation;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007702 for (int i = 0; i < result->length(); i++) {
7703 Object* current = result->get(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007704 DCHECK(current->IsNumber() || current->IsName());
Steve Blocka7e24c12009-10-30 11:49:00 +00007705 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007706 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007707#endif
7708 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007709}
7710
7711
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007712MaybeHandle<FixedArray> FixedArray::UnionOfKeys(Handle<FixedArray> first,
7713 Handle<FixedArray> second) {
7714 ElementsAccessor* accessor = ElementsAccessor::ForArray(second);
7715 Handle<FixedArray> result;
7716 ASSIGN_RETURN_ON_EXCEPTION(
7717 first->GetIsolate(), result,
7718 accessor->AddElementsToFixedArray(
7719 Handle<Object>::null(), // receiver
7720 Handle<JSObject>::null(), // holder
7721 first,
7722 Handle<FixedArrayBase>::cast(second)),
7723 FixedArray);
7724
7725#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochf87a2032010-10-22 12:50:53 +01007726 if (FLAG_enable_slow_asserts) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007727 DisallowHeapAllocation no_allocation;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007728 for (int i = 0; i < result->length(); i++) {
7729 Object* current = result->get(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007730 DCHECK(current->IsNumber() || current->IsName());
Ben Murdochf87a2032010-10-22 12:50:53 +01007731 }
7732 }
7733#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00007734 return result;
7735}
7736
7737
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007738Handle<FixedArray> FixedArray::CopySize(
7739 Handle<FixedArray> array, int new_length, PretenureFlag pretenure) {
7740 Isolate* isolate = array->GetIsolate();
7741 if (new_length == 0) return isolate->factory()->empty_fixed_array();
7742 Handle<FixedArray> result =
7743 isolate->factory()->NewFixedArray(new_length, pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +00007744 // Copy the content
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007745 DisallowHeapAllocation no_gc;
7746 int len = array->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00007747 if (new_length < len) len = new_length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007748 // We are taking the map from the old fixed array so the map is sure to
7749 // be an immortal immutable object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007750 result->set_map_no_write_barrier(array->map());
Leon Clarke4515c472010-02-03 11:58:03 +00007751 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00007752 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007753 result->set(i, array->get(i), mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00007754 }
7755 return result;
7756}
7757
7758
7759void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007760 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +00007761 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00007762 for (int index = 0; index < len; index++) {
7763 dest->set(dest_pos+index, get(pos+index), mode);
7764 }
7765}
7766
7767
7768#ifdef DEBUG
7769bool FixedArray::IsEqualTo(FixedArray* other) {
7770 if (length() != other->length()) return false;
7771 for (int i = 0 ; i < length(); ++i) {
7772 if (get(i) != other->get(i)) return false;
7773 }
7774 return true;
7775}
7776#endif
7777
7778
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007779Handle<DescriptorArray> DescriptorArray::Allocate(Isolate* isolate,
7780 int number_of_descriptors,
7781 int slack) {
7782 DCHECK(0 <= number_of_descriptors);
7783 Factory* factory = isolate->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +00007784 // Do not use DescriptorArray::cast on incomplete object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007785 int size = number_of_descriptors + slack;
7786 if (size == 0) return factory->empty_descriptor_array();
7787 // Allocate the array of keys.
7788 Handle<FixedArray> result = factory->NewFixedArray(LengthFor(size));
Steve Blocka7e24c12009-10-30 11:49:00 +00007789
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007790 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
7791 result->set(kEnumCacheIndex, Smi::FromInt(0));
7792 return Handle<DescriptorArray>::cast(result);
7793}
7794
7795
7796void DescriptorArray::ClearEnumCache() {
7797 set(kEnumCacheIndex, Smi::FromInt(0));
7798}
7799
7800
7801void DescriptorArray::Replace(int index, Descriptor* descriptor) {
7802 descriptor->SetSortedKeyIndex(GetSortedKeyIndex(index));
7803 Set(index, descriptor);
Steve Blocka7e24c12009-10-30 11:49:00 +00007804}
7805
7806
7807void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007808 FixedArray* new_cache,
7809 Object* new_index_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007810 DCHECK(bridge_storage->length() >= kEnumCacheBridgeLength);
7811 DCHECK(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
7812 DCHECK(!IsEmpty());
7813 DCHECK(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
7814 FixedArray::cast(bridge_storage)->
7815 set(kEnumCacheBridgeCacheIndex, new_cache);
7816 FixedArray::cast(bridge_storage)->
7817 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
7818 set(kEnumCacheIndex, bridge_storage);
Steve Blocka7e24c12009-10-30 11:49:00 +00007819}
7820
7821
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007822void DescriptorArray::CopyFrom(int index,
7823 DescriptorArray* src,
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007824 const WhitenessWitness& witness) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007825 Object* value = src->GetValue(index);
7826 PropertyDetails details = src->GetDetails(index);
7827 Descriptor desc(handle(src->GetKey(index)),
7828 handle(value, src->GetIsolate()),
7829 details);
7830 Set(index, &desc, witness);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007831}
7832
7833
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007834// We need the whiteness witness since sort will reshuffle the entries in the
7835// descriptor array. If the descriptor array were to be black, the shuffling
7836// would move a slot that was already recorded as pointing into an evacuation
7837// candidate. This would result in missing updates upon evacuation.
7838void DescriptorArray::Sort() {
Steve Blocka7e24c12009-10-30 11:49:00 +00007839 // In-place heap sort.
7840 int len = number_of_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007841 // Reset sorting since the descriptor array might contain invalid pointers.
7842 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00007843 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01007844 // Index of the last node with children
7845 const int max_parent_index = (len / 2) - 1;
7846 for (int i = max_parent_index; i >= 0; --i) {
7847 int parent_index = i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007848 const uint32_t parent_hash = GetSortedKey(i)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01007849 while (parent_index <= max_parent_index) {
7850 int child_index = 2 * parent_index + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007851 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01007852 if (child_index + 1 < len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007853 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01007854 if (right_child_hash > child_hash) {
7855 child_index++;
7856 child_hash = right_child_hash;
7857 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007858 }
Steve Block6ded16b2010-05-10 14:33:55 +01007859 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007860 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01007861 // Now element at child_index could be < its children.
7862 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00007863 }
7864 }
7865
7866 // Extract elements and create sorted array.
7867 for (int i = len - 1; i > 0; --i) {
7868 // Put max element at the back of the array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007869 SwapSortedKeys(0, i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007870 // Shift down the new top element.
Steve Blocka7e24c12009-10-30 11:49:00 +00007871 int parent_index = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007872 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01007873 const int max_parent_index = (i / 2) - 1;
7874 while (parent_index <= max_parent_index) {
7875 int child_index = parent_index * 2 + 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007876 uint32_t child_hash = GetSortedKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01007877 if (child_index + 1 < i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007878 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01007879 if (right_child_hash > child_hash) {
7880 child_index++;
7881 child_hash = right_child_hash;
7882 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007883 }
Steve Block6ded16b2010-05-10 14:33:55 +01007884 if (child_hash <= parent_hash) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007885 SwapSortedKeys(parent_index, child_index);
Steve Block6ded16b2010-05-10 14:33:55 +01007886 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00007887 }
7888 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007889 DCHECK(IsSortedNoDuplicates());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007890}
Steve Blocka7e24c12009-10-30 11:49:00 +00007891
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007892
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007893Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
7894 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
7895 copy->set_getter(pair->getter());
7896 copy->set_setter(pair->setter());
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007897 return copy;
7898}
7899
7900
7901Object* AccessorPair::GetComponent(AccessorComponent component) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007902 Object* accessor = get(component);
7903 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007904}
7905
7906
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007907Handle<DeoptimizationInputData> DeoptimizationInputData::New(
7908 Isolate* isolate, int deopt_entry_count, PretenureFlag pretenure) {
7909 DCHECK(deopt_entry_count > 0);
7910 return Handle<DeoptimizationInputData>::cast(
7911 isolate->factory()->NewFixedArray(LengthFor(deopt_entry_count),
7912 pretenure));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007913}
7914
7915
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007916Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
7917 Isolate* isolate,
7918 int number_of_deopt_points,
7919 PretenureFlag pretenure) {
7920 Handle<FixedArray> result;
7921 if (number_of_deopt_points == 0) {
7922 result = isolate->factory()->empty_fixed_array();
7923 } else {
7924 result = isolate->factory()->NewFixedArray(
7925 LengthOfFixedArray(number_of_deopt_points), pretenure);
7926 }
7927 return Handle<DeoptimizationOutputData>::cast(result);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007928}
7929
7930
Steve Blocka7e24c12009-10-30 11:49:00 +00007931#ifdef DEBUG
7932bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
7933 if (IsEmpty()) return other->IsEmpty();
7934 if (other->IsEmpty()) return false;
7935 if (length() != other->length()) return false;
7936 for (int i = 0; i < length(); ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007937 if (get(i) != other->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007938 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007939 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00007940}
7941#endif
7942
7943
Steve Blocka7e24c12009-10-30 11:49:00 +00007944bool String::LooksValid() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007945 if (!GetIsolate()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007946 return true;
7947}
7948
7949
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007950String::FlatContent String::GetFlatContent() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007951 DCHECK(!AllowHeapAllocation::IsAllowed());
Steve Blocka7e24c12009-10-30 11:49:00 +00007952 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007953 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007954 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00007955 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007956 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007957 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007958 if (cons->second()->length() != 0) {
7959 return FlatContent();
7960 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007961 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007962 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00007963 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007964 if (shape.representation_tag() == kSlicedStringTag) {
7965 SlicedString* slice = SlicedString::cast(string);
7966 offset = slice->offset();
7967 string = slice->parent();
7968 shape = StringShape(string);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007969 DCHECK(shape.representation_tag() != kConsStringTag &&
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007970 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00007971 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007972 if (shape.encoding_tag() == kOneByteStringTag) {
7973 const uint8_t* start;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007974 if (shape.representation_tag() == kSeqStringTag) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007975 start = SeqOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007976 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007977 start = ExternalOneByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007978 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007979 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007980 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007981 DCHECK(shape.encoding_tag() == kTwoByteStringTag);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007982 const uc16* start;
7983 if (shape.representation_tag() == kSeqStringTag) {
7984 start = SeqTwoByteString::cast(string)->GetChars();
7985 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01007986 start = ExternalTwoByteString::cast(string)->GetChars();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007987 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007988 return FlatContent(start + offset, length);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007989 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007990}
7991
7992
Ben Murdoch589d6972011-11-30 16:04:58 +00007993SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
7994 RobustnessFlag robust_flag,
7995 int offset,
7996 int length,
7997 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007998 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00007999 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008000 }
Steve Block44f0eee2011-05-26 01:26:41 +01008001 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008002
8003 // Negative length means the to the end of the string.
8004 if (length < 0) length = kMaxInt - offset;
8005
8006 // Compute the size of the UTF-8 string. Start at the specified offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008007 Access<ConsStringIteratorOp> op(
8008 heap->isolate()->objects_string_iterator());
8009 StringCharacterStream stream(this, op.value(), offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00008010 int character_position = offset;
8011 int utf8_bytes = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008012 int last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008013 while (stream.HasMore() && character_position++ < offset + length) {
8014 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008015 utf8_bytes += unibrow::Utf8::Length(character, last);
8016 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +00008017 }
8018
8019 if (length_return) {
8020 *length_return = utf8_bytes;
8021 }
8022
8023 char* result = NewArray<char>(utf8_bytes + 1);
8024
8025 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008026 stream.Reset(this, offset);
Steve Blocka7e24c12009-10-30 11:49:00 +00008027 character_position = offset;
8028 int utf8_byte_position = 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008029 last = unibrow::Utf16::kNoPreviousCharacter;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008030 while (stream.HasMore() && character_position++ < offset + length) {
8031 uint16_t character = stream.GetNext();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008032 if (allow_nulls == DISALLOW_NULLS && character == 0) {
8033 character = ' ';
Steve Blocka7e24c12009-10-30 11:49:00 +00008034 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008035 utf8_byte_position +=
8036 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8037 last = character;
Steve Blocka7e24c12009-10-30 11:49:00 +00008038 }
8039 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00008040 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00008041}
8042
8043
Ben Murdoch589d6972011-11-30 16:04:58 +00008044SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8045 RobustnessFlag robust_flag,
8046 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008047 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8048}
8049
8050
Steve Blocka7e24c12009-10-30 11:49:00 +00008051const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008052 DCHECK(!IsOneByteRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00008053 switch (StringShape(this).representation_tag()) {
8054 case kSeqStringTag:
8055 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
8056 case kExternalStringTag:
8057 return ExternalTwoByteString::cast(this)->
8058 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008059 case kSlicedStringTag: {
8060 SlicedString* slice = SlicedString::cast(this);
8061 return slice->parent()->GetTwoByteData(start + slice->offset());
8062 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008063 case kConsStringTag:
8064 UNREACHABLE();
8065 return NULL;
8066 }
8067 UNREACHABLE();
8068 return NULL;
8069}
8070
8071
Ben Murdoch589d6972011-11-30 16:04:58 +00008072SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008073 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00008074 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00008075 }
Steve Block44f0eee2011-05-26 01:26:41 +01008076 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008077
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008078 Access<ConsStringIteratorOp> op(
8079 heap->isolate()->objects_string_iterator());
8080 StringCharacterStream stream(this, op.value());
Steve Blocka7e24c12009-10-30 11:49:00 +00008081
8082 uc16* result = NewArray<uc16>(length() + 1);
8083
8084 int i = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008085 while (stream.HasMore()) {
8086 uint16_t character = stream.GetNext();
Steve Blocka7e24c12009-10-30 11:49:00 +00008087 result[i++] = character;
8088 }
8089 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00008090 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00008091}
8092
8093
8094const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
8095 return reinterpret_cast<uc16*>(
8096 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
8097}
8098
8099
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008100void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
Steve Block44f0eee2011-05-26 01:26:41 +01008101 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00008102 while (current != NULL) {
8103 current->PostGarbageCollection();
8104 current = current->prev_;
8105 }
8106}
8107
8108
8109// Reserve space for statics needing saving and restoring.
8110int Relocatable::ArchiveSpacePerThread() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008111 return sizeof(Relocatable*); // NOLINT
Steve Blocka7e24c12009-10-30 11:49:00 +00008112}
8113
8114
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008115// Archive statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +00008116char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01008117 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
8118 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008119 return to + ArchiveSpacePerThread();
8120}
8121
8122
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008123// Restore statics that are thread-local.
Ben Murdoch257744e2011-11-30 15:57:28 +00008124char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01008125 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00008126 return from + ArchiveSpacePerThread();
8127}
8128
8129
8130char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
8131 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
8132 Iterate(v, top);
8133 return thread_storage + ArchiveSpacePerThread();
8134}
8135
8136
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008137void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01008138 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00008139}
8140
8141
8142void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
8143 Relocatable* current = top;
8144 while (current != NULL) {
8145 current->IterateInstance(v);
8146 current = current->prev_;
8147 }
8148}
8149
8150
Steve Block44f0eee2011-05-26 01:26:41 +01008151FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
8152 : Relocatable(isolate),
8153 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00008154 length_(str->length()) {
8155 PostGarbageCollection();
8156}
8157
8158
Steve Block44f0eee2011-05-26 01:26:41 +01008159FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
8160 : Relocatable(isolate),
8161 str_(0),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008162 is_one_byte_(true),
Steve Blocka7e24c12009-10-30 11:49:00 +00008163 length_(input.length()),
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008164 start_(input.start()) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00008165
8166
8167void FlatStringReader::PostGarbageCollection() {
8168 if (str_ == NULL) return;
8169 Handle<String> str(str_);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008170 DCHECK(str->IsFlat());
8171 DisallowHeapAllocation no_gc;
8172 // This does not actually prevent the vector from being relocated later.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008173 String::FlatContent content = str->GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008174 DCHECK(content.IsFlat());
8175 is_one_byte_ = content.IsOneByte();
8176 if (is_one_byte_) {
8177 start_ = content.ToOneByteVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00008178 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008179 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00008180 }
8181}
8182
8183
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008184void ConsStringIteratorOp::Initialize(ConsString* cons_string, int offset) {
8185 DCHECK(cons_string != NULL);
8186 root_ = cons_string;
8187 consumed_ = offset;
8188 // Force stack blown condition to trigger restart.
8189 depth_ = 1;
8190 maximum_depth_ = kStackSize + depth_;
8191 DCHECK(StackBlown());
Steve Blocka7e24c12009-10-30 11:49:00 +00008192}
8193
8194
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008195String* ConsStringIteratorOp::Continue(int* offset_out) {
8196 DCHECK(depth_ != 0);
8197 DCHECK_EQ(0, *offset_out);
8198 bool blew_stack = StackBlown();
8199 String* string = NULL;
8200 // Get the next leaf if there is one.
8201 if (!blew_stack) string = NextLeaf(&blew_stack);
8202 // Restart search from root.
8203 if (blew_stack) {
8204 DCHECK(string == NULL);
8205 string = Search(offset_out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008206 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008207 // Ensure future calls return null immediately.
8208 if (string == NULL) Reset(NULL);
8209 return string;
Steve Blocka7e24c12009-10-30 11:49:00 +00008210}
8211
8212
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008213String* ConsStringIteratorOp::Search(int* offset_out) {
8214 ConsString* cons_string = root_;
8215 // Reset the stack, pushing the root string.
8216 depth_ = 1;
8217 maximum_depth_ = 1;
8218 frames_[0] = cons_string;
8219 const int consumed = consumed_;
8220 int offset = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008221 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008222 // Loop until the string is found which contains the target offset.
8223 String* string = cons_string->first();
8224 int length = string->length();
8225 int32_t type;
8226 if (consumed < offset + length) {
8227 // Target offset is in the left branch.
8228 // Keep going if we're still in a ConString.
8229 type = string->map()->instance_type();
8230 if ((type & kStringRepresentationMask) == kConsStringTag) {
8231 cons_string = ConsString::cast(string);
8232 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00008233 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00008234 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008235 // Tell the stack we're done descending.
8236 AdjustMaximumDepth();
Steve Blocka7e24c12009-10-30 11:49:00 +00008237 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008238 // Descend right.
8239 // Update progress through the string.
8240 offset += length;
8241 // Keep going if we're still in a ConString.
8242 string = cons_string->second();
8243 type = string->map()->instance_type();
8244 if ((type & kStringRepresentationMask) == kConsStringTag) {
8245 cons_string = ConsString::cast(string);
8246 PushRight(cons_string);
8247 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00008248 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008249 // Need this to be updated for the current string.
8250 length = string->length();
8251 // Account for the possibility of an empty right leaf.
8252 // This happens only if we have asked for an offset outside the string.
8253 if (length == 0) {
8254 // Reset so future operations will return null immediately.
8255 Reset(NULL);
8256 return NULL;
8257 }
8258 // Tell the stack we're done descending.
8259 AdjustMaximumDepth();
8260 // Pop stack so next iteration is in correct place.
8261 Pop();
8262 }
8263 DCHECK(length != 0);
8264 // Adjust return values and exit.
8265 consumed_ = offset + length;
8266 *offset_out = consumed - offset;
8267 return string;
8268 }
8269 UNREACHABLE();
8270 return NULL;
8271}
8272
8273
8274String* ConsStringIteratorOp::NextLeaf(bool* blew_stack) {
8275 while (true) {
8276 // Tree traversal complete.
8277 if (depth_ == 0) {
8278 *blew_stack = false;
8279 return NULL;
8280 }
8281 // We've lost track of higher nodes.
8282 if (StackBlown()) {
8283 *blew_stack = true;
8284 return NULL;
8285 }
8286 // Go right.
8287 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
8288 String* string = cons_string->second();
8289 int32_t type = string->map()->instance_type();
8290 if ((type & kStringRepresentationMask) != kConsStringTag) {
8291 // Pop stack so next iteration is in correct place.
8292 Pop();
8293 int length = string->length();
8294 // Could be a flattened ConsString.
8295 if (length == 0) continue;
8296 consumed_ += length;
8297 return string;
8298 }
8299 cons_string = ConsString::cast(string);
8300 PushRight(cons_string);
8301 // Need to traverse all the way left.
8302 while (true) {
8303 // Continue left.
8304 string = cons_string->first();
8305 type = string->map()->instance_type();
8306 if ((type & kStringRepresentationMask) != kConsStringTag) {
8307 AdjustMaximumDepth();
8308 int length = string->length();
8309 DCHECK(length != 0);
8310 consumed_ += length;
8311 return string;
8312 }
8313 cons_string = ConsString::cast(string);
8314 PushLeft(cons_string);
Steve Blocka7e24c12009-10-30 11:49:00 +00008315 }
8316 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008317 UNREACHABLE();
8318 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00008319}
8320
8321
Steve Blocka7e24c12009-10-30 11:49:00 +00008322uint16_t ConsString::ConsStringGet(int index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008323 DCHECK(index >= 0 && index < this->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008324
8325 // Check for a flattened cons string
8326 if (second()->length() == 0) {
8327 String* left = first();
8328 return left->Get(index);
8329 }
8330
8331 String* string = String::cast(this);
8332
8333 while (true) {
8334 if (StringShape(string).IsCons()) {
8335 ConsString* cons_string = ConsString::cast(string);
8336 String* left = cons_string->first();
8337 if (left->length() > index) {
8338 string = left;
8339 } else {
8340 index -= left->length();
8341 string = cons_string->second();
8342 }
8343 } else {
8344 return string->Get(index);
8345 }
8346 }
8347
8348 UNREACHABLE();
8349 return 0;
8350}
8351
8352
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008353uint16_t SlicedString::SlicedStringGet(int index) {
8354 return parent()->Get(offset() + index);
8355}
8356
8357
Steve Blocka7e24c12009-10-30 11:49:00 +00008358template <typename sinkchar>
8359void String::WriteToFlat(String* src,
8360 sinkchar* sink,
8361 int f,
8362 int t) {
8363 String* source = src;
8364 int from = f;
8365 int to = t;
8366 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008367 DCHECK(0 <= from && from <= to && to <= source->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008368 switch (StringShape(source).full_representation_tag()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008369 case kOneByteStringTag | kExternalStringTag: {
8370 CopyChars(sink, ExternalOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00008371 to - from);
8372 return;
8373 }
8374 case kTwoByteStringTag | kExternalStringTag: {
8375 const uc16* data =
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008376 ExternalTwoByteString::cast(source)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00008377 CopyChars(sink,
8378 data + from,
8379 to - from);
8380 return;
8381 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008382 case kOneByteStringTag | kSeqStringTag: {
Steve Blocka7e24c12009-10-30 11:49:00 +00008383 CopyChars(sink,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008384 SeqOneByteString::cast(source)->GetChars() + from,
Steve Blocka7e24c12009-10-30 11:49:00 +00008385 to - from);
8386 return;
8387 }
8388 case kTwoByteStringTag | kSeqStringTag: {
8389 CopyChars(sink,
8390 SeqTwoByteString::cast(source)->GetChars() + from,
8391 to - from);
8392 return;
8393 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008394 case kOneByteStringTag | kConsStringTag:
Steve Blocka7e24c12009-10-30 11:49:00 +00008395 case kTwoByteStringTag | kConsStringTag: {
8396 ConsString* cons_string = ConsString::cast(source);
8397 String* first = cons_string->first();
8398 int boundary = first->length();
8399 if (to - boundary >= boundary - from) {
8400 // Right hand side is longer. Recurse over left.
8401 if (from < boundary) {
8402 WriteToFlat(first, sink, from, boundary);
8403 sink += boundary - from;
8404 from = 0;
8405 } else {
8406 from -= boundary;
8407 }
8408 to -= boundary;
8409 source = cons_string->second();
8410 } else {
8411 // Left hand side is longer. Recurse over right.
8412 if (to > boundary) {
8413 String* second = cons_string->second();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008414 // When repeatedly appending to a string, we get a cons string that
8415 // is unbalanced to the left, a list, essentially. We inline the
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008416 // common case of sequential one-byte right child.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008417 if (to - boundary == 1) {
8418 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008419 } else if (second->IsSeqOneByteString()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008420 CopyChars(sink + boundary - from,
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008421 SeqOneByteString::cast(second)->GetChars(),
Steve Blocka7e24c12009-10-30 11:49:00 +00008422 to - boundary);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008423 } else {
8424 WriteToFlat(second,
8425 sink + boundary - from,
8426 0,
8427 to - boundary);
8428 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008429 to = boundary;
8430 }
8431 source = first;
8432 }
8433 break;
8434 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008435 case kOneByteStringTag | kSlicedStringTag:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008436 case kTwoByteStringTag | kSlicedStringTag: {
8437 SlicedString* slice = SlicedString::cast(source);
8438 unsigned offset = slice->offset();
8439 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8440 return;
8441 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008442 }
8443 }
8444}
8445
8446
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008447
8448template <typename SourceChar>
8449static void CalculateLineEndsImpl(Isolate* isolate,
8450 List<int>* line_ends,
8451 Vector<const SourceChar> src,
8452 bool include_ending_line) {
8453 const int src_len = src.length();
8454 StringSearch<uint8_t, SourceChar> search(isolate, STATIC_CHAR_VECTOR("\n"));
8455
8456 // Find and record line ends.
8457 int position = 0;
8458 while (position != -1 && position < src_len) {
8459 position = search.Search(src, position);
8460 if (position != -1) {
8461 line_ends->Add(position);
8462 position++;
8463 } else if (include_ending_line) {
8464 // Even if the last line misses a line end, it is counted.
8465 line_ends->Add(src_len);
8466 return;
8467 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008468 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008469}
8470
8471
8472Handle<FixedArray> String::CalculateLineEnds(Handle<String> src,
8473 bool include_ending_line) {
8474 src = Flatten(src);
8475 // Rough estimate of line count based on a roughly estimated average
8476 // length of (unpacked) code.
8477 int line_count_estimate = src->length() >> 4;
8478 List<int> line_ends(line_count_estimate);
8479 Isolate* isolate = src->GetIsolate();
8480 { DisallowHeapAllocation no_allocation; // ensure vectors stay valid.
8481 // Dispatch on type of strings.
8482 String::FlatContent content = src->GetFlatContent();
8483 DCHECK(content.IsFlat());
8484 if (content.IsOneByte()) {
8485 CalculateLineEndsImpl(isolate,
8486 &line_ends,
8487 content.ToOneByteVector(),
8488 include_ending_line);
8489 } else {
8490 CalculateLineEndsImpl(isolate,
8491 &line_ends,
8492 content.ToUC16Vector(),
8493 include_ending_line);
8494 }
8495 }
8496 int line_count = line_ends.length();
8497 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count);
8498 for (int i = 0; i < line_count; i++) {
8499 array->set(i, Smi::FromInt(line_ends[i]));
8500 }
8501 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00008502}
8503
8504
8505// Compares the contents of two strings by reading and comparing
8506// int-sized blocks of characters.
8507template <typename Char>
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008508static inline bool CompareRawStringContents(const Char* const a,
8509 const Char* const b,
8510 int length) {
8511 return CompareChars(a, b, length) == 0;
8512}
8513
8514
8515template<typename Chars1, typename Chars2>
8516class RawStringComparator : public AllStatic {
8517 public:
8518 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
8519 DCHECK(sizeof(Chars1) != sizeof(Chars2));
8520 for (int i = 0; i < len; i++) {
8521 if (a[i] != b[i]) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008522 return false;
8523 }
8524 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008525 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008526 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008527};
Steve Blocka7e24c12009-10-30 11:49:00 +00008528
8529
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008530template<>
8531class RawStringComparator<uint16_t, uint16_t> {
8532 public:
8533 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
8534 return CompareRawStringContents(a, b, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00008535 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008536};
8537
8538
8539template<>
8540class RawStringComparator<uint8_t, uint8_t> {
8541 public:
8542 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
8543 return CompareRawStringContents(a, b, len);
8544 }
8545};
8546
8547
8548class StringComparator {
8549 class State {
8550 public:
8551 explicit inline State(ConsStringIteratorOp* op)
8552 : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
8553
8554 inline void Init(String* string) {
8555 ConsString* cons_string = String::VisitFlat(this, string);
8556 op_->Reset(cons_string);
8557 if (cons_string != NULL) {
8558 int offset;
8559 string = op_->Next(&offset);
8560 String::VisitFlat(this, string, offset);
8561 }
8562 }
8563
8564 inline void VisitOneByteString(const uint8_t* chars, int length) {
8565 is_one_byte_ = true;
8566 buffer8_ = chars;
8567 length_ = length;
8568 }
8569
8570 inline void VisitTwoByteString(const uint16_t* chars, int length) {
8571 is_one_byte_ = false;
8572 buffer16_ = chars;
8573 length_ = length;
8574 }
8575
8576 void Advance(int consumed) {
8577 DCHECK(consumed <= length_);
8578 // Still in buffer.
8579 if (length_ != consumed) {
8580 if (is_one_byte_) {
8581 buffer8_ += consumed;
8582 } else {
8583 buffer16_ += consumed;
8584 }
8585 length_ -= consumed;
8586 return;
8587 }
8588 // Advance state.
8589 int offset;
8590 String* next = op_->Next(&offset);
8591 DCHECK_EQ(0, offset);
8592 DCHECK(next != NULL);
8593 String::VisitFlat(this, next);
8594 }
8595
8596 ConsStringIteratorOp* const op_;
8597 bool is_one_byte_;
8598 int length_;
8599 union {
8600 const uint8_t* buffer8_;
8601 const uint16_t* buffer16_;
8602 };
8603
8604 private:
8605 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
8606 };
8607
8608 public:
8609 inline StringComparator(ConsStringIteratorOp* op_1,
8610 ConsStringIteratorOp* op_2)
8611 : state_1_(op_1),
8612 state_2_(op_2) {
8613 }
8614
8615 template<typename Chars1, typename Chars2>
8616 static inline bool Equals(State* state_1, State* state_2, int to_check) {
8617 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
8618 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
8619 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
8620 }
8621
8622 bool Equals(String* string_1, String* string_2) {
8623 int length = string_1->length();
8624 state_1_.Init(string_1);
8625 state_2_.Init(string_2);
8626 while (true) {
8627 int to_check = Min(state_1_.length_, state_2_.length_);
8628 DCHECK(to_check > 0 && to_check <= length);
8629 bool is_equal;
8630 if (state_1_.is_one_byte_) {
8631 if (state_2_.is_one_byte_) {
8632 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
8633 } else {
8634 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
8635 }
8636 } else {
8637 if (state_2_.is_one_byte_) {
8638 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
8639 } else {
8640 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
8641 }
8642 }
8643 // Looping done.
8644 if (!is_equal) return false;
8645 length -= to_check;
8646 // Exit condition. Strings are equal.
8647 if (length == 0) return true;
8648 state_1_.Advance(to_check);
8649 state_2_.Advance(to_check);
8650 }
8651 }
8652
8653 private:
8654 State state_1_;
8655 State state_2_;
8656 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
8657};
Steve Blocka7e24c12009-10-30 11:49:00 +00008658
8659
Steve Blocka7e24c12009-10-30 11:49:00 +00008660bool String::SlowEquals(String* other) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008661 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00008662 // Fast check: negative check with lengths.
8663 int len = length();
8664 if (len != other->length()) return false;
8665 if (len == 0) return true;
8666
8667 // Fast check: if hash code is computed for both strings
8668 // a fast negative check can be performed.
8669 if (HasHashCode() && other->HasHashCode()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008670#ifdef ENABLE_SLOW_DCHECKS
Ben Murdochc7cc0282012-03-05 14:35:55 +00008671 if (FLAG_enable_slow_asserts) {
8672 if (Hash() != other->Hash()) {
8673 bool found_difference = false;
8674 for (int i = 0; i < len; i++) {
8675 if (Get(i) != other->Get(i)) {
8676 found_difference = true;
8677 break;
8678 }
8679 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008680 DCHECK(found_difference);
Ben Murdochc7cc0282012-03-05 14:35:55 +00008681 }
8682 }
8683#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00008684 if (Hash() != other->Hash()) return false;
8685 }
8686
Leon Clarkef7060e22010-06-03 12:02:55 +01008687 // We know the strings are both non-empty. Compare the first chars
8688 // before we try to flatten the strings.
8689 if (this->Get(0) != other->Get(0)) return false;
8690
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008691 if (IsSeqOneByteString() && other->IsSeqOneByteString()) {
8692 const uint8_t* str1 = SeqOneByteString::cast(this)->GetChars();
8693 const uint8_t* str2 = SeqOneByteString::cast(other)->GetChars();
8694 return CompareRawStringContents(str1, str2, len);
Steve Blocka7e24c12009-10-30 11:49:00 +00008695 }
8696
Steve Block44f0eee2011-05-26 01:26:41 +01008697 Isolate* isolate = GetIsolate();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008698 StringComparator comparator(isolate->objects_string_compare_iterator_a(),
8699 isolate->objects_string_compare_iterator_b());
8700
8701 return comparator.Equals(this, other);
8702}
8703
8704
8705bool String::SlowEquals(Handle<String> one, Handle<String> two) {
8706 // Fast check: negative check with lengths.
8707 int one_length = one->length();
8708 if (one_length != two->length()) return false;
8709 if (one_length == 0) return true;
8710
8711 // Fast check: if hash code is computed for both strings
8712 // a fast negative check can be performed.
8713 if (one->HasHashCode() && two->HasHashCode()) {
8714#ifdef ENABLE_SLOW_DCHECKS
8715 if (FLAG_enable_slow_asserts) {
8716 if (one->Hash() != two->Hash()) {
8717 bool found_difference = false;
8718 for (int i = 0; i < one_length; i++) {
8719 if (one->Get(i) != two->Get(i)) {
8720 found_difference = true;
8721 break;
8722 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008723 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008724 DCHECK(found_difference);
Steve Blocka7e24c12009-10-30 11:49:00 +00008725 }
8726 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008727#endif
8728 if (one->Hash() != two->Hash()) return false;
8729 }
8730
8731 // We know the strings are both non-empty. Compare the first chars
8732 // before we try to flatten the strings.
8733 if (one->Get(0) != two->Get(0)) return false;
8734
8735 one = String::Flatten(one);
8736 two = String::Flatten(two);
8737
8738 DisallowHeapAllocation no_gc;
8739 String::FlatContent flat1 = one->GetFlatContent();
8740 String::FlatContent flat2 = two->GetFlatContent();
8741
8742 if (flat1.IsOneByte() && flat2.IsOneByte()) {
8743 return CompareRawStringContents(flat1.ToOneByteVector().start(),
8744 flat2.ToOneByteVector().start(),
8745 one_length);
Steve Blocka7e24c12009-10-30 11:49:00 +00008746 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008747 for (int i = 0; i < one_length; i++) {
8748 if (flat1.Get(i) != flat2.Get(i)) return false;
8749 }
8750 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008751 }
8752}
8753
8754
8755bool String::MarkAsUndetectable() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008756 if (StringShape(this).IsInternalized()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008757
8758 Map* map = this->map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008759 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01008760 if (map == heap->string_map()) {
8761 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008762 return true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008763 } else if (map == heap->one_byte_string_map()) {
8764 this->set_map(heap->undetectable_one_byte_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00008765 return true;
8766 }
8767 // Rest cannot be marked as undetectable
8768 return false;
8769}
8770
8771
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008772bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008773 int slen = length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008774 // Can't check exact length equality, but we can check bounds.
8775 int str_len = str.length();
8776 if (!allow_prefix_match &&
8777 (str_len < slen ||
8778 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
8779 return false;
8780 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008781 int i;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008782 unsigned remaining_in_str = static_cast<unsigned>(str_len);
8783 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
8784 for (i = 0; i < slen && remaining_in_str > 0; i++) {
8785 unsigned cursor = 0;
8786 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
8787 DCHECK(cursor > 0 && cursor <= remaining_in_str);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008788 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
8789 if (i > slen - 1) return false;
8790 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
8791 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
8792 } else {
8793 if (Get(i) != r) return false;
8794 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008795 utf8_data += cursor;
8796 remaining_in_str -= cursor;
Steve Blocka7e24c12009-10-30 11:49:00 +00008797 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008798 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008799}
8800
8801
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008802bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
Steve Block9fac8402011-05-12 15:51:54 +01008803 int slen = length();
8804 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008805 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008806 FlatContent content = GetFlatContent();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008807 if (content.IsOneByte()) {
8808 return CompareChars(content.ToOneByteVector().start(),
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008809 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008810 }
8811 for (int i = 0; i < slen; i++) {
8812 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01008813 }
8814 return true;
8815}
8816
8817
8818bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
8819 int slen = length();
8820 if (str.length() != slen) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008821 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008822 FlatContent content = GetFlatContent();
8823 if (content.IsTwoByte()) {
8824 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008825 }
Steve Block9fac8402011-05-12 15:51:54 +01008826 for (int i = 0; i < slen; i++) {
8827 if (Get(i) != str[i]) return false;
8828 }
8829 return true;
8830}
8831
8832
Steve Blocka7e24c12009-10-30 11:49:00 +00008833uint32_t String::ComputeAndSetHash() {
8834 // Should only be called if hash code has not yet been computed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008835 DCHECK(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00008836
8837 // Store the hash code in the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008838 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
Steve Blockd0582a62009-12-15 09:54:21 +00008839 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00008840
8841 // Check the hash code is there.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008842 DCHECK(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00008843 uint32_t result = field >> kHashShift;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008844 DCHECK(result != 0); // Ensure that the hash value of 0 is never computed.
Steve Blocka7e24c12009-10-30 11:49:00 +00008845 return result;
8846}
8847
8848
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008849bool String::ComputeArrayIndex(uint32_t* index) {
8850 int length = this->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008851 if (length == 0 || length > kMaxArrayIndexSize) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008852 ConsStringIteratorOp op;
8853 StringCharacterStream stream(this, &op);
8854 return StringToArrayIndex(&stream, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008855}
8856
8857
8858bool String::SlowAsArrayIndex(uint32_t* index) {
8859 if (length() <= kMaxCachedArrayIndexLength) {
8860 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00008861 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008862 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00008863 // Isolate the array index form the full hash field.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008864 *index = ArrayIndexValueBits::decode(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00008865 return true;
8866 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008867 return ComputeArrayIndex(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008868 }
8869}
8870
8871
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008872Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
8873 int new_size, old_size;
8874 int old_length = string->length();
8875 if (old_length <= new_length) return string;
8876
8877 if (string->IsSeqOneByteString()) {
8878 old_size = SeqOneByteString::SizeFor(old_length);
8879 new_size = SeqOneByteString::SizeFor(new_length);
8880 } else {
8881 DCHECK(string->IsSeqTwoByteString());
8882 old_size = SeqTwoByteString::SizeFor(old_length);
8883 new_size = SeqTwoByteString::SizeFor(new_length);
8884 }
8885
8886 int delta = old_size - new_size;
8887
8888 Address start_of_string = string->address();
8889 DCHECK_OBJECT_ALIGNED(start_of_string);
8890 DCHECK_OBJECT_ALIGNED(start_of_string + new_size);
8891
8892 Heap* heap = string->GetHeap();
8893 NewSpace* newspace = heap->new_space();
8894 if (newspace->Contains(start_of_string) &&
8895 newspace->top() == start_of_string + old_size) {
8896 // Last allocated object in new space. Simply lower allocation top.
8897 newspace->set_top(start_of_string + new_size);
8898 } else {
8899 // Sizes are pointer size aligned, so that we can use filler objects
8900 // that are a multiple of pointer size.
8901 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
8902 }
8903 heap->AdjustLiveBytes(start_of_string, -delta, Heap::FROM_MUTATOR);
8904
8905 // We are storing the new length using release store after creating a filler
8906 // for the left-over space to avoid races with the sweeper thread.
8907 string->synchronized_set_length(new_length);
8908
8909 if (new_length == 0) return heap->isolate()->factory()->empty_string();
8910 return string;
8911}
8912
8913
Iain Merrick9ac36c92010-09-13 15:29:50 +01008914uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008915 // For array indexes mix the length into the hash as an array index could
8916 // be zero.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008917 DCHECK(length > 0);
8918 DCHECK(length <= String::kMaxArrayIndexSize);
8919 DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008920 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01008921
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008922 value <<= String::ArrayIndexValueBits::kShift;
8923 value |= length << String::ArrayIndexLengthBits::kShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01008924
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008925 DCHECK((value & String::kIsNotArrayIndexMask) == 0);
8926 DCHECK((length > String::kMaxCachedArrayIndexLength) ||
Iain Merrick9ac36c92010-09-13 15:29:50 +01008927 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008928 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00008929}
8930
8931
8932uint32_t StringHasher::GetHashField() {
Steve Blockd0582a62009-12-15 09:54:21 +00008933 if (length_ <= String::kMaxHashCalcLength) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008934 if (is_array_index_) {
8935 return MakeArrayIndexHash(array_index_, length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008936 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008937 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
8938 String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00008939 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01008940 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00008941 }
8942}
8943
8944
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008945uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
8946 uint32_t seed,
8947 int* utf16_length_out) {
8948 int vector_length = chars.length();
8949 // Handle some edge cases
8950 if (vector_length <= 1) {
8951 DCHECK(vector_length == 0 ||
8952 static_cast<uint8_t>(chars.start()[0]) <=
8953 unibrow::Utf8::kMaxOneByteChar);
8954 *utf16_length_out = vector_length;
8955 return HashSequentialString(chars.start(), vector_length, seed);
Steve Blocka7e24c12009-10-30 11:49:00 +00008956 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008957 // Start with a fake length which won't affect computation.
8958 // It will be updated later.
8959 StringHasher hasher(String::kMaxArrayIndexSize, seed);
8960 unsigned remaining = static_cast<unsigned>(vector_length);
8961 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
8962 int utf16_length = 0;
8963 bool is_index = true;
8964 DCHECK(hasher.is_array_index_);
8965 while (remaining > 0) {
8966 unsigned consumed = 0;
8967 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
8968 DCHECK(consumed > 0 && consumed <= remaining);
8969 stream += consumed;
8970 remaining -= consumed;
8971 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
8972 utf16_length += is_two_characters ? 2 : 1;
8973 // No need to keep hashing. But we do need to calculate utf16_length.
8974 if (utf16_length > String::kMaxHashCalcLength) continue;
8975 if (is_two_characters) {
8976 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
8977 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
8978 hasher.AddCharacter(c1);
8979 hasher.AddCharacter(c2);
8980 if (is_index) is_index = hasher.UpdateIndex(c1);
8981 if (is_index) is_index = hasher.UpdateIndex(c2);
8982 } else {
8983 hasher.AddCharacter(c);
8984 if (is_index) is_index = hasher.UpdateIndex(c);
8985 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008986 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008987 *utf16_length_out = static_cast<int>(utf16_length);
8988 // Must set length here so that hash computation is correct.
8989 hasher.length_ = utf16_length;
Steve Blocka7e24c12009-10-30 11:49:00 +00008990 return hasher.GetHashField();
8991}
8992
8993
Steve Blocka7e24c12009-10-30 11:49:00 +00008994void String::PrintOn(FILE* file) {
8995 int length = this->length();
8996 for (int i = 0; i < length; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00008997 PrintF(file, "%c", Get(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008998 }
8999}
9000
9001
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009002int Map::Hash() {
9003 // For performance reasons we only hash the 3 most variable fields of a map:
9004 // constructor, prototype and bit_field2.
9005
9006 // Shift away the tag.
9007 int hash = (static_cast<uint32_t>(
9008 reinterpret_cast<uintptr_t>(constructor())) >> 2);
9009
9010 // XOR-ing the prototype and constructor directly yields too many zero bits
9011 // when the two pointers are close (which is fairly common).
9012 // To avoid this we shift the prototype 4 bits relatively to the constructor.
9013 hash ^= (static_cast<uint32_t>(
9014 reinterpret_cast<uintptr_t>(prototype())) << 2);
9015
9016 return hash ^ (hash >> 16) ^ bit_field2();
9017}
9018
9019
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009020static bool CheckEquivalent(Map* first, Map* second) {
9021 return
9022 first->constructor() == second->constructor() &&
9023 first->prototype() == second->prototype() &&
9024 first->instance_type() == second->instance_type() &&
9025 first->bit_field() == second->bit_field() &&
9026 first->bit_field2() == second->bit_field2() &&
9027 first->is_frozen() == second->is_frozen() &&
9028 first->has_instance_call_handler() == second->has_instance_call_handler();
9029}
9030
9031
9032bool Map::EquivalentToForTransition(Map* other) {
9033 return CheckEquivalent(this, other);
9034}
9035
9036
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009037bool Map::EquivalentToForNormalization(Map* other,
9038 PropertyNormalizationMode mode) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009039 int properties = mode == CLEAR_INOBJECT_PROPERTIES
9040 ? 0 : other->inobject_properties();
9041 return CheckEquivalent(this, other) && inobject_properties() == properties;
9042}
9043
9044
9045void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
9046 // Unfortunately the serializer relies on pointers within an object being
9047 // visited in-order, so we have to iterate both the code and heap pointers in
9048 // the small section before doing so in the extended section.
9049 for (int s = 0; s <= final_section(); ++s) {
9050 LayoutSection section = static_cast<LayoutSection>(s);
9051 ConstantPoolArray::Iterator code_iter(this, ConstantPoolArray::CODE_PTR,
9052 section);
9053 while (!code_iter.is_finished()) {
9054 v->VisitCodeEntry(reinterpret_cast<Address>(
9055 RawFieldOfElementAt(code_iter.next_index())));
9056 }
9057
9058 ConstantPoolArray::Iterator heap_iter(this, ConstantPoolArray::HEAP_PTR,
9059 section);
9060 while (!heap_iter.is_finished()) {
9061 v->VisitPointer(RawFieldOfElementAt(heap_iter.next_index()));
9062 }
9063 }
9064}
9065
9066
9067void ConstantPoolArray::ClearPtrEntries(Isolate* isolate) {
9068 Type type[] = { CODE_PTR, HEAP_PTR };
9069 Address default_value[] = {
9070 isolate->builtins()->builtin(Builtins::kIllegal)->entry(),
9071 reinterpret_cast<Address>(isolate->heap()->undefined_value()) };
9072
9073 for (int i = 0; i < 2; ++i) {
9074 for (int s = 0; s <= final_section(); ++s) {
9075 LayoutSection section = static_cast<LayoutSection>(s);
9076 if (number_of_entries(type[i], section) > 0) {
9077 int offset = OffsetOfElementAt(first_index(type[i], section));
9078 MemsetPointer(
9079 reinterpret_cast<Address*>(HeapObject::RawField(this, offset)),
9080 default_value[i],
9081 number_of_entries(type[i], section));
9082 }
9083 }
9084 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009085}
9086
9087
Steve Block791712a2010-08-27 10:21:07 +01009088void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
9089 // Iterate over all fields in the body but take care in dealing with
9090 // the code entry.
9091 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
9092 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
9093 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
9094}
9095
9096
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009097void JSFunction::MarkForOptimization() {
9098 DCHECK(!IsOptimized());
9099 DCHECK(shared()->allows_lazy_compilation() ||
Ben Murdochb8e0da22011-05-16 14:20:40 +01009100 code()->optimizable());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009101 DCHECK(!shared()->is_generator());
9102 set_code_no_write_barrier(
9103 GetIsolate()->builtins()->builtin(Builtins::kCompileOptimized));
9104 // No write barrier required, since the builtin is part of the root set.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009105}
9106
9107
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009108void JSFunction::MarkForConcurrentOptimization() {
9109 DCHECK(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
9110 DCHECK(!IsOptimized());
9111 DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
9112 DCHECK(!shared()->is_generator());
9113 DCHECK(GetIsolate()->concurrent_recompilation_enabled());
9114 if (FLAG_trace_concurrent_recompilation) {
9115 PrintF(" ** Marking ");
9116 ShortPrint();
9117 PrintF(" for concurrent recompilation.\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009118 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009119 set_code_no_write_barrier(
9120 GetIsolate()->builtins()->builtin(Builtins::kCompileOptimizedConcurrent));
9121 // No write barrier required, since the builtin is part of the root set.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009122}
9123
9124
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009125void JSFunction::MarkInOptimizationQueue() {
9126 // We can only arrive here via the concurrent-recompilation builtin. If
9127 // break points were set, the code would point to the lazy-compile builtin.
9128 DCHECK(!GetIsolate()->DebuggerHasBreakPoints());
9129 DCHECK(IsMarkedForConcurrentOptimization() && !IsOptimized());
9130 DCHECK(shared()->allows_lazy_compilation() || code()->optimizable());
9131 DCHECK(GetIsolate()->concurrent_recompilation_enabled());
9132 if (FLAG_trace_concurrent_recompilation) {
9133 PrintF(" ** Queueing ");
9134 ShortPrint();
9135 PrintF(" for concurrent recompilation.\n");
9136 }
9137 set_code_no_write_barrier(
9138 GetIsolate()->builtins()->builtin(Builtins::kInOptimizationQueue));
9139 // No write barrier required, since the builtin is part of the root set.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009140}
9141
9142
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009143Handle<JSFunction> JSFunction::CloneClosure(Handle<JSFunction> function) {
9144 Isolate* isolate = function->GetIsolate();
9145 Handle<Map> map(function->map());
9146 Handle<SharedFunctionInfo> shared(function->shared());
9147 Handle<Context> context(function->context());
9148 Handle<JSFunction> clone =
9149 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
9150
9151 if (shared->bound()) {
9152 clone->set_function_bindings(function->function_bindings());
9153 }
9154
9155 // In typical case, __proto__ of ``function`` is the default Function
9156 // prototype, which means that SetPrototype below is a no-op.
9157 // In rare cases when that is not true, we mutate the clone's __proto__.
9158 Handle<Object> original_prototype(map->prototype(), isolate);
9159 if (*original_prototype != clone->map()->prototype()) {
9160 JSObject::SetPrototype(clone, original_prototype, false).Assert();
9161 }
9162
9163 return clone;
9164}
9165
9166
9167void SharedFunctionInfo::AddToOptimizedCodeMap(
9168 Handle<SharedFunctionInfo> shared,
9169 Handle<Context> native_context,
9170 Handle<Code> code,
9171 Handle<FixedArray> literals,
9172 BailoutId osr_ast_id) {
9173 Isolate* isolate = shared->GetIsolate();
9174 DCHECK(code->kind() == Code::OPTIMIZED_FUNCTION);
9175 DCHECK(native_context->IsNativeContext());
9176 STATIC_ASSERT(kEntryLength == 4);
9177 Handle<FixedArray> new_code_map;
9178 Handle<Object> value(shared->optimized_code_map(), isolate);
9179 int old_length;
9180 if (value->IsSmi()) {
9181 // No optimized code map.
9182 DCHECK_EQ(0, Smi::cast(*value)->value());
9183 // Create 3 entries per context {context, code, literals}.
9184 new_code_map = isolate->factory()->NewFixedArray(kInitialLength);
9185 old_length = kEntriesStart;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009186 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009187 // Copy old map and append one new entry.
9188 Handle<FixedArray> old_code_map = Handle<FixedArray>::cast(value);
9189 DCHECK_EQ(-1, shared->SearchOptimizedCodeMap(*native_context, osr_ast_id));
9190 old_length = old_code_map->length();
9191 new_code_map = FixedArray::CopySize(
9192 old_code_map, old_length + kEntryLength);
9193 // Zap the old map for the sake of the heap verifier.
9194 if (Heap::ShouldZapGarbage()) {
9195 Object** data = old_code_map->data_start();
9196 MemsetPointer(data, isolate->heap()->the_hole_value(), old_length);
9197 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009198 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009199 new_code_map->set(old_length + kContextOffset, *native_context);
9200 new_code_map->set(old_length + kCachedCodeOffset, *code);
9201 new_code_map->set(old_length + kLiteralsOffset, *literals);
9202 new_code_map->set(old_length + kOsrAstIdOffset,
9203 Smi::FromInt(osr_ast_id.ToInt()));
9204
9205#ifdef DEBUG
9206 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
9207 DCHECK(new_code_map->get(i + kContextOffset)->IsNativeContext());
9208 DCHECK(new_code_map->get(i + kCachedCodeOffset)->IsCode());
9209 DCHECK(Code::cast(new_code_map->get(i + kCachedCodeOffset))->kind() ==
9210 Code::OPTIMIZED_FUNCTION);
9211 DCHECK(new_code_map->get(i + kLiteralsOffset)->IsFixedArray());
9212 DCHECK(new_code_map->get(i + kOsrAstIdOffset)->IsSmi());
9213 }
9214#endif
9215 shared->set_optimized_code_map(*new_code_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009216}
9217
9218
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009219FixedArray* SharedFunctionInfo::GetLiteralsFromOptimizedCodeMap(int index) {
9220 DCHECK(index > kEntriesStart);
9221 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9222 if (!bound()) {
9223 FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
9224 DCHECK_NE(NULL, cached_literals);
9225 return cached_literals;
9226 }
9227 return NULL;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009228}
9229
9230
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009231Code* SharedFunctionInfo::GetCodeFromOptimizedCodeMap(int index) {
9232 DCHECK(index > kEntriesStart);
9233 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9234 Code* code = Code::cast(code_map->get(index));
9235 DCHECK_NE(NULL, code);
9236 return code;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009237}
9238
9239
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009240void SharedFunctionInfo::ClearOptimizedCodeMap() {
9241 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9242
9243 // If the next map link slot is already used then the function was
9244 // enqueued with code flushing and we remove it now.
9245 if (!code_map->get(kNextMapIndex)->IsUndefined()) {
9246 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
9247 flusher->EvictOptimizedCodeMap(this);
9248 }
9249
9250 DCHECK(code_map->get(kNextMapIndex)->IsUndefined());
9251 set_optimized_code_map(Smi::FromInt(0));
9252}
9253
9254
9255void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
9256 const char* reason) {
9257 DisallowHeapAllocation no_gc;
9258 if (optimized_code_map()->IsSmi()) return;
9259
9260 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9261 int dst = kEntriesStart;
9262 int length = code_map->length();
9263 for (int src = kEntriesStart; src < length; src += kEntryLength) {
9264 DCHECK(code_map->get(src)->IsNativeContext());
9265 if (Code::cast(code_map->get(src + kCachedCodeOffset)) == optimized_code) {
9266 // Evict the src entry by not copying it to the dst entry.
9267 if (FLAG_trace_opt) {
9268 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
9269 ShortPrint();
9270 BailoutId osr(Smi::cast(code_map->get(src + kOsrAstIdOffset))->value());
9271 if (osr.IsNone()) {
9272 PrintF("]\n");
9273 } else {
9274 PrintF(" (osr ast id %d)]\n", osr.ToInt());
9275 }
9276 }
9277 } else {
9278 // Keep the src entry by copying it to the dst entry.
9279 if (dst != src) {
9280 code_map->set(dst + kContextOffset,
9281 code_map->get(src + kContextOffset));
9282 code_map->set(dst + kCachedCodeOffset,
9283 code_map->get(src + kCachedCodeOffset));
9284 code_map->set(dst + kLiteralsOffset,
9285 code_map->get(src + kLiteralsOffset));
9286 code_map->set(dst + kOsrAstIdOffset,
9287 code_map->get(src + kOsrAstIdOffset));
9288 }
9289 dst += kEntryLength;
9290 }
9291 }
9292 if (dst != length) {
9293 // Always trim even when array is cleared because of heap verifier.
9294 GetHeap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(code_map, length - dst);
9295 if (code_map->length() == kEntriesStart) ClearOptimizedCodeMap();
9296 }
9297}
9298
9299
9300void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
9301 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9302 DCHECK(shrink_by % kEntryLength == 0);
9303 DCHECK(shrink_by <= code_map->length() - kEntriesStart);
9304 // Always trim even when array is cleared because of heap verifier.
9305 GetHeap()->RightTrimFixedArray<Heap::FROM_GC>(code_map, shrink_by);
9306 if (code_map->length() == kEntriesStart) {
9307 ClearOptimizedCodeMap();
9308 }
9309}
9310
9311
9312void JSObject::OptimizeAsPrototype(Handle<JSObject> object,
9313 PrototypeOptimizationMode mode) {
9314 if (object->IsGlobalObject()) return;
9315 if (object->IsJSGlobalProxy()) return;
9316 if (mode == FAST_PROTOTYPE && !object->map()->is_prototype_map()) {
9317 // First normalize to ensure all JSFunctions are CONSTANT.
9318 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, 0);
9319 }
9320 if (!object->HasFastProperties()) {
9321 JSObject::MigrateSlowToFast(object, 0);
9322 }
9323 if (mode == FAST_PROTOTYPE && object->HasFastProperties() &&
9324 !object->map()->is_prototype_map()) {
9325 Handle<Map> new_map = Map::Copy(handle(object->map()));
9326 JSObject::MigrateToMap(object, new_map);
9327 object->map()->set_is_prototype_map(true);
9328 }
9329}
9330
9331
9332void JSObject::ReoptimizeIfPrototype(Handle<JSObject> object) {
9333 if (!object->map()->is_prototype_map()) return;
9334 OptimizeAsPrototype(object, FAST_PROTOTYPE);
9335}
9336
9337
9338Handle<Object> CacheInitialJSArrayMaps(
9339 Handle<Context> native_context, Handle<Map> initial_map) {
9340 // Replace all of the cached initial array maps in the native context with
9341 // the appropriate transitioned elements kind maps.
9342 Factory* factory = native_context->GetIsolate()->factory();
9343 Handle<FixedArray> maps = factory->NewFixedArrayWithHoles(
9344 kElementsKindCount, TENURED);
9345
9346 Handle<Map> current_map = initial_map;
9347 ElementsKind kind = current_map->elements_kind();
9348 DCHECK(kind == GetInitialFastElementsKind());
9349 maps->set(kind, *current_map);
9350 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
9351 i < kFastElementsKindCount; ++i) {
9352 Handle<Map> new_map;
9353 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
9354 if (current_map->HasElementsTransition()) {
9355 new_map = handle(current_map->elements_transition_map());
9356 DCHECK(new_map->elements_kind() == next_kind);
9357 } else {
9358 new_map = Map::CopyAsElementsKind(
9359 current_map, next_kind, INSERT_TRANSITION);
9360 }
9361 maps->set(next_kind, *new_map);
9362 current_map = new_map;
9363 }
9364 native_context->set_js_array_maps(*maps);
9365 return initial_map;
9366}
9367
9368
9369void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
9370 Handle<Object> value) {
9371 Isolate* isolate = function->GetIsolate();
9372
9373 DCHECK(value->IsJSReceiver());
9374
9375 // Now some logic for the maps of the objects that are created by using this
9376 // function as a constructor.
9377 if (function->has_initial_map()) {
9378 // If the function has allocated the initial map replace it with a
9379 // copy containing the new prototype. Also complete any in-object
9380 // slack tracking that is in progress at this point because it is
9381 // still tracking the old copy.
9382 if (function->IsInobjectSlackTrackingInProgress()) {
9383 function->CompleteInobjectSlackTracking();
9384 }
9385
9386 Handle<Map> initial_map(function->initial_map(), isolate);
9387
9388 if (!initial_map->GetIsolate()->bootstrapper()->IsActive() &&
9389 initial_map->instance_type() == JS_OBJECT_TYPE) {
9390 // Put the value in the initial map field until an initial map is needed.
9391 // At that point, a new initial map is created and the prototype is put
9392 // into the initial map where it belongs.
9393 function->set_prototype_or_initial_map(*value);
9394 } else {
9395 Handle<Map> new_map = Map::Copy(initial_map);
9396 JSFunction::SetInitialMap(function, new_map, value);
9397
9398 // If the function is used as the global Array function, cache the
9399 // initial map (and transitioned versions) in the native context.
9400 Context* native_context = function->context()->native_context();
9401 Object* array_function =
9402 native_context->get(Context::ARRAY_FUNCTION_INDEX);
9403 if (array_function->IsJSFunction() &&
9404 *function == JSFunction::cast(array_function)) {
9405 CacheInitialJSArrayMaps(handle(native_context, isolate), new_map);
9406 }
9407 }
9408
9409 // Deoptimize all code that embeds the previous initial map.
9410 initial_map->dependent_code()->DeoptimizeDependentCodeGroup(
9411 isolate, DependentCode::kInitialMapChangedGroup);
Steve Blocka7e24c12009-10-30 11:49:00 +00009412 } else {
9413 // Put the value in the initial map field until an initial map is
9414 // needed. At that point, a new initial map is created and the
9415 // prototype is put into the initial map where it belongs.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009416 function->set_prototype_or_initial_map(*value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009417 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009418 isolate->heap()->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00009419}
9420
9421
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009422void JSFunction::SetPrototype(Handle<JSFunction> function,
9423 Handle<Object> value) {
9424 DCHECK(function->should_have_prototype());
9425 Handle<Object> construct_prototype = value;
Steve Blocka7e24c12009-10-30 11:49:00 +00009426
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009427 // If the value is not a JSReceiver, store the value in the map's
Steve Blocka7e24c12009-10-30 11:49:00 +00009428 // constructor field so it can be accessed. Also, set the prototype
9429 // used for constructing objects to the original object prototype.
9430 // See ECMA-262 13.2.2.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009431 if (!value->IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009432 // Copy the map so this does not affect unrelated functions.
9433 // Remove map transitions because they point to maps with a
9434 // different prototype.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009435 Handle<Map> new_map = Map::Copy(handle(function->map()));
9436
9437 JSObject::MigrateToMap(function, new_map);
9438 new_map->set_constructor(*value);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009439 new_map->set_non_instance_prototype(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009440 Isolate* isolate = new_map->GetIsolate();
9441 construct_prototype = handle(
9442 isolate->context()->native_context()->initial_object_prototype(),
9443 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009444 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009445 function->map()->set_non_instance_prototype(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00009446 }
9447
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009448 return SetInstancePrototype(function, construct_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00009449}
9450
9451
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009452bool JSFunction::RemovePrototype() {
9453 Context* native_context = context()->native_context();
9454 Map* no_prototype_map = shared()->strict_mode() == SLOPPY
9455 ? native_context->sloppy_function_without_prototype_map()
9456 : native_context->strict_function_without_prototype_map();
Steve Block44f0eee2011-05-26 01:26:41 +01009457
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009458 if (map() == no_prototype_map) return true;
9459
9460#ifdef DEBUG
9461 if (map() != (shared()->strict_mode() == SLOPPY
9462 ? native_context->sloppy_function_map()
9463 : native_context->strict_function_map())) {
9464 return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009465 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009466#endif
Steve Block44f0eee2011-05-26 01:26:41 +01009467
9468 set_map(no_prototype_map);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009469 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009470 return true;
Steve Block6ded16b2010-05-10 14:33:55 +01009471}
9472
9473
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009474void JSFunction::SetInitialMap(Handle<JSFunction> function, Handle<Map> map,
9475 Handle<Object> prototype) {
9476 if (prototype->IsJSObject()) {
9477 Handle<JSObject> js_proto = Handle<JSObject>::cast(prototype);
9478 JSObject::OptimizeAsPrototype(js_proto, FAST_PROTOTYPE);
9479 }
9480 map->set_prototype(*prototype);
9481 function->set_prototype_or_initial_map(*map);
9482 map->set_constructor(*function);
9483}
9484
9485
9486void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
9487 if (function->has_initial_map()) return;
9488 Isolate* isolate = function->GetIsolate();
9489
9490 // First create a new map with the size and number of in-object properties
9491 // suggested by the function.
9492 InstanceType instance_type;
9493 int instance_size;
9494 int in_object_properties;
9495 if (function->shared()->is_generator()) {
9496 instance_type = JS_GENERATOR_OBJECT_TYPE;
9497 instance_size = JSGeneratorObject::kSize;
9498 in_object_properties = 0;
9499 } else {
9500 instance_type = JS_OBJECT_TYPE;
9501 instance_size = function->shared()->CalculateInstanceSize();
9502 in_object_properties = function->shared()->CalculateInObjectProperties();
9503 }
9504 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
9505
9506 // Fetch or allocate prototype.
9507 Handle<Object> prototype;
9508 if (function->has_instance_prototype()) {
9509 prototype = handle(function->instance_prototype(), isolate);
9510 } else {
9511 prototype = isolate->factory()->NewFunctionPrototype(function);
9512 }
9513 map->set_inobject_properties(in_object_properties);
9514 map->set_unused_property_fields(in_object_properties);
9515 DCHECK(map->has_fast_object_elements());
9516
9517 // Finally link initial map and constructor function.
9518 JSFunction::SetInitialMap(function, map, Handle<JSReceiver>::cast(prototype));
9519
9520 if (!function->shared()->is_generator()) {
9521 function->StartInobjectSlackTracking();
9522 }
9523}
9524
9525
9526void JSFunction::SetInstanceClassName(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009527 shared()->set_instance_class_name(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00009528}
9529
9530
Ben Murdochb0fe1622011-05-05 13:52:32 +01009531void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +00009532 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009533 PrintF(out, "%s", name.get());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009534}
9535
9536
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009537Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
9538 return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00009539}
9540
9541
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009542// The filter is a pattern that matches function names in this way:
9543// "*" all; the default
9544// "-" all but the top-level function
9545// "-name" all but the function "name"
9546// "" only the top-level function
9547// "name" only the function "name"
9548// "name*" only functions starting with "name"
9549// "~" none; the tilde is not an identifier
9550bool JSFunction::PassesFilter(const char* raw_filter) {
9551 if (*raw_filter == '*') return true;
9552 String* name = shared()->DebugName();
9553 Vector<const char> filter = CStrVector(raw_filter);
9554 if (filter.length() == 0) return name->length() == 0;
9555 if (filter[0] == '-') {
9556 // Negative filter.
9557 if (filter.length() == 1) {
9558 return (name->length() != 0);
9559 } else if (name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
9560 return false;
9561 }
9562 if (filter[filter.length() - 1] == '*' &&
9563 name->IsUtf8EqualTo(filter.SubVector(1, filter.length() - 1), true)) {
9564 return false;
9565 }
9566 return true;
9567
9568 } else if (name->IsUtf8EqualTo(filter)) {
9569 return true;
John Reck59135872010-11-02 12:39:01 -07009570 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009571 if (filter[filter.length() - 1] == '*' &&
9572 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
9573 return true;
9574 }
9575 return false;
9576}
9577
9578
9579void Oddball::Initialize(Isolate* isolate,
9580 Handle<Oddball> oddball,
9581 const char* to_string,
9582 Handle<Object> to_number,
9583 byte kind) {
9584 Handle<String> internalized_to_string =
9585 isolate->factory()->InternalizeUtf8String(to_string);
9586 oddball->set_to_string(*internalized_to_string);
9587 oddball->set_to_number(*to_number);
9588 oddball->set_kind(kind);
9589}
9590
9591
9592void Script::InitLineEnds(Handle<Script> script) {
9593 if (!script->line_ends()->IsUndefined()) return;
9594
9595 Isolate* isolate = script->GetIsolate();
9596
9597 if (!script->source()->IsString()) {
9598 DCHECK(script->source()->IsUndefined());
9599 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0);
9600 script->set_line_ends(*empty);
9601 DCHECK(script->line_ends()->IsFixedArray());
9602 return;
9603 }
9604
9605 Handle<String> src(String::cast(script->source()), isolate);
9606
9607 Handle<FixedArray> array = String::CalculateLineEnds(src, true);
9608
9609 if (*array != isolate->heap()->empty_fixed_array()) {
9610 array->set_map(isolate->heap()->fixed_cow_array_map());
9611 }
9612
9613 script->set_line_ends(*array);
9614 DCHECK(script->line_ends()->IsFixedArray());
9615}
9616
9617
9618int Script::GetColumnNumber(Handle<Script> script, int code_pos) {
9619 int line_number = GetLineNumber(script, code_pos);
9620 if (line_number == -1) return -1;
9621
9622 DisallowHeapAllocation no_allocation;
9623 FixedArray* line_ends_array = FixedArray::cast(script->line_ends());
9624 line_number = line_number - script->line_offset()->value();
9625 if (line_number == 0) return code_pos + script->column_offset()->value();
9626 int prev_line_end_pos =
9627 Smi::cast(line_ends_array->get(line_number - 1))->value();
9628 return code_pos - (prev_line_end_pos + 1);
9629}
9630
9631
9632int Script::GetLineNumberWithArray(int code_pos) {
9633 DisallowHeapAllocation no_allocation;
9634 DCHECK(line_ends()->IsFixedArray());
9635 FixedArray* line_ends_array = FixedArray::cast(line_ends());
9636 int line_ends_len = line_ends_array->length();
9637 if (line_ends_len == 0) return -1;
9638
9639 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) {
9640 return line_offset()->value();
9641 }
9642
9643 int left = 0;
9644 int right = line_ends_len;
9645 while (int half = (right - left) / 2) {
9646 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) {
9647 right -= half;
9648 } else {
9649 left += half;
9650 }
9651 }
9652 return right + line_offset()->value();
9653}
9654
9655
9656int Script::GetLineNumber(Handle<Script> script, int code_pos) {
9657 InitLineEnds(script);
9658 return script->GetLineNumberWithArray(code_pos);
9659}
9660
9661
9662int Script::GetLineNumber(int code_pos) {
9663 DisallowHeapAllocation no_allocation;
9664 if (!line_ends()->IsUndefined()) return GetLineNumberWithArray(code_pos);
9665
9666 // Slow mode: we do not have line_ends. We have to iterate through source.
9667 if (!source()->IsString()) return -1;
9668
9669 String* source_string = String::cast(source());
9670 int line = 0;
9671 int len = source_string->length();
9672 for (int pos = 0; pos < len; pos++) {
9673 if (pos == code_pos) break;
9674 if (source_string->Get(pos) == '\n') line++;
9675 }
9676 return line;
9677}
9678
9679
9680Handle<Object> Script::GetNameOrSourceURL(Handle<Script> script) {
9681 Isolate* isolate = script->GetIsolate();
9682 Handle<String> name_or_source_url_key =
9683 isolate->factory()->InternalizeOneByteString(
9684 STATIC_CHAR_VECTOR("nameOrSourceURL"));
9685 Handle<JSObject> script_wrapper = Script::GetWrapper(script);
9686 Handle<Object> property = Object::GetProperty(
9687 script_wrapper, name_or_source_url_key).ToHandleChecked();
9688 DCHECK(property->IsJSFunction());
9689 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
9690 Handle<Object> result;
9691 // Do not check against pending exception, since this function may be called
9692 // when an exception has already been pending.
9693 if (!Execution::TryCall(method, script_wrapper, 0, NULL).ToHandle(&result)) {
9694 return isolate->factory()->undefined_value();
9695 }
9696 return result;
9697}
9698
9699
9700// Wrappers for scripts are kept alive and cached in weak global
9701// handles referred from foreign objects held by the scripts as long as
9702// they are used. When they are not used anymore, the garbage
9703// collector will call the weak callback on the global handle
9704// associated with the wrapper and get rid of both the wrapper and the
9705// handle.
9706static void ClearWrapperCacheWeakCallback(
9707 const v8::WeakCallbackData<v8::Value, void>& data) {
9708 Object** location = reinterpret_cast<Object**>(data.GetParameter());
9709 JSValue* wrapper = JSValue::cast(*location);
9710 Script::cast(wrapper->value())->ClearWrapperCache();
9711}
9712
9713
9714void Script::ClearWrapperCache() {
9715 Foreign* foreign = wrapper();
9716 Object** location = reinterpret_cast<Object**>(foreign->foreign_address());
9717 DCHECK_EQ(foreign->foreign_address(), reinterpret_cast<Address>(location));
9718 foreign->set_foreign_address(0);
9719 GlobalHandles::Destroy(location);
9720 GetIsolate()->counters()->script_wrappers()->Decrement();
9721}
9722
9723
9724Handle<JSObject> Script::GetWrapper(Handle<Script> script) {
9725 if (script->wrapper()->foreign_address() != NULL) {
9726 // Return a handle for the existing script wrapper from the cache.
9727 return Handle<JSValue>(
9728 *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address()));
9729 }
9730 Isolate* isolate = script->GetIsolate();
9731 // Construct a new script wrapper.
9732 isolate->counters()->script_wrappers()->Increment();
9733 Handle<JSFunction> constructor = isolate->script_function();
9734 Handle<JSValue> result =
9735 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor));
9736
9737 result->set_value(*script);
9738
9739 // Create a new weak global handle and use it to cache the wrapper
9740 // for future use. The cache will automatically be cleared by the
9741 // garbage collector when it is not used anymore.
9742 Handle<Object> handle = isolate->global_handles()->Create(*result);
9743 GlobalHandles::MakeWeak(handle.location(),
9744 reinterpret_cast<void*>(handle.location()),
9745 &ClearWrapperCacheWeakCallback);
9746 script->wrapper()->set_foreign_address(
9747 reinterpret_cast<Address>(handle.location()));
9748 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00009749}
9750
9751
Ben Murdochf87a2032010-10-22 12:50:53 +01009752String* SharedFunctionInfo::DebugName() {
9753 Object* n = name();
9754 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
9755 return String::cast(n);
9756}
9757
9758
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009759bool SharedFunctionInfo::HasSourceCode() const {
Steve Blocka7e24c12009-10-30 11:49:00 +00009760 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01009761 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00009762}
9763
9764
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009765Handle<Object> SharedFunctionInfo::GetSourceCode() {
9766 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
9767 Handle<String> source(String::cast(Script::cast(script())->source()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009768 return GetIsolate()->factory()->NewSubString(
9769 source, start_position(), end_position());
9770}
9771
9772
9773bool SharedFunctionInfo::IsInlineable() {
9774 // Check that the function has a script associated with it.
9775 if (!script()->IsScript()) return false;
9776 if (optimization_disabled()) return false;
9777 // If we never ran this (unlikely) then lets try to optimize it.
9778 if (code()->kind() != Code::FUNCTION) return true;
9779 return code()->optimizable();
Steve Blocka7e24c12009-10-30 11:49:00 +00009780}
9781
9782
Ben Murdochb0fe1622011-05-05 13:52:32 +01009783int SharedFunctionInfo::SourceSize() {
9784 return end_position() - start_position();
9785}
9786
9787
Steve Blocka7e24c12009-10-30 11:49:00 +00009788int SharedFunctionInfo::CalculateInstanceSize() {
9789 int instance_size =
9790 JSObject::kHeaderSize +
9791 expected_nof_properties() * kPointerSize;
9792 if (instance_size > JSObject::kMaxInstanceSize) {
9793 instance_size = JSObject::kMaxInstanceSize;
9794 }
9795 return instance_size;
9796}
9797
9798
9799int SharedFunctionInfo::CalculateInObjectProperties() {
9800 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
9801}
9802
9803
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009804// Output the source code without any allocation in the heap.
9805OStream& operator<<(OStream& os, const SourceCodeOf& v) {
9806 const SharedFunctionInfo* s = v.value;
Steve Blocka7e24c12009-10-30 11:49:00 +00009807 // For some native functions there is no source.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009808 if (!s->HasSourceCode()) return os << "<No Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +00009809
Steve Blockd0582a62009-12-15 09:54:21 +00009810 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00009811 // Don't use String::cast because we don't want more assertion errors while
9812 // we are already creating a stack dump.
9813 String* script_source =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009814 reinterpret_cast<String*>(Script::cast(s->script())->source());
Steve Blocka7e24c12009-10-30 11:49:00 +00009815
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009816 if (!script_source->LooksValid()) return os << "<Invalid Source>";
Steve Blocka7e24c12009-10-30 11:49:00 +00009817
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009818 if (!s->is_toplevel()) {
9819 os << "function ";
9820 Object* name = s->name();
Steve Blocka7e24c12009-10-30 11:49:00 +00009821 if (name->IsString() && String::cast(name)->length() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009822 String::cast(name)->PrintUC16(os);
Steve Blocka7e24c12009-10-30 11:49:00 +00009823 }
9824 }
9825
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009826 int len = s->end_position() - s->start_position();
9827 if (len <= v.max_length || v.max_length < 0) {
9828 script_source->PrintUC16(os, s->start_position(), s->end_position());
9829 return os;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009830 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009831 script_source->PrintUC16(os, s->start_position(),
9832 s->start_position() + v.max_length);
9833 return os << "...\n";
Steve Blocka7e24c12009-10-30 11:49:00 +00009834 }
9835}
9836
9837
Ben Murdochb0fe1622011-05-05 13:52:32 +01009838static bool IsCodeEquivalent(Code* code, Code* recompiled) {
9839 if (code->instruction_size() != recompiled->instruction_size()) return false;
9840 ByteArray* code_relocation = code->relocation_info();
9841 ByteArray* recompiled_relocation = recompiled->relocation_info();
9842 int length = code_relocation->length();
9843 if (length != recompiled_relocation->length()) return false;
9844 int compare = memcmp(code_relocation->GetDataStartAddress(),
9845 recompiled_relocation->GetDataStartAddress(),
9846 length);
9847 return compare == 0;
9848}
9849
9850
9851void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009852 DCHECK(!has_deoptimization_support());
9853 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +01009854 Code* code = this->code();
9855 if (IsCodeEquivalent(code, recompiled)) {
9856 // Copy the deoptimization data from the recompiled code.
9857 code->set_deoptimization_data(recompiled->deoptimization_data());
9858 code->set_has_deoptimization_support(true);
9859 } else {
9860 // TODO(3025757): In case the recompiled isn't equivalent to the
9861 // old code, we have to replace it. We should try to avoid this
9862 // altogether because it flushes valuable type feedback by
9863 // effectively resetting all IC state.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009864 ReplaceCode(recompiled);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009865 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009866 DCHECK(has_deoptimization_support());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009867}
9868
9869
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009870void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
Ben Murdoch257744e2011-11-30 15:57:28 +00009871 // Disable optimization for the shared function info and mark the
9872 // code as non-optimizable. The marker on the shared function info
9873 // is there because we flush non-optimized code thereby loosing the
9874 // non-optimizable information for the code. When the code is
9875 // regenerated and set on the shared function info it is marked as
9876 // non-optimizable if optimization is disabled for the shared
9877 // function info.
9878 set_optimization_disabled(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009879 set_bailout_reason(reason);
Ben Murdoch257744e2011-11-30 15:57:28 +00009880 // Code should be the lazy compilation stub or else unoptimized. If the
9881 // latter, disable optimization for the code too.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009882 DCHECK(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
Ben Murdoch257744e2011-11-30 15:57:28 +00009883 if (code()->kind() == Code::FUNCTION) {
9884 code()->set_optimizable(false);
9885 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009886 PROFILE(GetIsolate(), CodeDisableOptEvent(code(), this));
Ben Murdoch257744e2011-11-30 15:57:28 +00009887 if (FLAG_trace_opt) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009888 PrintF("[disabled optimization for ");
9889 ShortPrint();
9890 PrintF(", reason: %s]\n", GetBailoutReason(reason));
Ben Murdoch257744e2011-11-30 15:57:28 +00009891 }
9892}
9893
9894
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009895bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
9896 DCHECK(!id.IsNone());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009897 Code* unoptimized = code();
9898 DeoptimizationOutputData* data =
9899 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
9900 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
9901 USE(ignore);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009902 return true; // Return true if there was no DCHECK.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009903}
9904
9905
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009906void JSFunction::StartInobjectSlackTracking() {
9907 DCHECK(has_initial_map() && !IsInobjectSlackTrackingInProgress());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009908
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009909 if (!FLAG_clever_optimizations) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009910 Map* map = initial_map();
Ben Murdoch3ef787d2012-04-12 10:51:47 +01009911
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009912 // Only initiate the tracking the first time.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009913 if (map->done_inobject_slack_tracking()) return;
9914 map->set_done_inobject_slack_tracking(true);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009915
9916 // No tracking during the snapshot construction phase.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009917 Isolate* isolate = GetIsolate();
9918 if (isolate->serializer_enabled()) return;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009919
9920 if (map->unused_property_fields() == 0) return;
9921
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009922 map->set_construction_count(kGenerousAllocationCount);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009923}
9924
9925
Ben Murdoch8f9999f2012-04-23 10:39:17 +01009926void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
9927 code()->ClearInlineCaches();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009928 // If we clear ICs, we need to clear the type feedback vector too, since
9929 // CallICs are synced with a feedback vector slot.
9930 ClearTypeFeedbackInfo();
Ben Murdoch8f9999f2012-04-23 10:39:17 +01009931 set_ic_age(new_ic_age);
9932 if (code()->kind() == Code::FUNCTION) {
9933 code()->set_profiler_ticks(0);
9934 if (optimization_disabled() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009935 opt_count() >= FLAG_max_opt_count) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +01009936 // Re-enable optimizations if they were disabled due to opt_count limit.
9937 set_optimization_disabled(false);
9938 code()->set_optimizable(true);
9939 }
9940 set_opt_count(0);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009941 set_deopt_count(0);
Ben Murdoch8f9999f2012-04-23 10:39:17 +01009942 }
9943}
9944
9945
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009946static void GetMinInobjectSlack(Map* map, void* data) {
9947 int slack = map->unused_property_fields();
9948 if (*reinterpret_cast<int*>(data) > slack) {
9949 *reinterpret_cast<int*>(data) = slack;
9950 }
9951}
9952
9953
9954static void ShrinkInstanceSize(Map* map, void* data) {
9955 int slack = *reinterpret_cast<int*>(data);
9956 map->set_inobject_properties(map->inobject_properties() - slack);
9957 map->set_unused_property_fields(map->unused_property_fields() - slack);
9958 map->set_instance_size(map->instance_size() - slack * kPointerSize);
9959
9960 // Visitor id might depend on the instance size, recalculate it.
9961 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
9962}
9963
9964
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009965void JSFunction::CompleteInobjectSlackTracking() {
9966 DCHECK(has_initial_map());
9967 Map* map = initial_map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009968
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009969 DCHECK(map->done_inobject_slack_tracking());
9970 map->set_construction_count(kNoSlackTracking);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009971
9972 int slack = map->unused_property_fields();
9973 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
9974 if (slack != 0) {
9975 // Resize the initial map and all maps in its transition tree.
9976 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01009977 }
9978}
9979
9980
Ben Murdochb8a8cc12014-11-26 15:28:44 +00009981int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context,
9982 BailoutId osr_ast_id) {
9983 DisallowHeapAllocation no_gc;
9984 DCHECK(native_context->IsNativeContext());
9985 if (!FLAG_cache_optimized_code) return -1;
9986 Object* value = optimized_code_map();
9987 if (!value->IsSmi()) {
9988 FixedArray* optimized_code_map = FixedArray::cast(value);
9989 int length = optimized_code_map->length();
9990 Smi* osr_ast_id_smi = Smi::FromInt(osr_ast_id.ToInt());
9991 for (int i = kEntriesStart; i < length; i += kEntryLength) {
9992 if (optimized_code_map->get(i + kContextOffset) == native_context &&
9993 optimized_code_map->get(i + kOsrAstIdOffset) == osr_ast_id_smi) {
9994 return i + kCachedCodeOffset;
9995 }
9996 }
9997 if (FLAG_trace_opt) {
9998 PrintF("[didn't find optimized code in optimized code map for ");
9999 ShortPrint();
10000 PrintF("]\n");
10001 }
10002 }
10003 return -1;
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010004}
10005
10006
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010007#define DECLARE_TAG(ignore1, name, ignore2) name,
10008const char* const VisitorSynchronization::kTags[
10009 VisitorSynchronization::kNumberOfSyncTags] = {
10010 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10011};
10012#undef DECLARE_TAG
10013
10014
10015#define DECLARE_TAG(ignore1, ignore2, name) name,
10016const char* const VisitorSynchronization::kTagNames[
10017 VisitorSynchronization::kNumberOfSyncTags] = {
10018 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10019};
10020#undef DECLARE_TAG
10021
10022
Steve Blocka7e24c12009-10-30 11:49:00 +000010023void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010024 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010025 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
10026 Object* old_target = target;
10027 VisitPointer(&target);
10028 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
10029}
10030
10031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010032void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
10033 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
10034 Object* stub = rinfo->code_age_stub();
10035 if (stub) {
10036 VisitPointer(&stub);
10037 }
10038}
10039
10040
Steve Block791712a2010-08-27 10:21:07 +010010041void ObjectVisitor::VisitCodeEntry(Address entry_address) {
10042 Object* code = Code::GetObjectFromEntryAddress(entry_address);
10043 Object* old_code = code;
10044 VisitPointer(&code);
10045 if (code != old_code) {
10046 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
10047 }
10048}
10049
10050
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010051void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
10052 DCHECK(rinfo->rmode() == RelocInfo::CELL);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010053 Object* cell = rinfo->target_cell();
10054 Object* old_cell = cell;
10055 VisitPointer(&cell);
10056 if (cell != old_cell) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010057 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
Ben Murdochb0fe1622011-05-05 13:52:32 +010010058 }
10059}
10060
10061
Steve Blocka7e24c12009-10-30 11:49:00 +000010062void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010063 DCHECK((RelocInfo::IsJSReturn(rinfo->rmode()) &&
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010010064 rinfo->IsPatchedReturnSequence()) ||
10065 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
10066 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010067 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
10068 Object* old_target = target;
10069 VisitPointer(&target);
10070 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
10071}
10072
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010073
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010074void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010075 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
10076 Object* p = rinfo->target_object();
10077 VisitPointer(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010078}
10079
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010080
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010081void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010082 Address p = rinfo->target_reference();
10083 VisitExternalReference(&p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010084}
10085
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010086
Ben Murdochb0fe1622011-05-05 13:52:32 +010010087void Code::InvalidateRelocation() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010088 InvalidateEmbeddedObjects();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010089 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010090}
10091
10092
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010093void Code::InvalidateEmbeddedObjects() {
10094 Object* undefined = GetHeap()->undefined_value();
10095 Cell* undefined_cell = GetHeap()->undefined_cell();
10096 int mode_mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
10097 RelocInfo::ModeMask(RelocInfo::CELL);
10098 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10099 RelocInfo::Mode mode = it.rinfo()->rmode();
10100 if (mode == RelocInfo::EMBEDDED_OBJECT) {
10101 it.rinfo()->set_target_object(undefined, SKIP_WRITE_BARRIER);
10102 } else if (mode == RelocInfo::CELL) {
10103 it.rinfo()->set_target_cell(undefined_cell, SKIP_WRITE_BARRIER);
10104 }
10105 }
10106}
10107
10108
Steve Blockd0582a62009-12-15 09:54:21 +000010109void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010110 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010111 it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010112 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010113 CpuFeatures::FlushICache(instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000010114}
10115
10116
10117void Code::CopyFrom(const CodeDesc& desc) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010118 DCHECK(Marking::Color(this) == Marking::WHITE_OBJECT);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010119
Steve Blocka7e24c12009-10-30 11:49:00 +000010120 // copy code
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010121 CopyBytes(instruction_start(), desc.buffer,
10122 static_cast<size_t>(desc.instr_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000010123
Steve Blocka7e24c12009-10-30 11:49:00 +000010124 // copy reloc info
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010125 CopyBytes(relocation_start(),
10126 desc.buffer + desc.buffer_size - desc.reloc_size,
10127 static_cast<size_t>(desc.reloc_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000010128
10129 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +000010130 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +000010131 int mode_mask = RelocInfo::kCodeTargetMask |
10132 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010133 RelocInfo::ModeMask(RelocInfo::CELL) |
10134 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
Steve Blocka7e24c12009-10-30 11:49:00 +000010135 RelocInfo::kApplyMask;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010136 // Needed to find target_object and runtime_entry on X64
10137 Assembler* origin = desc.origin;
10138 AllowDeferredHandleDereference embedding_raw_address;
Steve Blocka7e24c12009-10-30 11:49:00 +000010139 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
10140 RelocInfo::Mode mode = it.rinfo()->rmode();
10141 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +000010142 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010143 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
10144 } else if (mode == RelocInfo::CELL) {
10145 Handle<Cell> cell = it.rinfo()->target_cell_handle();
10146 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010147 } else if (RelocInfo::IsCodeTarget(mode)) {
10148 // rewrite code handles in inline cache targets to direct
10149 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +000010150 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +000010151 Code* code = Code::cast(*p);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010152 it.rinfo()->set_target_address(code->instruction_start(),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010153 SKIP_WRITE_BARRIER,
10154 SKIP_ICACHE_FLUSH);
10155 } else if (RelocInfo::IsRuntimeEntry(mode)) {
10156 Address p = it.rinfo()->target_runtime_entry(origin);
10157 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER,
10158 SKIP_ICACHE_FLUSH);
10159 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
10160 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
10161 Code* code = Code::cast(*p);
10162 it.rinfo()->set_code_age_stub(code, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010163 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010164 it.rinfo()->apply(delta, SKIP_ICACHE_FLUSH);
Steve Blocka7e24c12009-10-30 11:49:00 +000010165 }
10166 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010167 CpuFeatures::FlushICache(instruction_start(), instruction_size());
Steve Blocka7e24c12009-10-30 11:49:00 +000010168}
10169
10170
10171// Locate the source position which is closest to the address in the code. This
10172// is using the source position information embedded in the relocation info.
10173// The position returned is relative to the beginning of the script where the
10174// source for this function is found.
10175int Code::SourcePosition(Address pc) {
10176 int distance = kMaxInt;
10177 int position = RelocInfo::kNoPosition; // Initially no position found.
10178 // Run through all the relocation info to find the best matching source
10179 // position. All the code needs to be considered as the sequence of the
10180 // instructions in the code does not necessarily follow the same order as the
10181 // source.
10182 RelocIterator it(this, RelocInfo::kPositionMask);
10183 while (!it.done()) {
10184 // Only look at positions after the current pc.
10185 if (it.rinfo()->pc() < pc) {
10186 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +000010187
10188 int dist = static_cast<int>(pc - it.rinfo()->pc());
10189 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000010190 // If this position is closer than the current candidate or if it has the
10191 // same distance as the current candidate and the position is higher then
10192 // this position is the new candidate.
10193 if ((dist < distance) ||
10194 (dist == distance && pos > position)) {
10195 position = pos;
10196 distance = dist;
10197 }
10198 }
10199 it.next();
10200 }
10201 return position;
10202}
10203
10204
10205// Same as Code::SourcePosition above except it only looks for statement
10206// positions.
10207int Code::SourceStatementPosition(Address pc) {
10208 // First find the position as close as possible using all position
10209 // information.
10210 int position = SourcePosition(pc);
10211 // Now find the closest statement position before the position.
10212 int statement_position = 0;
10213 RelocIterator it(this, RelocInfo::kPositionMask);
10214 while (!it.done()) {
10215 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +000010216 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +000010217 if (statement_position < p && p <= position) {
10218 statement_position = p;
10219 }
10220 }
10221 it.next();
10222 }
10223 return statement_position;
10224}
10225
10226
Ben Murdochb8e0da22011-05-16 14:20:40 +010010227SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010228 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +010010229 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010230}
10231
10232
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010233Object* Code::FindNthObject(int n, Map* match_map) {
10234 DCHECK(is_inline_cache_stub());
10235 DisallowHeapAllocation no_allocation;
Ben Murdochb0fe1622011-05-05 13:52:32 +010010236 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10237 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10238 RelocInfo* info = it.rinfo();
10239 Object* object = info->target_object();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010240 if (object->IsHeapObject()) {
10241 if (HeapObject::cast(object)->map() == match_map) {
10242 if (--n == 0) return object;
10243 }
10244 }
10245 }
10246 return NULL;
10247}
10248
10249
10250AllocationSite* Code::FindFirstAllocationSite() {
10251 Object* result = FindNthObject(1, GetHeap()->allocation_site_map());
10252 return (result != NULL) ? AllocationSite::cast(result) : NULL;
10253}
10254
10255
10256Map* Code::FindFirstMap() {
10257 Object* result = FindNthObject(1, GetHeap()->meta_map());
10258 return (result != NULL) ? Map::cast(result) : NULL;
10259}
10260
10261
10262void Code::FindAndReplace(const FindAndReplacePattern& pattern) {
10263 DCHECK(is_inline_cache_stub() || is_handler());
10264 DisallowHeapAllocation no_allocation;
10265 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10266 STATIC_ASSERT(FindAndReplacePattern::kMaxCount < 32);
10267 int current_pattern = 0;
10268 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10269 RelocInfo* info = it.rinfo();
10270 Object* object = info->target_object();
10271 if (object->IsHeapObject()) {
10272 Map* map = HeapObject::cast(object)->map();
10273 if (map == *pattern.find_[current_pattern]) {
10274 info->set_target_object(*pattern.replace_[current_pattern]);
10275 if (++current_pattern == pattern.count_) return;
10276 }
10277 }
10278 }
10279 UNREACHABLE();
10280}
10281
10282
10283void Code::FindAllMaps(MapHandleList* maps) {
10284 DCHECK(is_inline_cache_stub());
10285 DisallowHeapAllocation no_allocation;
10286 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10287 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10288 RelocInfo* info = it.rinfo();
10289 Object* object = info->target_object();
10290 if (object->IsMap()) maps->Add(handle(Map::cast(object)));
10291 }
10292}
10293
10294
10295Code* Code::FindFirstHandler() {
10296 DCHECK(is_inline_cache_stub());
10297 DisallowHeapAllocation no_allocation;
10298 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10299 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10300 RelocInfo* info = it.rinfo();
10301 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10302 if (code->kind() == Code::HANDLER) return code;
10303 }
10304 return NULL;
10305}
10306
10307
10308bool Code::FindHandlers(CodeHandleList* code_list, int length) {
10309 DCHECK(is_inline_cache_stub());
10310 DisallowHeapAllocation no_allocation;
10311 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10312 int i = 0;
10313 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10314 if (i == length) return true;
10315 RelocInfo* info = it.rinfo();
10316 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10317 // IC stubs with handlers never contain non-handler code objects before
10318 // handler targets.
10319 if (code->kind() != Code::HANDLER) break;
10320 code_list->Add(Handle<Code>(code));
10321 i++;
10322 }
10323 return i == length;
10324}
10325
10326
10327MaybeHandle<Code> Code::FindHandlerForMap(Map* map) {
10328 DCHECK(is_inline_cache_stub());
10329 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10330 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10331 bool return_next = false;
10332 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10333 RelocInfo* info = it.rinfo();
10334 if (info->rmode() == RelocInfo::EMBEDDED_OBJECT) {
10335 Object* object = info->target_object();
10336 if (object == map) return_next = true;
10337 } else if (return_next) {
10338 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10339 DCHECK(code->kind() == Code::HANDLER);
10340 return handle(code);
10341 }
10342 }
10343 return MaybeHandle<Code>();
10344}
10345
10346
10347Name* Code::FindFirstName() {
10348 DCHECK(is_inline_cache_stub());
10349 DisallowHeapAllocation no_allocation;
10350 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10351 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10352 RelocInfo* info = it.rinfo();
10353 Object* object = info->target_object();
10354 if (object->IsName()) return Name::cast(object);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010355 }
10356 return NULL;
10357}
10358
10359
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010360void Code::ClearInlineCaches() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010361 ClearInlineCaches(NULL);
10362}
10363
10364
10365void Code::ClearInlineCaches(Code::Kind kind) {
10366 ClearInlineCaches(&kind);
10367}
10368
10369
10370void Code::ClearInlineCaches(Code::Kind* kind) {
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010371 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10372 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010373 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010374 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10375 RelocInfo* info = it.rinfo();
10376 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
10377 if (target->is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010378 if (kind == NULL || *kind == target->kind()) {
10379 IC::Clear(this->GetIsolate(), info->pc(),
10380 info->host()->constant_pool());
10381 }
Ben Murdoch8f9999f2012-04-23 10:39:17 +010010382 }
10383 }
10384}
10385
10386
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010387void SharedFunctionInfo::ClearTypeFeedbackInfo() {
10388 TypeFeedbackVector* vector = feedback_vector();
10389 Heap* heap = GetHeap();
10390 int length = vector->length();
10391
10392 for (int i = 0; i < length; i++) {
10393 Object* obj = vector->get(i);
10394 if (obj->IsHeapObject()) {
10395 InstanceType instance_type =
10396 HeapObject::cast(obj)->map()->instance_type();
10397 switch (instance_type) {
10398 case ALLOCATION_SITE_TYPE:
10399 // AllocationSites are not cleared because they do not store
10400 // information that leaks.
10401 break;
10402 // Fall through...
10403 default:
10404 vector->set(i, TypeFeedbackVector::RawUninitializedSentinel(heap),
10405 SKIP_WRITE_BARRIER);
10406 }
10407 }
10408 }
10409}
10410
10411
10412BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
10413 DisallowHeapAllocation no_gc;
10414 DCHECK(kind() == FUNCTION);
10415 BackEdgeTable back_edges(this, &no_gc);
10416 for (uint32_t i = 0; i < back_edges.length(); i++) {
10417 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
10418 }
10419 return BailoutId::None();
10420}
10421
10422
10423uint32_t Code::TranslateAstIdToPcOffset(BailoutId ast_id) {
10424 DisallowHeapAllocation no_gc;
10425 DCHECK(kind() == FUNCTION);
10426 BackEdgeTable back_edges(this, &no_gc);
10427 for (uint32_t i = 0; i < back_edges.length(); i++) {
10428 if (back_edges.ast_id(i) == ast_id) return back_edges.pc_offset(i);
10429 }
10430 UNREACHABLE(); // We expect to find the back edge.
10431 return 0;
10432}
10433
10434
10435void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
10436 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
10437}
10438
10439
10440void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
10441 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
10442 NO_MARKING_PARITY);
10443}
10444
10445
10446static Code::Age EffectiveAge(Code::Age age) {
10447 if (age == Code::kNotExecutedCodeAge) {
10448 // Treat that's never been executed as old immediately.
10449 age = Code::kIsOldCodeAge;
10450 } else if (age == Code::kExecutedOnceCodeAge) {
10451 // Pre-age code that has only been executed once.
10452 age = Code::kPreAgedCodeAge;
10453 }
10454 return age;
10455}
10456
10457
10458void Code::MakeOlder(MarkingParity current_parity) {
10459 byte* sequence = FindCodeAgeSequence();
10460 if (sequence != NULL) {
10461 Age age;
10462 MarkingParity code_parity;
10463 Isolate* isolate = GetIsolate();
10464 GetCodeAgeAndParity(isolate, sequence, &age, &code_parity);
10465 age = EffectiveAge(age);
10466 if (age != kLastCodeAge && code_parity != current_parity) {
10467 PatchPlatformCodeAge(isolate,
10468 sequence,
10469 static_cast<Age>(age + 1),
10470 current_parity);
10471 }
10472 }
10473}
10474
10475
10476bool Code::IsOld() {
10477 return GetAge() >= kIsOldCodeAge;
10478}
10479
10480
10481byte* Code::FindCodeAgeSequence() {
10482 return FLAG_age_code &&
10483 prologue_offset() != Code::kPrologueOffsetNotSet &&
10484 (kind() == OPTIMIZED_FUNCTION ||
10485 (kind() == FUNCTION && !has_debug_break_slots()))
10486 ? instruction_start() + prologue_offset()
10487 : NULL;
10488}
10489
10490
10491Code::Age Code::GetAge() {
10492 return EffectiveAge(GetRawAge());
10493}
10494
10495
10496Code::Age Code::GetRawAge() {
10497 byte* sequence = FindCodeAgeSequence();
10498 if (sequence == NULL) {
10499 return kNoAgeCodeAge;
10500 }
10501 Age age;
10502 MarkingParity parity;
10503 GetCodeAgeAndParity(GetIsolate(), sequence, &age, &parity);
10504 return age;
10505}
10506
10507
10508void Code::GetCodeAgeAndParity(Code* code, Age* age,
10509 MarkingParity* parity) {
10510 Isolate* isolate = code->GetIsolate();
10511 Builtins* builtins = isolate->builtins();
10512 Code* stub = NULL;
10513#define HANDLE_CODE_AGE(AGE) \
10514 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
10515 if (code == stub) { \
10516 *age = k##AGE##CodeAge; \
10517 *parity = EVEN_MARKING_PARITY; \
10518 return; \
10519 } \
10520 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10521 if (code == stub) { \
10522 *age = k##AGE##CodeAge; \
10523 *parity = ODD_MARKING_PARITY; \
10524 return; \
10525 }
10526 CODE_AGE_LIST(HANDLE_CODE_AGE)
10527#undef HANDLE_CODE_AGE
10528 stub = *builtins->MarkCodeAsExecutedOnce();
10529 if (code == stub) {
10530 *age = kNotExecutedCodeAge;
10531 *parity = NO_MARKING_PARITY;
10532 return;
10533 }
10534 stub = *builtins->MarkCodeAsExecutedTwice();
10535 if (code == stub) {
10536 *age = kExecutedOnceCodeAge;
10537 *parity = NO_MARKING_PARITY;
10538 return;
10539 }
10540 UNREACHABLE();
10541}
10542
10543
10544Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
10545 Builtins* builtins = isolate->builtins();
10546 switch (age) {
10547#define HANDLE_CODE_AGE(AGE) \
10548 case k##AGE##CodeAge: { \
10549 Code* stub = parity == EVEN_MARKING_PARITY \
10550 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
10551 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10552 return stub; \
10553 }
10554 CODE_AGE_LIST(HANDLE_CODE_AGE)
10555#undef HANDLE_CODE_AGE
10556 case kNotExecutedCodeAge: {
10557 DCHECK(parity == NO_MARKING_PARITY);
10558 return *builtins->MarkCodeAsExecutedOnce();
10559 }
10560 case kExecutedOnceCodeAge: {
10561 DCHECK(parity == NO_MARKING_PARITY);
10562 return *builtins->MarkCodeAsExecutedTwice();
10563 }
10564 default:
10565 UNREACHABLE();
10566 break;
10567 }
10568 return NULL;
10569}
10570
10571
10572void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
10573 const char* last_comment = NULL;
10574 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
10575 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
10576 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10577 RelocInfo* info = it.rinfo();
10578 if (info->rmode() == RelocInfo::COMMENT) {
10579 last_comment = reinterpret_cast<const char*>(info->data());
10580 } else if (last_comment != NULL) {
10581 if ((bailout_id == Deoptimizer::GetDeoptimizationId(
10582 GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
10583 (bailout_id == Deoptimizer::GetDeoptimizationId(
10584 GetIsolate(), info->target_address(), Deoptimizer::SOFT)) ||
10585 (bailout_id == Deoptimizer::GetDeoptimizationId(
10586 GetIsolate(), info->target_address(), Deoptimizer::LAZY))) {
10587 CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
10588 PrintF(out, " %s\n", last_comment);
10589 return;
10590 }
10591 }
10592 }
10593}
10594
10595
10596bool Code::CanDeoptAt(Address pc) {
10597 DeoptimizationInputData* deopt_data =
10598 DeoptimizationInputData::cast(deoptimization_data());
10599 Address code_start_address = instruction_start();
10600 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
10601 if (deopt_data->Pc(i)->value() == -1) continue;
10602 Address address = code_start_address + deopt_data->Pc(i)->value();
10603 if (address == pc) return true;
10604 }
10605 return false;
10606}
10607
10608
10609// Identify kind of code.
10610const char* Code::Kind2String(Kind kind) {
10611 switch (kind) {
10612#define CASE(name) case name: return #name;
10613 CODE_KIND_LIST(CASE)
10614#undef CASE
10615 case NUMBER_OF_KINDS: break;
10616 }
10617 UNREACHABLE();
10618 return NULL;
10619}
10620
10621
Steve Blocka7e24c12009-10-30 11:49:00 +000010622#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010010623
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010624void DeoptimizationInputData::DeoptimizationInputDataPrint(
10625 OStream& os) { // NOLINT
Ben Murdochb0fe1622011-05-05 13:52:32 +010010626 disasm::NameConverter converter;
10627 int deopt_count = DeoptCount();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010628 os << "Deoptimization Input Data (deopt points = " << deopt_count << ")\n";
10629 if (0 != deopt_count) {
10630 os << " index ast id argc pc";
10631 if (FLAG_print_code_verbose) os << " commands";
10632 os << "\n";
10633 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010634 for (int i = 0; i < deopt_count; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010635 // TODO(svenpanne) Add some basic formatting to our streams.
10636 Vector<char> buf1 = Vector<char>::New(128);
10637 SNPrintF(buf1, "%6d %6d %6d %6d", i, AstId(i).ToInt(),
10638 ArgumentsStackHeight(i)->value(), Pc(i)->value());
10639 os << buf1.start();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010640
10641 if (!FLAG_print_code_verbose) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010642 os << "\n";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010643 continue;
10644 }
10645 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +010010646 int translation_index = TranslationIndex(i)->value();
10647 TranslationIterator iterator(TranslationByteArray(), translation_index);
10648 Translation::Opcode opcode =
10649 static_cast<Translation::Opcode>(iterator.Next());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010650 DCHECK(Translation::BEGIN == opcode);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010651 int frame_count = iterator.Next();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010652 int jsframe_count = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010653 os << " " << Translation::StringFor(opcode)
10654 << " {frame count=" << frame_count
10655 << ", js frame count=" << jsframe_count << "}\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010656
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010657 while (iterator.HasNext() &&
10658 Translation::BEGIN !=
10659 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010660 Vector<char> buf2 = Vector<char>::New(128);
10661 SNPrintF(buf2, "%27s %s ", "", Translation::StringFor(opcode));
10662 os << buf2.start();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010663
10664 switch (opcode) {
10665 case Translation::BEGIN:
10666 UNREACHABLE();
10667 break;
10668
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010669 case Translation::JS_FRAME: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010670 int ast_id = iterator.Next();
10671 int function_id = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010672 unsigned height = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010673 os << "{ast_id=" << ast_id << ", function=";
10674 if (function_id != Translation::kSelfLiteralId) {
10675 Object* function = LiteralArray()->get(function_id);
10676 os << Brief(JSFunction::cast(function)->shared()->DebugName());
10677 } else {
10678 os << "<self>";
10679 }
10680 os << ", height=" << height << "}";
10681 break;
10682 }
10683
10684 case Translation::COMPILED_STUB_FRAME: {
10685 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
10686 os << "{kind=" << stub_kind << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010687 break;
10688 }
10689
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010690 case Translation::ARGUMENTS_ADAPTOR_FRAME:
10691 case Translation::CONSTRUCT_STUB_FRAME: {
10692 int function_id = iterator.Next();
10693 JSFunction* function =
10694 JSFunction::cast(LiteralArray()->get(function_id));
10695 unsigned height = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010696 os << "{function=" << Brief(function->shared()->DebugName())
10697 << ", height=" << height << "}";
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010698 break;
10699 }
10700
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010701 case Translation::GETTER_STUB_FRAME:
10702 case Translation::SETTER_STUB_FRAME: {
10703 int function_id = iterator.Next();
10704 JSFunction* function =
10705 JSFunction::cast(LiteralArray()->get(function_id));
10706 os << "{function=" << Brief(function->shared()->DebugName()) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010707 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010708 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010709
10710 case Translation::REGISTER: {
10711 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010712 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010713 break;
10714 }
10715
10716 case Translation::INT32_REGISTER: {
10717 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010718 os << "{input=" << converter.NameOfCPURegister(reg_code) << "}";
10719 break;
10720 }
10721
10722 case Translation::UINT32_REGISTER: {
10723 int reg_code = iterator.Next();
10724 os << "{input=" << converter.NameOfCPURegister(reg_code)
10725 << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010726 break;
10727 }
10728
10729 case Translation::DOUBLE_REGISTER: {
10730 int reg_code = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010731 os << "{input=" << DoubleRegister::AllocationIndexToString(reg_code)
10732 << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010733 break;
10734 }
10735
10736 case Translation::STACK_SLOT: {
10737 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010738 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010739 break;
10740 }
10741
10742 case Translation::INT32_STACK_SLOT: {
10743 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010744 os << "{input=" << input_slot_index << "}";
10745 break;
10746 }
10747
10748 case Translation::UINT32_STACK_SLOT: {
10749 int input_slot_index = iterator.Next();
10750 os << "{input=" << input_slot_index << " (unsigned)}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010751 break;
10752 }
10753
10754 case Translation::DOUBLE_STACK_SLOT: {
10755 int input_slot_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010756 os << "{input=" << input_slot_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010757 break;
10758 }
10759
10760 case Translation::LITERAL: {
10761 unsigned literal_index = iterator.Next();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010762 os << "{literal_id=" << literal_index << "}";
10763 break;
10764 }
10765
10766 case Translation::DUPLICATED_OBJECT: {
10767 int object_index = iterator.Next();
10768 os << "{object_index=" << object_index << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010769 break;
10770 }
10771
10772 case Translation::ARGUMENTS_OBJECT:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010773 case Translation::CAPTURED_OBJECT: {
10774 int args_length = iterator.Next();
10775 os << "{length=" << args_length << "}";
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010776 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010777 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010778 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010779 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010780 }
Ben Murdochb0fe1622011-05-05 13:52:32 +010010781 }
10782}
10783
10784
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010785void DeoptimizationOutputData::DeoptimizationOutputDataPrint(
10786 OStream& os) { // NOLINT
10787 os << "Deoptimization Output Data (deopt points = " << this->DeoptPoints()
10788 << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010789 if (this->DeoptPoints() == 0) return;
10790
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010791 os << "ast id pc state\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010792 for (int i = 0; i < this->DeoptPoints(); i++) {
10793 int pc_and_state = this->PcAndState(i)->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010794 // TODO(svenpanne) Add some basic formatting to our streams.
10795 Vector<char> buf = Vector<char>::New(100);
10796 SNPrintF(buf, "%6d %8d %s\n", this->AstId(i).ToInt(),
10797 FullCodeGenerator::PcField::decode(pc_and_state),
10798 FullCodeGenerator::State2String(
10799 FullCodeGenerator::StateField::decode(pc_and_state)));
10800 os << buf.start();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010801 }
10802}
10803
Ben Murdochb0fe1622011-05-05 13:52:32 +010010804
Steve Blocka7e24c12009-10-30 11:49:00 +000010805const char* Code::ICState2String(InlineCacheState state) {
10806 switch (state) {
10807 case UNINITIALIZED: return "UNINITIALIZED";
10808 case PREMONOMORPHIC: return "PREMONOMORPHIC";
10809 case MONOMORPHIC: return "MONOMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010810 case PROTOTYPE_FAILURE:
10811 return "PROTOTYPE_FAILURE";
10812 case POLYMORPHIC: return "POLYMORPHIC";
Steve Blocka7e24c12009-10-30 11:49:00 +000010813 case MEGAMORPHIC: return "MEGAMORPHIC";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010814 case GENERIC: return "GENERIC";
10815 case DEBUG_STUB: return "DEBUG_STUB";
10816 case DEFAULT:
10817 return "DEFAULT";
Steve Blocka7e24c12009-10-30 11:49:00 +000010818 }
10819 UNREACHABLE();
10820 return NULL;
10821}
10822
10823
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010824const char* Code::StubType2String(StubType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010825 switch (type) {
10826 case NORMAL: return "NORMAL";
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010827 case FAST: return "FAST";
Steve Blocka7e24c12009-10-30 11:49:00 +000010828 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010829 UNREACHABLE(); // keep the compiler happy
Steve Blocka7e24c12009-10-30 11:49:00 +000010830 return NULL;
10831}
10832
Ben Murdochb0fe1622011-05-05 13:52:32 +010010833
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010834void Code::PrintExtraICState(OStream& os, // NOLINT
10835 Kind kind, ExtraICState extra) {
10836 os << "extra_ic_state = ";
10837 if ((kind == STORE_IC || kind == KEYED_STORE_IC) && (extra == STRICT)) {
10838 os << "STRICT\n";
Steve Block1e0659c2011-05-24 12:43:12 +010010839 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010840 os << extra << "\n";
Steve Block1e0659c2011-05-24 12:43:12 +010010841 }
10842}
10843
10844
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010845void Code::Disassemble(const char* name, OStream& os) { // NOLINT
10846 os << "kind = " << Kind2String(kind()) << "\n";
10847 if (IsCodeStubOrIC()) {
10848 const char* n = CodeStub::MajorName(CodeStub::GetMajorKey(this), true);
10849 os << "major_key = " << (n == NULL ? "null" : n) << "\n";
10850 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010851 if (is_inline_cache_stub()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010852 os << "ic_state = " << ICState2String(ic_state()) << "\n";
10853 PrintExtraICState(os, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +000010854 if (ic_state() == MONOMORPHIC) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010855 os << "type = " << StubType2String(type()) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000010856 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010857 if (is_compare_ic_stub()) {
10858 DCHECK(CodeStub::GetMajorKey(this) == CodeStub::CompareIC);
10859 CompareICStub stub(stub_key(), GetIsolate());
10860 os << "compare_state = " << CompareICState::GetStateName(stub.left())
10861 << "*" << CompareICState::GetStateName(stub.right()) << " -> "
10862 << CompareICState::GetStateName(stub.state()) << "\n";
10863 os << "compare_operation = " << Token::Name(stub.op()) << "\n";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010864 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010865 }
10866 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010867 os << "name = " << name << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010868 }
10869 if (kind() == OPTIMIZED_FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010870 os << "stack_slots = " << stack_slots() << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000010871 }
10872
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010873 os << "Instructions (size = " << instruction_size() << ")\n";
10874 // TODO(svenpanne) The Disassembler should use streams, too!
10875 {
10876 CodeTracer::Scope trace_scope(GetIsolate()->GetCodeTracer());
10877 Disassembler::Decode(trace_scope.file(), this);
10878 }
10879 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010880
Ben Murdochb0fe1622011-05-05 13:52:32 +010010881 if (kind() == FUNCTION) {
10882 DeoptimizationOutputData* data =
10883 DeoptimizationOutputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010884 data->DeoptimizationOutputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010885 } else if (kind() == OPTIMIZED_FUNCTION) {
10886 DeoptimizationInputData* data =
10887 DeoptimizationInputData::cast(this->deoptimization_data());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010888 data->DeoptimizationInputDataPrint(os);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010889 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010890 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010891
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010892 if (is_crankshafted()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010010893 SafepointTable table(this);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010894 os << "Safepoints (size = " << table.size() << ")\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010895 for (unsigned i = 0; i < table.length(); i++) {
10896 unsigned pc_offset = table.GetPcOffset(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010897 os << (instruction_start() + pc_offset) << " ";
10898 // TODO(svenpanne) Add some basic formatting to our streams.
10899 Vector<char> buf1 = Vector<char>::New(30);
10900 SNPrintF(buf1, "%4d", pc_offset);
10901 os << buf1.start() << " ";
10902 table.PrintEntry(i, os);
10903 os << " (sp -> fp) ";
Ben Murdochb8e0da22011-05-16 14:20:40 +010010904 SafepointEntry entry = table.GetEntry(i);
10905 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010906 Vector<char> buf2 = Vector<char>::New(30);
10907 SNPrintF(buf2, "%6d", entry.deoptimization_index());
10908 os << buf2.start();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010909 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010910 os << "<none>";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010911 }
Ben Murdochb8e0da22011-05-16 14:20:40 +010010912 if (entry.argument_count() > 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010913 os << " argc: " << entry.argument_count();
Ben Murdochb8e0da22011-05-16 14:20:40 +010010914 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010915 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010916 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010917 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010918 } else if (kind() == FUNCTION) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010919 unsigned offset = back_edge_table_offset();
10920 // If there is no back edge table, the "table start" will be at or after
Ben Murdochb0fe1622011-05-05 13:52:32 +010010921 // (due to alignment) the end of the instruction stream.
10922 if (static_cast<int>(offset) < instruction_size()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010923 DisallowHeapAllocation no_gc;
10924 BackEdgeTable back_edges(this, &no_gc);
10925
10926 os << "Back edges (size = " << back_edges.length() << ")\n";
10927 os << "ast_id pc_offset loop_depth\n";
10928
10929 for (uint32_t i = 0; i < back_edges.length(); i++) {
10930 Vector<char> buf = Vector<char>::New(100);
10931 SNPrintF(buf, "%6d %9u %10u\n", back_edges.ast_id(i).ToInt(),
10932 back_edges.pc_offset(i), back_edges.loop_depth(i));
10933 os << buf.start();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010934 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010935
10936 os << "\n";
Ben Murdochb0fe1622011-05-05 13:52:32 +010010937 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010938#ifdef OBJECT_PRINT
10939 if (!type_feedback_info()->IsUndefined()) {
10940 OFStream os(stdout);
10941 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(os);
10942 os << "\n";
10943 }
10944#endif
Ben Murdochb0fe1622011-05-05 13:52:32 +010010945 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010946
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010947 os << "RelocInfo (size = " << relocation_size() << ")\n";
10948 for (RelocIterator it(this); !it.done(); it.next()) {
10949 it.rinfo()->Print(GetIsolate(), os);
10950 }
10951 os << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000010952}
10953#endif // ENABLE_DISASSEMBLER
10954
10955
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010956Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength(
10957 Handle<JSObject> object,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010958 int capacity,
10959 int length,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010960 SetFastElementsCapacitySmiMode smi_mode) {
Steve Block3ce2e202009-11-05 08:53:23 +000010961 // We should never end in here with a pixel or external array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010962 DCHECK(!object->HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +010010963
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010964 // Allocate a new fast elements backing store.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010965 Handle<FixedArray> new_elements =
10966 object->GetIsolate()->factory()->NewUninitializedFixedArray(capacity);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010967
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010968 ElementsKind elements_kind = object->GetElementsKind();
10969 ElementsKind new_elements_kind;
10970 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
10971 // or if it's allowed and the old elements array contained only SMIs.
10972 bool has_fast_smi_elements =
10973 (smi_mode == kForceSmiElements) ||
10974 ((smi_mode == kAllowSmiElements) && object->HasFastSmiElements());
10975 if (has_fast_smi_elements) {
10976 if (IsHoleyElementsKind(elements_kind)) {
10977 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
10978 } else {
10979 new_elements_kind = FAST_SMI_ELEMENTS;
10980 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010010981 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000010982 if (IsHoleyElementsKind(elements_kind)) {
10983 new_elements_kind = FAST_HOLEY_ELEMENTS;
10984 } else {
10985 new_elements_kind = FAST_ELEMENTS;
10986 }
10987 }
10988 Handle<FixedArrayBase> old_elements(object->elements());
10989 ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
10990 accessor->CopyElements(object, new_elements, elements_kind);
10991
10992 if (elements_kind != SLOPPY_ARGUMENTS_ELEMENTS) {
10993 Handle<Map> new_map = (new_elements_kind != elements_kind)
10994 ? GetElementsTransitionMap(object, new_elements_kind)
10995 : handle(object->map());
10996 JSObject::ValidateElements(object);
10997 JSObject::SetMapAndElements(object, new_map, new_elements);
10998
10999 // Transition through the allocation site as well if present.
11000 JSObject::UpdateAllocationSite(object, new_elements_kind);
11001 } else {
11002 Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(old_elements);
11003 parameter_map->set(1, *new_elements);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011004 }
11005
11006 if (FLAG_trace_elements_transitions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011007 PrintElementsTransition(stdout, object, elements_kind, old_elements,
11008 object->GetElementsKind(), new_elements);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011009 }
11010
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011011 if (object->IsJSArray()) {
11012 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011013 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011014 return new_elements;
11015}
11016
11017
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011018void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,
11019 int capacity,
11020 int length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011021 // We should never end in here with a pixel or external array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011022 DCHECK(!object->HasExternalArrayElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011023
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011024 Handle<FixedArrayBase> elems =
11025 object->GetIsolate()->factory()->NewFixedDoubleArray(capacity);
Steve Block8defd9f2010-07-08 12:39:36 +010011026
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011027 ElementsKind elements_kind = object->GetElementsKind();
11028 CHECK(elements_kind != SLOPPY_ARGUMENTS_ELEMENTS);
11029 ElementsKind new_elements_kind = elements_kind;
11030 if (IsHoleyElementsKind(elements_kind)) {
11031 new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011032 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011033 new_elements_kind = FAST_DOUBLE_ELEMENTS;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011034 }
11035
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011036 Handle<Map> new_map = GetElementsTransitionMap(object, new_elements_kind);
11037
11038 Handle<FixedArrayBase> old_elements(object->elements());
11039 ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
11040 accessor->CopyElements(object, elems, elements_kind);
11041
11042 JSObject::ValidateElements(object);
11043 JSObject::SetMapAndElements(object, new_map, elems);
11044
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011045 if (FLAG_trace_elements_transitions) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011046 PrintElementsTransition(stdout, object, elements_kind, old_elements,
11047 object->GetElementsKind(), elems);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011048 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011049
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011050 if (object->IsJSArray()) {
11051 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(length));
Steve Block8defd9f2010-07-08 12:39:36 +010011052 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011053}
11054
11055
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011056// static
11057void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) {
11058 DCHECK(capacity >= 0);
11059 array->GetIsolate()->factory()->NewJSArrayStorage(
11060 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
11061}
11062
11063
11064void JSArray::Expand(Handle<JSArray> array, int required_size) {
11065 ElementsAccessor* accessor = array->GetElementsAccessor();
11066 accessor->SetCapacityAndLength(array, required_size, required_size);
11067}
11068
11069
11070// Returns false if the passed-in index is marked non-configurable,
11071// which will cause the ES5 truncation operation to halt, and thus
11072// no further old values need be collected.
11073static bool GetOldValue(Isolate* isolate,
11074 Handle<JSObject> object,
11075 uint32_t index,
11076 List<Handle<Object> >* old_values,
11077 List<uint32_t>* indices) {
11078 Maybe<PropertyAttributes> maybe =
11079 JSReceiver::GetOwnElementAttribute(object, index);
11080 DCHECK(maybe.has_value);
11081 DCHECK(maybe.value != ABSENT);
11082 if (maybe.value == DONT_DELETE) return false;
11083 Handle<Object> value;
11084 if (!JSObject::GetOwnElementAccessorPair(object, index).is_null()) {
11085 value = Handle<Object>::cast(isolate->factory()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011086 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011087 value = Object::GetElement(isolate, object, index).ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000011088 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011089 old_values->Add(value);
11090 indices->Add(index);
11091 return true;
11092}
11093
11094static void EnqueueSpliceRecord(Handle<JSArray> object,
11095 uint32_t index,
11096 Handle<JSArray> deleted,
11097 uint32_t add_count) {
11098 Isolate* isolate = object->GetIsolate();
11099 HandleScope scope(isolate);
11100 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
11101 Handle<Object> add_count_object =
11102 isolate->factory()->NewNumberFromUint(add_count);
11103
11104 Handle<Object> args[] =
11105 { object, index_object, deleted, add_count_object };
11106
11107 Execution::Call(isolate,
11108 Handle<JSFunction>(isolate->observers_enqueue_splice()),
11109 isolate->factory()->undefined_value(),
11110 arraysize(args),
11111 args).Assert();
Steve Blocka7e24c12009-10-30 11:49:00 +000011112}
11113
11114
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011115static void BeginPerformSplice(Handle<JSArray> object) {
11116 Isolate* isolate = object->GetIsolate();
11117 HandleScope scope(isolate);
11118 Handle<Object> args[] = { object };
11119
11120 Execution::Call(isolate,
11121 Handle<JSFunction>(isolate->observers_begin_perform_splice()),
11122 isolate->factory()->undefined_value(),
11123 arraysize(args),
11124 args).Assert();
Steve Blocka7e24c12009-10-30 11:49:00 +000011125}
11126
11127
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011128static void EndPerformSplice(Handle<JSArray> object) {
11129 Isolate* isolate = object->GetIsolate();
11130 HandleScope scope(isolate);
11131 Handle<Object> args[] = { object };
11132
11133 Execution::Call(isolate,
11134 Handle<JSFunction>(isolate->observers_end_perform_splice()),
11135 isolate->factory()->undefined_value(),
11136 arraysize(args),
11137 args).Assert();
11138}
11139
11140
11141MaybeHandle<Object> JSArray::SetElementsLength(
11142 Handle<JSArray> array,
11143 Handle<Object> new_length_handle) {
11144 if (array->HasFastElements()) {
11145 // If the new array won't fit in a some non-trivial fraction of the max old
11146 // space size, then force it to go dictionary mode.
11147 int max_fast_array_size = static_cast<int>(
11148 (array->GetHeap()->MaxOldGenerationSize() / kDoubleSize) / 4);
11149 if (new_length_handle->IsNumber() &&
11150 NumberToInt32(*new_length_handle) >= max_fast_array_size) {
11151 NormalizeElements(array);
11152 }
11153 }
11154
Steve Block3ce2e202009-11-05 08:53:23 +000011155 // We should never end in here with a pixel or external array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011156 DCHECK(array->AllowsSetElementsLength());
11157 if (!array->map()->is_observed()) {
11158 return array->GetElementsAccessor()->SetLength(array, new_length_handle);
11159 }
11160
11161 Isolate* isolate = array->GetIsolate();
11162 List<uint32_t> indices;
11163 List<Handle<Object> > old_values;
11164 Handle<Object> old_length_handle(array->length(), isolate);
11165 uint32_t old_length = 0;
11166 CHECK(old_length_handle->ToArrayIndex(&old_length));
11167 uint32_t new_length = 0;
11168 CHECK(new_length_handle->ToArrayIndex(&new_length));
11169
11170 static const PropertyAttributes kNoAttrFilter = NONE;
11171 int num_elements = array->NumberOfOwnElements(kNoAttrFilter);
11172 if (num_elements > 0) {
11173 if (old_length == static_cast<uint32_t>(num_elements)) {
11174 // Simple case for arrays without holes.
11175 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
11176 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break;
11177 }
11178 } else {
11179 // For sparse arrays, only iterate over existing elements.
11180 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
11181 // the to-be-removed indices twice.
11182 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
11183 array->GetOwnElementKeys(*keys, kNoAttrFilter);
11184 while (num_elements-- > 0) {
11185 uint32_t index = NumberToUint32(keys->get(num_elements));
11186 if (index < new_length) break;
11187 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break;
11188 }
11189 }
11190 }
11191
11192 Handle<Object> hresult;
11193 ASSIGN_RETURN_ON_EXCEPTION(
11194 isolate, hresult,
11195 array->GetElementsAccessor()->SetLength(array, new_length_handle),
11196 Object);
11197
11198 CHECK(array->length()->ToArrayIndex(&new_length));
11199 if (old_length == new_length) return hresult;
11200
11201 BeginPerformSplice(array);
11202
11203 for (int i = 0; i < indices.length(); ++i) {
11204 // For deletions where the property was an accessor, old_values[i]
11205 // will be the hole, which instructs EnqueueChangeRecord to elide
11206 // the "oldValue" property.
11207 JSObject::EnqueueChangeRecord(
11208 array, "delete", isolate->factory()->Uint32ToString(indices[i]),
11209 old_values[i]);
11210 }
11211 JSObject::EnqueueChangeRecord(
11212 array, "update", isolate->factory()->length_string(),
11213 old_length_handle);
11214
11215 EndPerformSplice(array);
11216
11217 uint32_t index = Min(old_length, new_length);
11218 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
11219 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
11220 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
11221 if (delete_count > 0) {
11222 for (int i = indices.length() - 1; i >= 0; i--) {
11223 // Skip deletions where the property was an accessor, leaving holes
11224 // in the array of old values.
11225 if (old_values[i]->IsTheHole()) continue;
11226 JSObject::SetElement(
11227 deleted, indices[i] - index, old_values[i], NONE, SLOPPY).Assert();
11228 }
11229
11230 SetProperty(deleted, isolate->factory()->length_string(),
11231 isolate->factory()->NewNumberFromUint(delete_count),
11232 STRICT).Assert();
11233 }
11234
11235 EnqueueSpliceRecord(array, index, deleted, add_count);
11236
11237 return hresult;
Steve Blocka7e24c12009-10-30 11:49:00 +000011238}
11239
11240
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011241Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
11242 Handle<Object> prototype) {
11243 FixedArray* cache = map->GetPrototypeTransitions();
11244 int number_of_transitions = map->NumberOfProtoTransitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011245 const int proto_offset =
11246 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
11247 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
11248 const int step = kProtoTransitionElementsPerEntry;
11249 for (int i = 0; i < number_of_transitions; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011250 if (cache->get(proto_offset + i * step) == *prototype) {
11251 Object* result = cache->get(map_offset + i * step);
11252 return Handle<Map>(Map::cast(result));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011253 }
Steve Block053d10c2011-06-13 19:13:29 +010011254 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011255 return Handle<Map>();
Steve Block053d10c2011-06-13 19:13:29 +010011256}
11257
11258
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011259Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
11260 Handle<Object> prototype,
11261 Handle<Map> target_map) {
11262 DCHECK(target_map->IsMap());
11263 DCHECK(HeapObject::cast(*prototype)->map()->IsMap());
11264 // Don't cache prototype transition if this map is either shared, or a map of
11265 // a prototype.
11266 if (map->is_prototype_map()) return map;
11267 if (map->is_dictionary_map() || !FLAG_cache_prototype_transitions) return map;
Steve Block053d10c2011-06-13 19:13:29 +010011268
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011269 const int step = kProtoTransitionElementsPerEntry;
11270 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +010011271
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011272 Handle<FixedArray> cache(map->GetPrototypeTransitions());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011273 int capacity = (cache->length() - header) / step;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011274 int transitions = map->NumberOfProtoTransitions() + 1;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011275
11276 if (transitions > capacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011277 if (capacity > kMaxCachedPrototypeTransitions) return map;
Steve Block053d10c2011-06-13 19:13:29 +010011278
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011279 // Grow array by factor 2 over and above what we need.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011280 cache = FixedArray::CopySize(cache, transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +010011281
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011282 SetPrototypeTransitions(map, cache);
Steve Block053d10c2011-06-13 19:13:29 +010011283 }
11284
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011285 // Reload number of transitions as GC might shrink them.
11286 int last = map->NumberOfProtoTransitions();
11287 int entry = header + last * step;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011288
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011289 cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
11290 cache->set(entry + kProtoTransitionMapOffset, *target_map);
11291 map->SetNumberOfProtoTransitions(last + 1);
Steve Block053d10c2011-06-13 19:13:29 +010011292
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011293 return map;
Steve Block053d10c2011-06-13 19:13:29 +010011294}
11295
11296
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011297void Map::ZapTransitions() {
11298 TransitionArray* transition_array = transitions();
11299 // TODO(mstarzinger): Temporarily use a slower version instead of the faster
11300 // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
11301 Object** data = transition_array->data_start();
11302 Object* the_hole = GetHeap()->the_hole_value();
11303 int length = transition_array->length();
11304 for (int i = 0; i < length; i++) {
11305 data[i] = the_hole;
11306 }
11307}
11308
11309
11310void Map::ZapPrototypeTransitions() {
11311 FixedArray* proto_transitions = GetPrototypeTransitions();
11312 MemsetPointer(proto_transitions->data_start(),
11313 GetHeap()->the_hole_value(),
11314 proto_transitions->length());
11315}
11316
11317
11318// static
11319void Map::AddDependentCompilationInfo(Handle<Map> map,
11320 DependentCode::DependencyGroup group,
11321 CompilationInfo* info) {
11322 Handle<DependentCode> codes =
11323 DependentCode::Insert(handle(map->dependent_code(), info->isolate()),
11324 group, info->object_wrapper());
11325 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11326 info->dependencies(group)->Add(map, info->zone());
11327}
11328
11329
11330// static
11331void Map::AddDependentCode(Handle<Map> map,
11332 DependentCode::DependencyGroup group,
11333 Handle<Code> code) {
11334 Handle<DependentCode> codes = DependentCode::Insert(
11335 Handle<DependentCode>(map->dependent_code()), group, code);
11336 if (*codes != map->dependent_code()) map->set_dependent_code(*codes);
11337}
11338
11339
11340// static
11341void Map::AddDependentIC(Handle<Map> map,
11342 Handle<Code> stub) {
11343 DCHECK(stub->next_code_link()->IsUndefined());
11344 int n = map->dependent_code()->number_of_entries(DependentCode::kWeakICGroup);
11345 if (n == 0) {
11346 // Slow path: insert the head of the list with possible heap allocation.
11347 Map::AddDependentCode(map, DependentCode::kWeakICGroup, stub);
11348 } else {
11349 // Fast path: link the stub to the existing head of the list without any
11350 // heap allocation.
11351 DCHECK(n == 1);
11352 map->dependent_code()->AddToDependentICList(stub);
11353 }
11354}
11355
11356
11357DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
11358 Recompute(entries);
11359}
11360
11361
11362void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
11363 start_indexes_[0] = 0;
11364 for (int g = 1; g <= kGroupCount; g++) {
11365 int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
11366 start_indexes_[g] = start_indexes_[g - 1] + count;
11367 }
11368}
11369
11370
11371DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
11372 DependencyGroup group) {
11373 AllowDeferredHandleDereference dependencies_are_safe;
11374 if (group == DependentCode::kPropertyCellChangedGroup) {
11375 return Handle<PropertyCell>::cast(object)->dependent_code();
11376 } else if (group == DependentCode::kAllocationSiteTenuringChangedGroup ||
11377 group == DependentCode::kAllocationSiteTransitionChangedGroup) {
11378 return Handle<AllocationSite>::cast(object)->dependent_code();
11379 }
11380 return Handle<Map>::cast(object)->dependent_code();
11381}
11382
11383
11384Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
11385 DependencyGroup group,
11386 Handle<Object> object) {
11387 GroupStartIndexes starts(*entries);
11388 int start = starts.at(group);
11389 int end = starts.at(group + 1);
11390 int number_of_entries = starts.number_of_entries();
11391 // Check for existing entry to avoid duplicates.
11392 for (int i = start; i < end; i++) {
11393 if (entries->object_at(i) == *object) return entries;
11394 }
11395 if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
11396 int capacity = kCodesStartIndex + number_of_entries + 1;
11397 if (capacity > 5) capacity = capacity * 5 / 4;
11398 Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
11399 FixedArray::CopySize(entries, capacity, TENURED));
11400 // The number of codes can change after GC.
11401 starts.Recompute(*entries);
11402 start = starts.at(group);
11403 end = starts.at(group + 1);
11404 number_of_entries = starts.number_of_entries();
11405 for (int i = 0; i < number_of_entries; i++) {
11406 entries->clear_at(i);
11407 }
11408 // If the old fixed array was empty, we need to reset counters of the
11409 // new array.
11410 if (number_of_entries == 0) {
11411 for (int g = 0; g < kGroupCount; g++) {
11412 new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
11413 }
11414 }
11415 entries = new_entries;
11416 }
11417 entries->ExtendGroup(group);
11418 entries->set_object_at(end, *object);
11419 entries->set_number_of_entries(group, end + 1 - start);
11420 return entries;
11421}
11422
11423
11424void DependentCode::UpdateToFinishedCode(DependencyGroup group,
11425 CompilationInfo* info,
11426 Code* code) {
11427 DisallowHeapAllocation no_gc;
11428 AllowDeferredHandleDereference get_object_wrapper;
11429 Foreign* info_wrapper = *info->object_wrapper();
11430 GroupStartIndexes starts(this);
11431 int start = starts.at(group);
11432 int end = starts.at(group + 1);
11433 for (int i = start; i < end; i++) {
11434 if (object_at(i) == info_wrapper) {
11435 set_object_at(i, code);
11436 break;
11437 }
11438 }
11439
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011440#ifdef DEBUG
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011441 for (int i = start; i < end; i++) {
11442 DCHECK(is_code_at(i) || compilation_info_at(i) != info);
11443 }
11444#endif
11445}
11446
11447
11448void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
11449 CompilationInfo* info) {
11450 DisallowHeapAllocation no_allocation;
11451 AllowDeferredHandleDereference get_object_wrapper;
11452 Foreign* info_wrapper = *info->object_wrapper();
11453 GroupStartIndexes starts(this);
11454 int start = starts.at(group);
11455 int end = starts.at(group + 1);
11456 // Find compilation info wrapper.
11457 int info_pos = -1;
11458 for (int i = start; i < end; i++) {
11459 if (object_at(i) == info_wrapper) {
11460 info_pos = i;
11461 break;
11462 }
11463 }
11464 if (info_pos == -1) return; // Not found.
11465 int gap = info_pos;
11466 // Use the last of each group to fill the gap in the previous group.
11467 for (int i = group; i < kGroupCount; i++) {
11468 int last_of_group = starts.at(i + 1) - 1;
11469 DCHECK(last_of_group >= gap);
11470 if (last_of_group == gap) continue;
11471 copy(last_of_group, gap);
11472 gap = last_of_group;
11473 }
11474 DCHECK(gap == starts.number_of_entries() - 1);
11475 clear_at(gap); // Clear last gap.
11476 set_number_of_entries(group, end - start - 1);
11477
11478#ifdef DEBUG
11479 for (int i = start; i < end - 1; i++) {
11480 DCHECK(is_code_at(i) || compilation_info_at(i) != info);
11481 }
11482#endif
11483}
11484
11485
11486static bool CodeListContains(Object* head, Code* code) {
11487 while (!head->IsUndefined()) {
11488 if (head == code) return true;
11489 head = Code::cast(head)->next_code_link();
11490 }
11491 return false;
11492}
11493
11494
11495bool DependentCode::Contains(DependencyGroup group, Code* code) {
11496 GroupStartIndexes starts(this);
11497 int start = starts.at(group);
11498 int end = starts.at(group + 1);
11499 if (group == kWeakICGroup) {
11500 return CodeListContains(object_at(start), code);
11501 }
11502 for (int i = start; i < end; i++) {
11503 if (object_at(i) == code) return true;
11504 }
11505 return false;
11506}
11507
11508
11509bool DependentCode::MarkCodeForDeoptimization(
11510 Isolate* isolate,
11511 DependentCode::DependencyGroup group) {
11512 DisallowHeapAllocation no_allocation_scope;
11513 DependentCode::GroupStartIndexes starts(this);
11514 int start = starts.at(group);
11515 int end = starts.at(group + 1);
11516 int code_entries = starts.number_of_entries();
11517 if (start == end) return false;
11518
11519 // Mark all the code that needs to be deoptimized.
11520 bool marked = false;
11521 for (int i = start; i < end; i++) {
11522 if (is_code_at(i)) {
11523 Code* code = code_at(i);
11524 if (!code->marked_for_deoptimization()) {
11525 SetMarkedForDeoptimization(code, group);
11526 marked = true;
11527 }
11528 } else {
11529 CompilationInfo* info = compilation_info_at(i);
11530 info->AbortDueToDependencyChange();
11531 }
11532 }
11533 // Compact the array by moving all subsequent groups to fill in the new holes.
11534 for (int src = end, dst = start; src < code_entries; src++, dst++) {
11535 copy(src, dst);
11536 }
11537 // Now the holes are at the end of the array, zap them for heap-verifier.
11538 int removed = end - start;
11539 for (int i = code_entries - removed; i < code_entries; i++) {
11540 clear_at(i);
11541 }
11542 set_number_of_entries(group, 0);
11543 return marked;
11544}
11545
11546
11547void DependentCode::DeoptimizeDependentCodeGroup(
11548 Isolate* isolate,
11549 DependentCode::DependencyGroup group) {
11550 DCHECK(AllowCodeDependencyChange::IsAllowed());
11551 DisallowHeapAllocation no_allocation_scope;
11552 bool marked = MarkCodeForDeoptimization(isolate, group);
11553
11554 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
11555}
11556
11557
11558void DependentCode::AddToDependentICList(Handle<Code> stub) {
11559 DisallowHeapAllocation no_heap_allocation;
11560 GroupStartIndexes starts(this);
11561 int i = starts.at(kWeakICGroup);
11562 Object* head = object_at(i);
11563 // Try to insert the stub after the head of the list to minimize number of
11564 // writes to the DependentCode array, since a write to the array can make it
11565 // strong if it was alread marked by incremental marker.
11566 if (head->IsCode()) {
11567 stub->set_next_code_link(Code::cast(head)->next_code_link());
11568 Code::cast(head)->set_next_code_link(*stub);
11569 } else {
11570 stub->set_next_code_link(head);
11571 set_object_at(i, *stub);
11572 }
11573}
11574
11575
11576void DependentCode::SetMarkedForDeoptimization(Code* code,
11577 DependencyGroup group) {
11578 code->set_marked_for_deoptimization(true);
11579 if (FLAG_trace_deopt &&
11580 (code->deoptimization_data() != code->GetHeap()->empty_fixed_array())) {
11581 DeoptimizationInputData* deopt_data =
11582 DeoptimizationInputData::cast(code->deoptimization_data());
11583 CodeTracer::Scope scope(code->GetHeap()->isolate()->GetCodeTracer());
11584 PrintF(scope.file(), "[marking dependent code 0x%08" V8PRIxPTR
11585 " (opt #%d) for deoptimization, reason: %s]\n",
11586 reinterpret_cast<intptr_t>(code),
11587 deopt_data->OptimizationId()->value(), DependencyGroupName(group));
11588 }
11589}
11590
11591
11592const char* DependentCode::DependencyGroupName(DependencyGroup group) {
11593 switch (group) {
11594 case kWeakICGroup:
11595 return "weak-ic";
11596 case kWeakCodeGroup:
11597 return "weak-code";
11598 case kTransitionGroup:
11599 return "transition";
11600 case kPrototypeCheckGroup:
11601 return "prototype-check";
11602 case kElementsCantBeAddedGroup:
11603 return "elements-cant-be-added";
11604 case kPropertyCellChangedGroup:
11605 return "property-cell-changed";
11606 case kFieldTypeGroup:
11607 return "field-type";
11608 case kInitialMapChangedGroup:
11609 return "initial-map-changed";
11610 case kAllocationSiteTenuringChangedGroup:
11611 return "allocation-site-tenuring-changed";
11612 case kAllocationSiteTransitionChangedGroup:
11613 return "allocation-site-transition-changed";
11614 }
11615 UNREACHABLE();
11616 return "?";
11617}
11618
11619
11620Handle<Map> Map::TransitionToPrototype(Handle<Map> map,
11621 Handle<Object> prototype) {
11622 Handle<Map> new_map = GetPrototypeTransition(map, prototype);
11623 if (new_map.is_null()) {
11624 new_map = Copy(map);
11625 PutPrototypeTransition(map, prototype, new_map);
11626 new_map->set_prototype(*prototype);
11627 }
11628 return new_map;
11629}
11630
11631
11632MaybeHandle<Object> JSObject::SetPrototype(Handle<JSObject> object,
11633 Handle<Object> value,
11634 bool from_javascript) {
11635#ifdef DEBUG
11636 int size = object->Size();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011637#endif
11638
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011639 Isolate* isolate = object->GetIsolate();
11640 Heap* heap = isolate->heap();
Andrei Popescu402d9372010-02-26 13:31:12 +000011641 // Silently ignore the change if value is not a JSObject or null.
11642 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011643 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +000011644
Ben Murdoch8b112d22011-06-08 16:22:53 +010011645 // From 8.6.2 Object Internal Methods
11646 // ...
11647 // In addition, if [[Extensible]] is false the value of the [[Class]] and
11648 // [[Prototype]] internal properties of the object may not be modified.
11649 // ...
11650 // Implementation specific extensions that modify [[Class]], [[Prototype]]
11651 // or [[Extensible]] must not violate the invariants defined in the preceding
11652 // paragraph.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011653 if (!object->map()->is_extensible()) {
11654 Handle<Object> args[] = { object };
11655 THROW_NEW_ERROR(isolate, NewTypeError("non_extensible_proto",
11656 HandleVector(args, arraysize(args))),
11657 Object);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011658 }
11659
Andrei Popescu402d9372010-02-26 13:31:12 +000011660 // Before we can set the prototype we need to be sure
11661 // prototype cycles are prevented.
11662 // It is sufficient to validate that the receiver is not in the new prototype
11663 // chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011664 for (PrototypeIterator iter(isolate, *value,
11665 PrototypeIterator::START_AT_RECEIVER);
11666 !iter.IsAtEnd(); iter.Advance()) {
11667 if (JSReceiver::cast(iter.GetCurrent()) == *object) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011668 // Cycle detected.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011669 THROW_NEW_ERROR(isolate,
11670 NewError("cyclic_proto", HandleVector<Object>(NULL, 0)),
11671 Object);
Andrei Popescu402d9372010-02-26 13:31:12 +000011672 }
11673 }
11674
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011675 bool dictionary_elements_in_chain =
11676 object->map()->DictionaryElementsInPrototypeChainOnly();
11677 Handle<JSObject> real_receiver = object;
Andrei Popescu402d9372010-02-26 13:31:12 +000011678
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011679 if (from_javascript) {
Andrei Popescu402d9372010-02-26 13:31:12 +000011680 // Find the first object in the chain whose prototype object is not
11681 // hidden and set the new prototype on that object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011682 PrototypeIterator iter(isolate, real_receiver);
11683 while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
11684 real_receiver =
11685 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
11686 iter.Advance();
Andrei Popescu402d9372010-02-26 13:31:12 +000011687 }
11688 }
11689
11690 // Set the new prototype of the object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011691 Handle<Map> map(real_receiver->map());
Steve Block053d10c2011-06-13 19:13:29 +010011692
11693 // Nothing to do if prototype is already set.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011694 if (map->prototype() == *value) return value;
Steve Block053d10c2011-06-13 19:13:29 +010011695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011696 if (value->IsJSObject()) {
11697 PrototypeOptimizationMode mode =
11698 from_javascript ? REGULAR_PROTOTYPE : FAST_PROTOTYPE;
11699 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value), mode);
John Reck59135872010-11-02 12:39:01 -070011700 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011701
11702 Handle<Map> new_map = Map::TransitionToPrototype(map, value);
11703 DCHECK(new_map->prototype() == *value);
11704 JSObject::MigrateToMap(real_receiver, new_map);
11705
11706 if (!dictionary_elements_in_chain &&
11707 new_map->DictionaryElementsInPrototypeChainOnly()) {
11708 // If the prototype chain didn't previously have element callbacks, then
11709 // KeyedStoreICs need to be cleared to ensure any that involve this
11710 // map go generic.
11711 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
11712 }
Andrei Popescu402d9372010-02-26 13:31:12 +000011713
Steve Block44f0eee2011-05-26 01:26:41 +010011714 heap->ClearInstanceofCache();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011715 DCHECK(size == object->Size());
Andrei Popescu402d9372010-02-26 13:31:12 +000011716 return value;
11717}
11718
11719
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011720void JSObject::EnsureCanContainElements(Handle<JSObject> object,
11721 Arguments* args,
11722 uint32_t first_arg,
11723 uint32_t arg_count,
11724 EnsureElementsMode mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011725 // Elements in |Arguments| are ordered backwards (because they're on the
11726 // stack), but the method that's called here iterates over them in forward
11727 // direction.
11728 return EnsureCanContainElements(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011729 object, args->arguments() - first_arg - (arg_count - 1), arg_count, mode);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000011730}
11731
11732
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011733MaybeHandle<AccessorPair> JSObject::GetOwnElementAccessorPair(
11734 Handle<JSObject> object,
11735 uint32_t index) {
11736 if (object->IsJSGlobalProxy()) {
11737 PrototypeIterator iter(object->GetIsolate(), object);
11738 if (iter.IsAtEnd()) return MaybeHandle<AccessorPair>();
11739 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
11740 return GetOwnElementAccessorPair(
11741 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
11742 }
11743
11744 // Check for lookup interceptor.
11745 if (object->HasIndexedInterceptor()) return MaybeHandle<AccessorPair>();
11746
11747 return object->GetElementsAccessor()->GetAccessorPair(object, object, index);
11748}
11749
11750
11751MaybeHandle<Object> JSObject::SetElementWithInterceptor(
11752 Handle<JSObject> object,
11753 uint32_t index,
11754 Handle<Object> value,
11755 PropertyAttributes attributes,
11756 StrictMode strict_mode,
11757 bool check_prototype,
11758 SetPropertyMode set_mode) {
11759 Isolate* isolate = object->GetIsolate();
11760
Steve Blocka7e24c12009-10-30 11:49:00 +000011761 // Make sure that the top context does not change when doing
11762 // callbacks or interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011763 AssertNoContextChange ncc(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011764
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011765 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +000011766 if (!interceptor->setter()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011767 v8::IndexedPropertySetterCallback setter =
11768 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +010011769 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011770 ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index));
11771 PropertyCallbackArguments args(isolate, interceptor->data(), *object,
11772 *object);
11773 v8::Handle<v8::Value> result =
11774 args.Call(setter, index, v8::Utils::ToLocal(value));
11775 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
11776 if (!result.IsEmpty()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +000011777 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011778
11779 return SetElementWithoutInterceptor(object, index, value, attributes,
11780 strict_mode,
11781 check_prototype,
11782 set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000011783}
11784
11785
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011786MaybeHandle<Object> JSObject::GetElementWithCallback(
11787 Handle<JSObject> object,
11788 Handle<Object> receiver,
11789 Handle<Object> structure,
11790 uint32_t index,
11791 Handle<Object> holder) {
11792 Isolate* isolate = object->GetIsolate();
11793 DCHECK(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +010011794 // api style callbacks.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011795 if (structure->IsExecutableAccessorInfo()) {
11796 Handle<ExecutableAccessorInfo> data =
11797 Handle<ExecutableAccessorInfo>::cast(structure);
Leon Clarkef7060e22010-06-03 12:02:55 +010011798 Object* fun_obj = data->getter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011799 v8::AccessorNameGetterCallback call_fun =
11800 v8::ToCData<v8::AccessorNameGetterCallback>(fun_obj);
11801 if (call_fun == NULL) return isolate->factory()->undefined_value();
11802 Handle<JSObject> holder_handle = Handle<JSObject>::cast(holder);
Steve Block44f0eee2011-05-26 01:26:41 +010011803 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011804 Handle<String> key = isolate->factory()->NumberToString(number);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011805 LOG(isolate, ApiNamedPropertyAccess("load", *holder_handle, *key));
11806 PropertyCallbackArguments
11807 args(isolate, data->data(), *receiver, *holder_handle);
11808 v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key));
11809 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
11810 if (result.IsEmpty()) return isolate->factory()->undefined_value();
11811 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
11812 result_internal->VerifyApiCallResultType();
11813 // Rebox handle before return.
11814 return handle(*result_internal, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +010011815 }
11816
11817 // __defineGetter__ callback
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011818 if (structure->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011819 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
11820 isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011821 if (getter->IsSpecFunction()) {
11822 // TODO(rossberg): nicer would be to cast to some JSCallable here...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011823 return GetPropertyWithDefinedGetter(
11824 receiver, Handle<JSReceiver>::cast(getter));
Leon Clarkef7060e22010-06-03 12:02:55 +010011825 }
11826 // Getter is not a function.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011827 return isolate->factory()->undefined_value();
11828 }
11829
11830 if (structure->IsDeclaredAccessorInfo()) {
11831 return GetDeclaredAccessorProperty(
11832 receiver, Handle<DeclaredAccessorInfo>::cast(structure), isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +010011833 }
11834
11835 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011836 return MaybeHandle<Object>();
Leon Clarkef7060e22010-06-03 12:02:55 +010011837}
11838
11839
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011840MaybeHandle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
11841 Handle<Object> structure,
11842 uint32_t index,
11843 Handle<Object> value,
11844 Handle<JSObject> holder,
11845 StrictMode strict_mode) {
11846 Isolate* isolate = object->GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +010011847
11848 // We should never get here to initialize a const with the hole
11849 // value since a const declaration would conflict with the setter.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011850 DCHECK(!value->IsTheHole());
11851 DCHECK(!structure->IsForeign());
11852 if (structure->IsExecutableAccessorInfo()) {
Leon Clarkef7060e22010-06-03 12:02:55 +010011853 // api style callbacks
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011854 Handle<ExecutableAccessorInfo> data =
11855 Handle<ExecutableAccessorInfo>::cast(structure);
Leon Clarkef7060e22010-06-03 12:02:55 +010011856 Object* call_obj = data->setter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011857 v8::AccessorNameSetterCallback call_fun =
11858 v8::ToCData<v8::AccessorNameSetterCallback>(call_obj);
Leon Clarkef7060e22010-06-03 12:02:55 +010011859 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +010011860 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11861 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011862 LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
11863 PropertyCallbackArguments
11864 args(isolate, data->data(), *object, *holder);
11865 args.Call(call_fun,
11866 v8::Utils::ToLocal(key),
11867 v8::Utils::ToLocal(value));
11868 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
11869 return value;
Leon Clarkef7060e22010-06-03 12:02:55 +010011870 }
11871
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011872 if (structure->IsAccessorPair()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011873 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011874 if (setter->IsSpecFunction()) {
11875 // TODO(rossberg): nicer would be to cast to some JSCallable here...
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011876 return SetPropertyWithDefinedSetter(
11877 object, Handle<JSReceiver>::cast(setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +010011878 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011879 if (strict_mode == SLOPPY) return value;
Steve Block44f0eee2011-05-26 01:26:41 +010011880 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011881 Handle<Object> args[2] = { key, holder };
11882 THROW_NEW_ERROR(
11883 isolate, NewTypeError("no_setter_in_callback", HandleVector(args, 2)),
11884 Object);
Leon Clarkef7060e22010-06-03 12:02:55 +010011885 }
11886 }
11887
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011888 // TODO(dcarney): Handle correctly.
11889 if (structure->IsDeclaredAccessorInfo()) return value;
11890
Leon Clarkef7060e22010-06-03 12:02:55 +010011891 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011892 return MaybeHandle<Object>();
Leon Clarkef7060e22010-06-03 12:02:55 +010011893}
11894
11895
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011896bool JSObject::HasFastArgumentsElements() {
11897 Heap* heap = GetHeap();
11898 if (!elements()->IsFixedArray()) return false;
11899 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011900 if (elements->map() != heap->sloppy_arguments_elements_map()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011901 return false;
11902 }
11903 FixedArray* arguments = FixedArray::cast(elements->get(1));
11904 return !arguments->IsDictionary();
11905}
11906
11907
11908bool JSObject::HasDictionaryArgumentsElements() {
11909 Heap* heap = GetHeap();
11910 if (!elements()->IsFixedArray()) return false;
11911 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011912 if (elements->map() != heap->sloppy_arguments_elements_map()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011913 return false;
11914 }
11915 FixedArray* arguments = FixedArray::cast(elements->get(1));
11916 return arguments->IsDictionary();
11917}
11918
11919
Steve Blocka7e24c12009-10-30 11:49:00 +000011920// Adding n elements in fast case is O(n*n).
11921// Note: revisit design to have dual undefined values to capture absent
11922// elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011923MaybeHandle<Object> JSObject::SetFastElement(Handle<JSObject> object,
11924 uint32_t index,
11925 Handle<Object> value,
11926 StrictMode strict_mode,
11927 bool check_prototype) {
11928 DCHECK(object->HasFastSmiOrObjectElements() ||
11929 object->HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000011930
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011931 Isolate* isolate = object->GetIsolate();
11932
11933 // Array optimizations rely on the prototype lookups of Array objects always
11934 // returning undefined. If there is a store to the initial prototype object,
11935 // make sure all of these optimizations are invalidated.
11936 if (isolate->is_initial_object_prototype(*object) ||
11937 isolate->is_initial_array_prototype(*object)) {
11938 object->map()->dependent_code()->DeoptimizeDependentCodeGroup(isolate,
11939 DependentCode::kElementsCantBeAddedGroup);
11940 }
11941
11942 Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
11943 if (backing_store->map() ==
11944 isolate->heap()->sloppy_arguments_elements_map()) {
11945 backing_store = handle(FixedArray::cast(backing_store->get(1)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011946 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011947 backing_store = EnsureWritableFastElements(object);
John Reck59135872010-11-02 12:39:01 -070011948 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011949 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000011950
Steve Block9fac8402011-05-12 15:51:54 +010011951 if (check_prototype &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011952 (index >= capacity || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +010011953 bool found;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011954 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
11955 object, index, value, &found, strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +010011956 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000011957 }
11958
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011959 uint32_t new_capacity = capacity;
11960 // Check if the length property of this object needs to be updated.
11961 uint32_t array_length = 0;
11962 bool must_update_array_length = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011963 bool introduces_holes = true;
11964 if (object->IsJSArray()) {
11965 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
11966 introduces_holes = index > array_length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011967 if (index >= array_length) {
11968 must_update_array_length = true;
11969 array_length = index + 1;
11970 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011971 } else {
11972 introduces_holes = index >= capacity;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011973 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011974
11975 // If the array is growing, and it's not growth by a single element at the
11976 // end, make sure that the ElementsKind is HOLEY.
11977 ElementsKind elements_kind = object->GetElementsKind();
11978 if (introduces_holes &&
11979 IsFastElementsKind(elements_kind) &&
11980 !IsFastHoleyElementsKind(elements_kind)) {
11981 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
11982 TransitionElementsKind(object, transitioned_kind);
11983 }
11984
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011985 // Check if the capacity of the backing store needs to be increased, or if
11986 // a transition to slow elements is necessary.
11987 if (index >= capacity) {
11988 bool convert_to_slow = true;
11989 if ((index - capacity) < kMaxGap) {
11990 new_capacity = NewElementsCapacity(index + 1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011991 DCHECK(new_capacity > index);
11992 if (!object->ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011993 convert_to_slow = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011994 }
11995 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011996 if (convert_to_slow) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000011997 NormalizeElements(object);
11998 return SetDictionaryElement(object, index, value, NONE, strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011999 check_prototype);
Ben Murdoch592a9fc2012-03-05 11:04:45 +000012000 }
12001 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012002 // Convert to fast double elements if appropriate.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012003 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
12004 // Consider fixing the boilerplate as well if we have one.
12005 ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
12006 ? FAST_HOLEY_DOUBLE_ELEMENTS
12007 : FAST_DOUBLE_ELEMENTS;
12008
12009 UpdateAllocationSite(object, to_kind);
12010
12011 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length);
12012 FixedDoubleArray::cast(object->elements())->set(index, value->Number());
12013 JSObject::ValidateElements(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012014 return value;
12015 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012016 // Change elements kind from Smi-only to generic FAST if necessary.
12017 if (object->HasFastSmiElements() && !value->IsSmi()) {
12018 ElementsKind kind = object->HasFastHoleyElements()
12019 ? FAST_HOLEY_ELEMENTS
12020 : FAST_ELEMENTS;
12021
12022 UpdateAllocationSite(object, kind);
12023 Handle<Map> new_map = GetElementsTransitionMap(object, kind);
12024 JSObject::MigrateToMap(object, new_map);
12025 DCHECK(IsFastObjectElementsKind(object->GetElementsKind()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012026 }
12027 // Increase backing store capacity if that's been decided previously.
12028 if (new_capacity != capacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012029 SetFastElementsCapacitySmiMode smi_mode =
12030 value->IsSmi() && object->HasFastSmiElements()
12031 ? kAllowSmiElements
12032 : kDontAllowSmiElements;
12033 Handle<FixedArray> new_elements =
12034 SetFastElementsCapacityAndLength(object, new_capacity, array_length,
12035 smi_mode);
12036 new_elements->set(index, *value);
12037 JSObject::ValidateElements(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012038 return value;
12039 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012040
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012041 // Finally, set the new element and length.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012042 DCHECK(object->elements()->IsFixedArray());
12043 backing_store->set(index, *value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012044 if (must_update_array_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012045 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012046 }
12047 return value;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012048}
12049
12050
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012051MaybeHandle<Object> JSObject::SetDictionaryElement(
12052 Handle<JSObject> object,
12053 uint32_t index,
12054 Handle<Object> value,
12055 PropertyAttributes attributes,
12056 StrictMode strict_mode,
12057 bool check_prototype,
12058 SetPropertyMode set_mode) {
12059 DCHECK(object->HasDictionaryElements() ||
12060 object->HasDictionaryArgumentsElements());
12061 Isolate* isolate = object->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012062
12063 // Insert element in the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012064 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012065 bool is_arguments =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012066 (elements->map() == isolate->heap()->sloppy_arguments_elements_map());
12067 Handle<SeededNumberDictionary> dictionary(is_arguments
12068 ? SeededNumberDictionary::cast(elements->get(1))
12069 : SeededNumberDictionary::cast(*elements));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012070
12071 int entry = dictionary->FindEntry(index);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012072 if (entry != SeededNumberDictionary::kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012073 Handle<Object> element(dictionary->ValueAt(entry), isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012074 PropertyDetails details = dictionary->DetailsAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012075 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012076 return SetElementWithCallback(object, element, index, value, object,
12077 strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012078 } else {
12079 dictionary->UpdateMaxNumberKey(index);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012080 // If a value has not been initialized we allow writing to it even if it
12081 // is read-only (a declared const that has not been initialized). If a
12082 // value is being defined we skip attribute checks completely.
12083 if (set_mode == DEFINE_PROPERTY) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012084 details = PropertyDetails(
12085 attributes, NORMAL, details.dictionary_index());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012086 dictionary->DetailsAtPut(entry, details);
12087 } else if (details.IsReadOnly() && !element->IsTheHole()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012088 if (strict_mode == SLOPPY) {
12089 return isolate->factory()->undefined_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012090 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012091 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012092 Handle<Object> args[2] = { number, object };
12093 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
12094 HandleVector(args, 2)),
12095 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012096 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012097 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012098 // Elements of the arguments object in slow mode might be slow aliases.
12099 if (is_arguments && element->IsAliasedArgumentsEntry()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012100 Handle<AliasedArgumentsEntry> entry =
12101 Handle<AliasedArgumentsEntry>::cast(element);
12102 Handle<Context> context(Context::cast(elements->get(0)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012103 int context_index = entry->aliased_context_slot();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012104 DCHECK(!context->get(context_index)->IsTheHole());
12105 context->set(context_index, *value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012106 // For elements that are still writable we keep slow aliasing.
12107 if (!details.IsReadOnly()) value = element;
12108 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012109 dictionary->ValueAtPut(entry, *value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012110 }
12111 } else {
12112 // Index not already used. Look for an accessor in the prototype chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012113 // Can cause GC!
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012114 if (check_prototype) {
12115 bool found;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012116 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12117 object, index, value, &found, strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012118 if (found) return result;
12119 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012120
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012121 // When we set the is_extensible flag to false we always force the
12122 // element into dictionary mode (and force them to stay there).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012123 if (!object->map()->is_extensible()) {
12124 if (strict_mode == SLOPPY) {
12125 return isolate->factory()->undefined_value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012126 } else {
12127 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12128 Handle<String> name = isolate->factory()->NumberToString(number);
12129 Handle<Object> args[1] = { name };
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012130 THROW_NEW_ERROR(isolate, NewTypeError("object_not_extensible",
12131 HandleVector(args, 1)),
12132 Object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012133 }
12134 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012135
12136 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
12137 Handle<SeededNumberDictionary> new_dictionary =
12138 SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
12139 details);
12140 if (*dictionary != *new_dictionary) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012141 if (is_arguments) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012142 elements->set(1, *new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012143 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012144 object->set_elements(*new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012145 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012146 dictionary = new_dictionary;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012147 }
12148 }
12149
12150 // Update the array length if this JSObject is an array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012151 if (object->IsJSArray()) {
12152 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index,
12153 value);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012154 }
12155
12156 // Attempt to put this object back in fast case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012157 if (object->ShouldConvertToFastElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012158 uint32_t new_length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012159 if (object->IsJSArray()) {
12160 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012161 } else {
12162 new_length = dictionary->max_number_key() + 1;
12163 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012164 bool has_smi_only_elements = false;
12165 bool should_convert_to_fast_double_elements =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012166 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
12167 SetFastElementsCapacitySmiMode smi_mode =
12168 has_smi_only_elements ? kForceSmiElements : kAllowSmiElements;
12169
12170 if (should_convert_to_fast_double_elements) {
12171 SetFastDoubleElementsCapacityAndLength(object, new_length, new_length);
12172 } else {
12173 SetFastElementsCapacityAndLength(object, new_length, new_length,
12174 smi_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012175 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012176 JSObject::ValidateElements(object);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012177#ifdef DEBUG
12178 if (FLAG_trace_normalization) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012179 OFStream os(stdout);
12180 os << "Object elements are fast case again:\n";
12181 object->Print(os);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012182 }
12183#endif
12184 }
12185 return value;
12186}
12187
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012188MaybeHandle<Object> JSObject::SetFastDoubleElement(
12189 Handle<JSObject> object,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012190 uint32_t index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012191 Handle<Object> value,
12192 StrictMode strict_mode,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012193 bool check_prototype) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012194 DCHECK(object->HasFastDoubleElements());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012195
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012196 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012197 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012198
12199 // If storing to an element that isn't in the array, pass the store request
12200 // up the prototype chain before storing in the receiver's elements.
12201 if (check_prototype &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012202 (index >= elms_length ||
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012203 Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012204 bool found;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012205 MaybeHandle<Object> result = SetElementWithCallbackSetterInPrototypes(
12206 object, index, value, &found, strict_mode);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012207 if (found) return result;
12208 }
12209
12210 // If the value object is not a heap number, switch to fast elements and try
12211 // again.
12212 bool value_is_smi = value->IsSmi();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012213 bool introduces_holes = true;
12214 uint32_t length = elms_length;
12215 if (object->IsJSArray()) {
12216 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length));
12217 introduces_holes = index > length;
12218 } else {
12219 introduces_holes = index >= elms_length;
12220 }
12221
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012222 if (!value->IsNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012223 SetFastElementsCapacityAndLength(object, elms_length, length,
12224 kDontAllowSmiElements);
12225 Handle<Object> result;
12226 ASSIGN_RETURN_ON_EXCEPTION(
12227 object->GetIsolate(), result,
12228 SetFastElement(object, index, value, strict_mode, check_prototype),
12229 Object);
12230 JSObject::ValidateElements(object);
12231 return result;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012232 }
12233
12234 double double_value = value_is_smi
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012235 ? static_cast<double>(Handle<Smi>::cast(value)->value())
12236 : Handle<HeapNumber>::cast(value)->value();
12237
12238 // If the array is growing, and it's not growth by a single element at the
12239 // end, make sure that the ElementsKind is HOLEY.
12240 ElementsKind elements_kind = object->GetElementsKind();
12241 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
12242 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12243 TransitionElementsKind(object, transitioned_kind);
12244 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012245
12246 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +000012247 if (index < elms_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012248 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012249 elms->set(index, double_value);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012250 if (object->IsJSArray()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012251 // Update the length of the array if needed.
12252 uint32_t array_length = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012253 CHECK(
12254 Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +000012255 if (index >= array_length) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012256 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +000012257 }
12258 }
12259 return value;
12260 }
12261
12262 // Allow gap in fast case.
12263 if ((index - elms_length) < kMaxGap) {
12264 // Try allocating extra space.
12265 int new_capacity = NewElementsCapacity(index+1);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012266 if (!object->ShouldConvertToSlowElements(new_capacity)) {
12267 DCHECK(static_cast<uint32_t>(new_capacity) > index);
12268 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1);
12269 FixedDoubleArray::cast(object->elements())->set(index, double_value);
12270 JSObject::ValidateElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000012271 return value;
12272 }
12273 }
12274
12275 // Otherwise default to slow case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012276 DCHECK(object->HasFastDoubleElements());
12277 DCHECK(object->map()->has_fast_double_elements());
12278 DCHECK(object->elements()->IsFixedDoubleArray() ||
12279 object->elements()->length() == 0);
12280
12281 NormalizeElements(object);
12282 DCHECK(object->HasDictionaryElements());
12283 return SetElement(object, index, value, NONE, strict_mode, check_prototype);
12284}
12285
12286
12287MaybeHandle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
12288 uint32_t index,
12289 Handle<Object> value,
12290 PropertyAttributes attributes,
12291 StrictMode strict_mode) {
12292 if (object->IsJSProxy()) {
12293 return JSProxy::SetElementWithHandler(
12294 Handle<JSProxy>::cast(object), object, index, value, strict_mode);
John Reck59135872010-11-02 12:39:01 -070012295 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012296 return JSObject::SetElement(
12297 Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012298}
12299
12300
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012301MaybeHandle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
12302 uint32_t index,
12303 Handle<Object> value,
12304 StrictMode strict_mode) {
12305 DCHECK(!object->HasExternalArrayElements());
12306 return JSObject::SetElement(object, index, value, NONE, strict_mode, false);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012307}
12308
12309
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012310MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
12311 uint32_t index,
12312 Handle<Object> value,
12313 PropertyAttributes attributes,
12314 StrictMode strict_mode,
12315 bool check_prototype,
12316 SetPropertyMode set_mode) {
12317 Isolate* isolate = object->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012318
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012319 if (object->HasExternalArrayElements() ||
12320 object->HasFixedTypedArrayElements()) {
12321 if (!value->IsNumber() && !value->IsUndefined()) {
12322 ASSIGN_RETURN_ON_EXCEPTION(
12323 isolate, value,
12324 Execution::ToNumber(isolate, value), Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012325 }
12326 }
Ben Murdochc7cc0282012-03-05 14:35:55 +000012327
Steve Blocka7e24c12009-10-30 11:49:00 +000012328 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012329 if (object->IsAccessCheckNeeded()) {
12330 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_SET)) {
12331 isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
12332 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12333 return value;
Ben Murdoch8b112d22011-06-08 16:22:53 +010012334 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012335 }
12336
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012337 if (object->IsJSGlobalProxy()) {
12338 PrototypeIterator iter(isolate, object);
12339 if (iter.IsAtEnd()) return value;
12340 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
12341 return SetElement(
12342 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index,
12343 value, attributes, strict_mode, check_prototype, set_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012344 }
12345
12346 // Don't allow element properties to be redefined for external arrays.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012347 if ((object->HasExternalArrayElements() ||
12348 object->HasFixedTypedArrayElements()) &&
12349 set_mode == DEFINE_PROPERTY) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012350 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012351 Handle<Object> args[] = { object, number };
12352 THROW_NEW_ERROR(isolate, NewTypeError("redef_external_array_element",
12353 HandleVector(args, arraysize(args))),
12354 Object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012355 }
12356
12357 // Normalize the elements to enable attributes on the property.
12358 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012359 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012360 // Make sure that we never go back to fast case.
12361 dictionary->set_requires_slow_elements();
Steve Blocka7e24c12009-10-30 11:49:00 +000012362 }
12363
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012364 if (!object->map()->is_observed()) {
12365 return object->HasIndexedInterceptor()
12366 ? SetElementWithInterceptor(object, index, value, attributes,
12367 strict_mode, check_prototype, set_mode)
12368 : SetElementWithoutInterceptor(object, index, value, attributes,
12369 strict_mode, check_prototype, set_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000012370 }
12371
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012372 Maybe<PropertyAttributes> maybe =
12373 JSReceiver::GetOwnElementAttribute(object, index);
12374 if (!maybe.has_value) return MaybeHandle<Object>();
12375 PropertyAttributes old_attributes = maybe.value;
12376
12377 Handle<Object> old_value = isolate->factory()->the_hole_value();
12378 Handle<Object> old_length_handle;
12379 Handle<Object> new_length_handle;
12380
12381 if (old_attributes != ABSENT) {
12382 if (GetOwnElementAccessorPair(object, index).is_null()) {
12383 old_value = Object::GetElement(isolate, object, index).ToHandleChecked();
12384 }
12385 } else if (object->IsJSArray()) {
12386 // Store old array length in case adding an element grows the array.
12387 old_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12388 isolate);
12389 }
12390
12391 // Check for lookup interceptor
12392 Handle<Object> result;
12393 ASSIGN_RETURN_ON_EXCEPTION(
12394 isolate, result,
12395 object->HasIndexedInterceptor()
12396 ? SetElementWithInterceptor(
12397 object, index, value, attributes,
12398 strict_mode, check_prototype, set_mode)
12399 : SetElementWithoutInterceptor(
12400 object, index, value, attributes,
12401 strict_mode, check_prototype, set_mode),
12402 Object);
12403
12404 Handle<String> name = isolate->factory()->Uint32ToString(index);
12405 maybe = GetOwnElementAttribute(object, index);
12406 if (!maybe.has_value) return MaybeHandle<Object>();
12407 PropertyAttributes new_attributes = maybe.value;
12408
12409 if (old_attributes == ABSENT) {
12410 if (object->IsJSArray() &&
12411 !old_length_handle->SameValue(
12412 Handle<JSArray>::cast(object)->length())) {
12413 new_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12414 isolate);
12415 uint32_t old_length = 0;
12416 uint32_t new_length = 0;
12417 CHECK(old_length_handle->ToArrayIndex(&old_length));
12418 CHECK(new_length_handle->ToArrayIndex(&new_length));
12419
12420 BeginPerformSplice(Handle<JSArray>::cast(object));
12421 EnqueueChangeRecord(object, "add", name, old_value);
12422 EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
12423 old_length_handle);
12424 EndPerformSplice(Handle<JSArray>::cast(object));
12425 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
12426 EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
12427 new_length - old_length);
12428 } else {
12429 EnqueueChangeRecord(object, "add", name, old_value);
12430 }
12431 } else if (old_value->IsTheHole()) {
12432 EnqueueChangeRecord(object, "reconfigure", name, old_value);
12433 } else {
12434 Handle<Object> new_value =
12435 Object::GetElement(isolate, object, index).ToHandleChecked();
12436 bool value_changed = !old_value->SameValue(*new_value);
12437 if (old_attributes != new_attributes) {
12438 if (!value_changed) old_value = isolate->factory()->the_hole_value();
12439 EnqueueChangeRecord(object, "reconfigure", name, old_value);
12440 } else if (value_changed) {
12441 EnqueueChangeRecord(object, "update", name, old_value);
12442 }
12443 }
12444
12445 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000012446}
12447
12448
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012449MaybeHandle<Object> JSObject::SetElementWithoutInterceptor(
12450 Handle<JSObject> object,
12451 uint32_t index,
12452 Handle<Object> value,
12453 PropertyAttributes attributes,
12454 StrictMode strict_mode,
12455 bool check_prototype,
12456 SetPropertyMode set_mode) {
12457 DCHECK(object->HasDictionaryElements() ||
12458 object->HasDictionaryArgumentsElements() ||
12459 (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
12460 Isolate* isolate = object->GetIsolate();
12461 if (FLAG_trace_external_array_abuse &&
12462 IsExternalArrayElementsKind(object->GetElementsKind())) {
12463 CheckArrayAbuse(object, "external elements write", index);
12464 }
12465 if (FLAG_trace_js_array_abuse &&
12466 !IsExternalArrayElementsKind(object->GetElementsKind())) {
12467 if (object->IsJSArray()) {
12468 CheckArrayAbuse(object, "elements write", index, true);
12469 }
12470 }
12471 if (object->IsJSArray() && JSArray::WouldChangeReadOnlyLength(
12472 Handle<JSArray>::cast(object), index)) {
12473 if (strict_mode == SLOPPY) {
12474 return value;
12475 } else {
12476 return JSArray::ReadOnlyLengthError(Handle<JSArray>::cast(object));
12477 }
12478 }
12479 switch (object->GetElementsKind()) {
12480 case FAST_SMI_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +000012481 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012482 case FAST_HOLEY_SMI_ELEMENTS:
12483 case FAST_HOLEY_ELEMENTS:
12484 return SetFastElement(object, index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012485 case FAST_DOUBLE_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012486 case FAST_HOLEY_DOUBLE_ELEMENTS:
12487 return SetFastDoubleElement(object, index, value, strict_mode,
12488 check_prototype);
12489
12490#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12491 case EXTERNAL_##TYPE##_ELEMENTS: { \
12492 Handle<External##Type##Array> array( \
12493 External##Type##Array::cast(object->elements())); \
12494 return External##Type##Array::SetValue(array, index, value); \
12495 } \
12496 case TYPE##_ELEMENTS: { \
12497 Handle<Fixed##Type##Array> array( \
12498 Fixed##Type##Array::cast(object->elements())); \
12499 return Fixed##Type##Array::SetValue(array, index, value); \
Steve Blocka7e24c12009-10-30 11:49:00 +000012500 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012501
12502 TYPED_ARRAYS(TYPED_ARRAY_CASE)
12503
12504#undef TYPED_ARRAY_CASE
12505
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012506 case DICTIONARY_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012507 return SetDictionaryElement(object, index, value, attributes, strict_mode,
12508 check_prototype,
12509 set_mode);
12510 case SLOPPY_ARGUMENTS_ELEMENTS: {
12511 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012512 uint32_t length = parameter_map->length();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012513 Handle<Object> probe = index < length - 2 ?
12514 Handle<Object>(parameter_map->get(index + 2), isolate) :
12515 Handle<Object>();
12516 if (!probe.is_null() && !probe->IsTheHole()) {
12517 Handle<Context> context(Context::cast(parameter_map->get(0)));
12518 int context_index = Handle<Smi>::cast(probe)->value();
12519 DCHECK(!context->get(context_index)->IsTheHole());
12520 context->set(context_index, *value);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012521 // Redefining attributes of an aliased element destroys fast aliasing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012522 if (set_mode == SET_PROPERTY || attributes == NONE) return value;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012523 parameter_map->set_the_hole(index + 2);
12524 // For elements that are still writable we re-establish slow aliasing.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012525 if ((attributes & READ_ONLY) == 0) {
12526 value = Handle<Object>::cast(
12527 isolate->factory()->NewAliasedArgumentsEntry(context_index));
Ben Murdoch85b71792012-04-11 18:30:58 +010012528 }
Ben Murdoch5d4cdbf2012-04-11 10:23:59 +010012529 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012530 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012531 if (arguments->IsDictionary()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012532 return SetDictionaryElement(object, index, value, attributes,
12533 strict_mode,
12534 check_prototype,
12535 set_mode);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012536 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012537 return SetFastElement(object, index, value, strict_mode,
12538 check_prototype);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012539 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012540 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012541 }
12542 // All possible cases have been handled above. Add a return to avoid the
12543 // complaints from the compiler.
12544 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012545 return isolate->factory()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000012546}
12547
12548
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012549const double AllocationSite::kPretenureRatio = 0.85;
12550
12551
12552void AllocationSite::ResetPretenureDecision() {
12553 set_pretenure_decision(kUndecided);
12554 set_memento_found_count(0);
12555 set_memento_create_count(0);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012556}
12557
12558
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012559PretenureFlag AllocationSite::GetPretenureMode() {
12560 PretenureDecision mode = pretenure_decision();
12561 // Zombie objects "decide" to be untenured.
12562 return mode == kTenure ? TENURED : NOT_TENURED;
12563}
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012564
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012565
12566bool AllocationSite::IsNestedSite() {
12567 DCHECK(FLAG_trace_track_allocation_sites);
12568 Object* current = GetHeap()->allocation_sites_list();
12569 while (current->IsAllocationSite()) {
12570 AllocationSite* current_site = AllocationSite::cast(current);
12571 if (current_site->nested_site() == this) {
12572 return true;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012573 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012574 current = current_site->weak_next();
12575 }
12576 return false;
12577}
12578
12579
12580void AllocationSite::DigestTransitionFeedback(Handle<AllocationSite> site,
12581 ElementsKind to_kind) {
12582 Isolate* isolate = site->GetIsolate();
12583
12584 if (site->SitePointsToLiteral() && site->transition_info()->IsJSArray()) {
12585 Handle<JSArray> transition_info =
12586 handle(JSArray::cast(site->transition_info()));
12587 ElementsKind kind = transition_info->GetElementsKind();
12588 // if kind is holey ensure that to_kind is as well.
12589 if (IsHoleyElementsKind(kind)) {
12590 to_kind = GetHoleyElementsKind(to_kind);
12591 }
12592 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
12593 // If the array is huge, it's not likely to be defined in a local
12594 // function, so we shouldn't make new instances of it very often.
12595 uint32_t length = 0;
12596 CHECK(transition_info->length()->ToArrayIndex(&length));
12597 if (length <= kMaximumArrayBytesToPretransition) {
12598 if (FLAG_trace_track_allocation_sites) {
12599 bool is_nested = site->IsNestedSite();
12600 PrintF(
12601 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
12602 reinterpret_cast<void*>(*site),
12603 is_nested ? "(nested)" : "",
12604 ElementsKindToString(kind),
12605 ElementsKindToString(to_kind));
12606 }
12607 JSObject::TransitionElementsKind(transition_info, to_kind);
12608 site->dependent_code()->DeoptimizeDependentCodeGroup(
12609 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
12610 }
12611 }
12612 } else {
12613 ElementsKind kind = site->GetElementsKind();
12614 // if kind is holey ensure that to_kind is as well.
12615 if (IsHoleyElementsKind(kind)) {
12616 to_kind = GetHoleyElementsKind(to_kind);
12617 }
12618 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
12619 if (FLAG_trace_track_allocation_sites) {
12620 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
12621 reinterpret_cast<void*>(*site),
12622 ElementsKindToString(kind),
12623 ElementsKindToString(to_kind));
12624 }
12625 site->SetElementsKind(to_kind);
12626 site->dependent_code()->DeoptimizeDependentCodeGroup(
12627 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
12628 }
12629 }
12630}
12631
12632
12633// static
12634void AllocationSite::AddDependentCompilationInfo(Handle<AllocationSite> site,
12635 Reason reason,
12636 CompilationInfo* info) {
12637 DependentCode::DependencyGroup group = site->ToDependencyGroup(reason);
12638 Handle<DependentCode> dep(site->dependent_code());
12639 Handle<DependentCode> codes =
12640 DependentCode::Insert(dep, group, info->object_wrapper());
12641 if (*codes != site->dependent_code()) site->set_dependent_code(*codes);
12642 info->dependencies(group)->Add(Handle<HeapObject>(*site), info->zone());
12643}
12644
12645
12646const char* AllocationSite::PretenureDecisionName(PretenureDecision decision) {
12647 switch (decision) {
12648 case kUndecided: return "undecided";
12649 case kDontTenure: return "don't tenure";
12650 case kMaybeTenure: return "maybe tenure";
12651 case kTenure: return "tenure";
12652 case kZombie: return "zombie";
12653 default: UNREACHABLE();
12654 }
12655 return NULL;
12656}
12657
12658
12659void JSObject::UpdateAllocationSite(Handle<JSObject> object,
12660 ElementsKind to_kind) {
12661 if (!object->IsJSArray()) return;
12662
12663 Heap* heap = object->GetHeap();
12664 if (!heap->InNewSpace(*object)) return;
12665
12666 Handle<AllocationSite> site;
12667 {
12668 DisallowHeapAllocation no_allocation;
12669
12670 AllocationMemento* memento = heap->FindAllocationMemento(*object);
12671 if (memento == NULL) return;
12672
12673 // Walk through to the Allocation Site
12674 site = handle(memento->GetAllocationSite());
12675 }
12676 AllocationSite::DigestTransitionFeedback(site, to_kind);
12677}
12678
12679
12680void JSObject::TransitionElementsKind(Handle<JSObject> object,
12681 ElementsKind to_kind) {
12682 ElementsKind from_kind = object->map()->elements_kind();
12683
12684 if (IsFastHoleyElementsKind(from_kind)) {
12685 to_kind = GetHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012686 }
12687
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012688 if (from_kind == to_kind) return;
12689 // Don't update the site if to_kind isn't fast
12690 if (IsFastElementsKind(to_kind)) {
12691 UpdateAllocationSite(object, to_kind);
12692 }
12693
12694 Isolate* isolate = object->GetIsolate();
12695 if (object->elements() == isolate->heap()->empty_fixed_array() ||
12696 (IsFastSmiOrObjectElementsKind(from_kind) &&
12697 IsFastSmiOrObjectElementsKind(to_kind)) ||
12698 (from_kind == FAST_DOUBLE_ELEMENTS &&
12699 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
12700 DCHECK(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
12701 // No change is needed to the elements() buffer, the transition
12702 // only requires a map change.
12703 Handle<Map> new_map = GetElementsTransitionMap(object, to_kind);
12704 MigrateToMap(object, new_map);
12705 if (FLAG_trace_elements_transitions) {
12706 Handle<FixedArrayBase> elms(object->elements());
12707 PrintElementsTransition(stdout, object, from_kind, elms, to_kind, elms);
12708 }
12709 return;
12710 }
12711
12712 Handle<FixedArrayBase> elms(object->elements());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012713 uint32_t capacity = static_cast<uint32_t>(elms->length());
12714 uint32_t length = capacity;
12715
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012716 if (object->IsJSArray()) {
12717 Object* raw_length = Handle<JSArray>::cast(object)->length();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012718 if (raw_length->IsUndefined()) {
12719 // If length is undefined, then JSArray is being initialized and has no
12720 // elements, assume a length of zero.
12721 length = 0;
12722 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012723 CHECK(raw_length->ToArrayIndex(&length));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012724 }
12725 }
12726
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012727 if (IsFastSmiElementsKind(from_kind) &&
12728 IsFastDoubleElementsKind(to_kind)) {
12729 SetFastDoubleElementsCapacityAndLength(object, capacity, length);
12730 JSObject::ValidateElements(object);
12731 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012732 }
12733
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012734 if (IsFastDoubleElementsKind(from_kind) &&
12735 IsFastObjectElementsKind(to_kind)) {
12736 SetFastElementsCapacityAndLength(object, capacity, length,
12737 kDontAllowSmiElements);
12738 JSObject::ValidateElements(object);
12739 return;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012740 }
12741
12742 // This method should never be called for any other case than the ones
12743 // handled above.
12744 UNREACHABLE();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012745}
12746
12747
12748// static
12749bool Map::IsValidElementsTransition(ElementsKind from_kind,
12750 ElementsKind to_kind) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012751 // Transitions can't go backwards.
12752 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
12753 return false;
12754 }
12755
12756 // Transitions from HOLEY -> PACKED are not allowed.
12757 return !IsFastHoleyElementsKind(from_kind) ||
12758 IsFastHoleyElementsKind(to_kind);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010012759}
12760
12761
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012762void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
12763 uint32_t index,
12764 Handle<Object> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000012765 uint32_t old_len = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012766 CHECK(array->length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +000012767 // Check to see if we need to update the length. For now, we make
12768 // sure that the length stays within 32-bits (unsigned).
12769 if (index >= old_len && index != 0xffffffff) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012770 Handle<Object> len = array->GetIsolate()->factory()->NewNumber(
12771 static_cast<double>(index) + 1);
12772 array->set_length(*len);
Steve Blocka7e24c12009-10-30 11:49:00 +000012773 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012774}
12775
12776
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012777bool JSArray::IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
12778 Isolate* isolate = jsarray_map->GetIsolate();
12779 DCHECK(!jsarray_map->is_dictionary_map());
12780 LookupResult lookup(isolate);
12781 Handle<Name> length_string = isolate->factory()->length_string();
12782 jsarray_map->LookupDescriptor(NULL, *length_string, &lookup);
12783 return lookup.IsReadOnly();
12784}
12785
12786
12787bool JSArray::WouldChangeReadOnlyLength(Handle<JSArray> array,
12788 uint32_t index) {
12789 uint32_t length = 0;
12790 CHECK(array->length()->ToArrayIndex(&length));
12791 if (length <= index) {
12792 LookupIterator it(array, array->GetIsolate()->factory()->length_string(),
12793 LookupIterator::OWN_SKIP_INTERCEPTOR);
12794 CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
12795 CHECK(it.IsFound());
12796 CHECK_EQ(LookupIterator::ACCESSOR, it.state());
12797 return it.IsReadOnly();
12798 }
12799 return false;
12800}
12801
12802
12803MaybeHandle<Object> JSArray::ReadOnlyLengthError(Handle<JSArray> array) {
12804 Isolate* isolate = array->GetIsolate();
12805 Handle<Name> length = isolate->factory()->length_string();
12806 Handle<Object> args[2] = { length, array };
12807 THROW_NEW_ERROR(isolate, NewTypeError("strict_read_only_property",
12808 HandleVector(args, arraysize(args))),
12809 Object);
12810}
12811
12812
12813MaybeHandle<Object> JSObject::GetElementWithInterceptor(
12814 Handle<JSObject> object,
12815 Handle<Object> receiver,
12816 uint32_t index) {
12817 Isolate* isolate = object->GetIsolate();
12818
Steve Blocka7e24c12009-10-30 11:49:00 +000012819 // Make sure that the top context does not change when doing
12820 // callbacks or interceptor calls.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012821 AssertNoContextChange ncc(isolate);
12822
12823 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor(), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012824 if (!interceptor->getter()->IsUndefined()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012825 v8::IndexedPropertyGetterCallback getter =
12826 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +010012827 LOG(isolate,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012828 ApiIndexedPropertyAccess("interceptor-indexed-get", *object, index));
12829 PropertyCallbackArguments
12830 args(isolate, interceptor->data(), *receiver, *object);
12831 v8::Handle<v8::Value> result = args.Call(getter, index);
12832 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
12833 if (!result.IsEmpty()) {
12834 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12835 result_internal->VerifyApiCallResultType();
12836 // Rebox handle before return.
12837 return handle(*result_internal, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000012838 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012839 }
12840
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012841 ElementsAccessor* handler = object->GetElementsAccessor();
12842 Handle<Object> result;
12843 ASSIGN_RETURN_ON_EXCEPTION(
12844 isolate, result, handler->Get(receiver, object, index),
12845 Object);
12846 if (!result->IsTheHole()) return result;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012847
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012848 PrototypeIterator iter(isolate, object);
12849 if (iter.IsAtEnd()) return isolate->factory()->undefined_value();
12850 return Object::GetElementWithReceiver(
12851 isolate, PrototypeIterator::GetCurrent(iter), receiver, index);
Steve Blocka7e24c12009-10-30 11:49:00 +000012852}
12853
12854
12855bool JSObject::HasDenseElements() {
12856 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012857 int used = 0;
12858 GetElementsCapacityAndUsage(&capacity, &used);
12859 return (capacity == 0) || (used > (capacity / 2));
12860}
12861
12862
12863void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
12864 *capacity = 0;
12865 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000012866
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012867 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
12868 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +000012869 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012870 case SLOPPY_ARGUMENTS_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012871 backing_store_base =
12872 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
12873 backing_store = FixedArray::cast(backing_store_base);
12874 if (backing_store->IsDictionary()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000012875 SeededNumberDictionary* dictionary =
12876 SeededNumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012877 *capacity = dictionary->Capacity();
12878 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012879 break;
12880 }
12881 // Fall through.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012882 case FAST_SMI_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012883 case FAST_ELEMENTS:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012884 if (IsJSArray()) {
12885 *capacity = backing_store_base->length();
12886 *used = Smi::cast(JSArray::cast(this)->length())->value();
12887 break;
12888 }
12889 // Fall through if packing is not guaranteed.
12890 case FAST_HOLEY_SMI_ELEMENTS:
12891 case FAST_HOLEY_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012892 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012893 *capacity = backing_store->length();
12894 for (int i = 0; i < *capacity; ++i) {
12895 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012896 }
12897 break;
12898 case DICTIONARY_ELEMENTS: {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012899 SeededNumberDictionary* dictionary = element_dictionary();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012900 *capacity = dictionary->Capacity();
12901 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012902 break;
12903 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012904 case FAST_DOUBLE_ELEMENTS:
12905 if (IsJSArray()) {
12906 *capacity = backing_store_base->length();
12907 *used = Smi::cast(JSArray::cast(this)->length())->value();
12908 break;
12909 }
12910 // Fall through if packing is not guaranteed.
12911 case FAST_HOLEY_DOUBLE_ELEMENTS: {
12912 *capacity = elements()->length();
12913 if (*capacity == 0) break;
12914 FixedDoubleArray * elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012915 for (int i = 0; i < *capacity; i++) {
12916 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +000012917 }
12918 break;
12919 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012920
12921#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
12922 case EXTERNAL_##TYPE##_ELEMENTS: \
12923 case TYPE##_ELEMENTS: \
12924
12925 TYPED_ARRAYS(TYPED_ARRAY_CASE)
12926#undef TYPED_ARRAY_CASE
12927 {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012928 // External arrays are considered 100% used.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012929 FixedArrayBase* external_array = FixedArrayBase::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012930 *capacity = external_array->length();
12931 *used = external_array->length();
12932 break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012933 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012934 }
Steve Blocka7e24c12009-10-30 11:49:00 +000012935}
12936
12937
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012938bool JSObject::WouldConvertToSlowElements(Handle<Object> key) {
12939 uint32_t index;
12940 if (HasFastElements() && key->ToArrayIndex(&index)) {
12941 Handle<FixedArrayBase> backing_store(FixedArrayBase::cast(elements()));
12942 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
12943 if (index >= capacity) {
12944 if ((index - capacity) >= kMaxGap) return true;
12945 uint32_t new_capacity = NewElementsCapacity(index + 1);
12946 return ShouldConvertToSlowElements(new_capacity);
12947 }
12948 }
12949 return false;
12950}
12951
12952
Steve Blocka7e24c12009-10-30 11:49:00 +000012953bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012954 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
12955 kMaxUncheckedFastElementsLength);
12956 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
12957 (new_capacity <= kMaxUncheckedFastElementsLength &&
12958 GetHeap()->InNewSpace(this))) {
12959 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012960 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012961 // If the fast-case backing storage takes up roughly three times as
12962 // much space (in machine words) as a dictionary backing storage
12963 // would, the object should have slow elements.
12964 int old_capacity = 0;
12965 int used_elements = 0;
12966 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdochc7cc0282012-03-05 14:35:55 +000012967 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
12968 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012969 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +000012970}
12971
12972
12973bool JSObject::ShouldConvertToFastElements() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012974 DCHECK(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000012975 // If the elements are sparse, we should not go back to fast case.
12976 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000012977 // An object requiring access checks is never allowed to have fast
12978 // elements. If it had fast elements we would skip security checks.
12979 if (IsAccessCheckNeeded()) return false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012980 // Observed objects may not go to fast mode because they rely on map checks,
12981 // and for fast element accesses we sometimes check element kinds only.
12982 if (map()->is_observed()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012983
12984 FixedArray* elements = FixedArray::cast(this->elements());
Ben Murdochc7cc0282012-03-05 14:35:55 +000012985 SeededNumberDictionary* dictionary = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000012986 if (elements->map() == GetHeap()->sloppy_arguments_elements_map()) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000012987 dictionary = SeededNumberDictionary::cast(elements->get(1));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012988 } else {
Ben Murdochc7cc0282012-03-05 14:35:55 +000012989 dictionary = SeededNumberDictionary::cast(elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000012990 }
12991 // If an element has been added at a very high index in the elements
12992 // dictionary, we cannot go back to fast case.
12993 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000012994 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012995 // space (in machine words) as a fast-case backing storage would,
12996 // the object should have fast elements.
12997 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000012998 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000012999 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +000013000 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013001 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +000013002 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013003 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
Ben Murdochc7cc0282012-03-05 14:35:55 +000013004 SeededNumberDictionary::kEntrySize;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013005 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +000013006}
13007
13008
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013009bool JSObject::ShouldConvertToFastDoubleElements(
13010 bool* has_smi_only_elements) {
13011 *has_smi_only_elements = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013012 if (HasSloppyArgumentsElements()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013013 if (FLAG_unbox_double_arrays) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013014 DCHECK(HasDictionaryElements());
13015 SeededNumberDictionary* dictionary = element_dictionary();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013016 bool found_double = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013017 for (int i = 0; i < dictionary->Capacity(); i++) {
13018 Object* key = dictionary->KeyAt(i);
13019 if (key->IsNumber()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013020 Object* value = dictionary->ValueAt(i);
13021 if (!value->IsNumber()) return false;
13022 if (!value->IsSmi()) {
13023 found_double = true;
13024 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013025 }
13026 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013027 *has_smi_only_elements = !found_double;
13028 return found_double;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013029 } else {
13030 return false;
13031 }
13032}
13033
13034
Steve Blocka7e24c12009-10-30 11:49:00 +000013035// Certain compilers request function template instantiation when they
13036// see the definition of the other template functions in the
13037// class. This requires us to have the template functions put
13038// together, so even though this function belongs in objects-debug.cc,
13039// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +010013040#ifdef OBJECT_PRINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013041template <typename Derived, typename Shape, typename Key>
13042void Dictionary<Derived, Shape, Key>::Print(OStream& os) { // NOLINT
13043 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000013044 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013045 Object* k = DerivedHashTable::KeyAt(i);
13046 if (DerivedHashTable::IsKey(k)) {
13047 os << " ";
Steve Blocka7e24c12009-10-30 11:49:00 +000013048 if (k->IsString()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013049 String::cast(k)->StringPrint(os);
Steve Blocka7e24c12009-10-30 11:49:00 +000013050 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013051 os << Brief(k);
Steve Blocka7e24c12009-10-30 11:49:00 +000013052 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013053 os << ": " << Brief(ValueAt(i)) << "\n";
Steve Blocka7e24c12009-10-30 11:49:00 +000013054 }
13055 }
13056}
13057#endif
13058
13059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013060template<typename Derived, typename Shape, typename Key>
13061void Dictionary<Derived, Shape, Key>::CopyValuesTo(FixedArray* elements) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013062 int pos = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013063 int capacity = DerivedHashTable::Capacity();
13064 DisallowHeapAllocation no_gc;
Leon Clarke4515c472010-02-03 11:58:03 +000013065 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +000013066 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013067 Object* k = Dictionary::KeyAt(i);
13068 if (Dictionary::IsKey(k)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013069 elements->set(pos++, ValueAt(i), mode);
13070 }
13071 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013072 DCHECK(pos == elements->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000013073}
13074
13075
13076InterceptorInfo* JSObject::GetNamedInterceptor() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013077 DCHECK(map()->has_named_interceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +000013078 JSFunction* constructor = JSFunction::cast(map()->constructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013079 DCHECK(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000013080 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010013081 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000013082 return InterceptorInfo::cast(result);
13083}
13084
13085
13086InterceptorInfo* JSObject::GetIndexedInterceptor() {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013087 DCHECK(map()->has_indexed_interceptor());
Steve Blocka7e24c12009-10-30 11:49:00 +000013088 JSFunction* constructor = JSFunction::cast(map()->constructor());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013089 DCHECK(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +000013090 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +010013091 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +000013092 return InterceptorInfo::cast(result);
13093}
13094
13095
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013096MaybeHandle<Object> JSObject::GetPropertyWithInterceptor(
13097 Handle<JSObject> holder,
13098 Handle<Object> receiver,
13099 Handle<Name> name) {
13100 Isolate* isolate = holder->GetIsolate();
13101
13102 // TODO(rossberg): Support symbols in the API.
13103 if (name->IsSymbol()) return isolate->factory()->undefined_value();
13104
13105 Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
13106 Handle<String> name_string = Handle<String>::cast(name);
13107
13108 if (interceptor->getter()->IsUndefined()) return MaybeHandle<Object>();
13109
13110 v8::NamedPropertyGetterCallback getter =
13111 v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
13112 LOG(isolate,
13113 ApiNamedPropertyAccess("interceptor-named-get", *holder, *name));
13114 PropertyCallbackArguments
13115 args(isolate, interceptor->data(), *receiver, *holder);
13116 v8::Handle<v8::Value> result =
13117 args.Call(getter, v8::Utils::ToLocal(name_string));
13118 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
13119 if (result.IsEmpty()) return MaybeHandle<Object>();
13120
13121 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13122 result_internal->VerifyApiCallResultType();
13123 // Rebox handle before return
13124 return handle(*result_internal, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013125}
13126
13127
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013128// Compute the property keys from the interceptor.
13129// TODO(rossberg): support symbols in API, and filter here if needed.
13130MaybeHandle<JSObject> JSObject::GetKeysForNamedInterceptor(
13131 Handle<JSObject> object, Handle<JSReceiver> receiver) {
13132 Isolate* isolate = receiver->GetIsolate();
13133 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
13134 PropertyCallbackArguments
13135 args(isolate, interceptor->data(), *receiver, *object);
13136 v8::Handle<v8::Object> result;
13137 if (!interceptor->enumerator()->IsUndefined()) {
13138 v8::NamedPropertyEnumeratorCallback enum_fun =
13139 v8::ToCData<v8::NamedPropertyEnumeratorCallback>(
13140 interceptor->enumerator());
13141 LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object));
13142 result = args.Call(enum_fun);
Andrei Popescu402d9372010-02-26 13:31:12 +000013143 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013144 if (result.IsEmpty()) return MaybeHandle<JSObject>();
13145#if ENABLE_EXTRA_CHECKS
13146 CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13147 v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13148#endif
13149 // Rebox before returning.
13150 return handle(*v8::Utils::OpenHandle(*result), isolate);
Steve Blockd0582a62009-12-15 09:54:21 +000013151}
13152
13153
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013154// Compute the element keys from the interceptor.
13155MaybeHandle<JSObject> JSObject::GetKeysForIndexedInterceptor(
13156 Handle<JSObject> object, Handle<JSReceiver> receiver) {
13157 Isolate* isolate = receiver->GetIsolate();
13158 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
13159 PropertyCallbackArguments
13160 args(isolate, interceptor->data(), *receiver, *object);
13161 v8::Handle<v8::Object> result;
13162 if (!interceptor->enumerator()->IsUndefined()) {
13163 v8::IndexedPropertyEnumeratorCallback enum_fun =
13164 v8::ToCData<v8::IndexedPropertyEnumeratorCallback>(
13165 interceptor->enumerator());
13166 LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object));
13167 result = args.Call(enum_fun);
13168 }
13169 if (result.IsEmpty()) return MaybeHandle<JSObject>();
13170#if ENABLE_EXTRA_CHECKS
13171 CHECK(v8::Utils::OpenHandle(*result)->IsJSArray() ||
13172 v8::Utils::OpenHandle(*result)->HasSloppyArgumentsElements());
13173#endif
13174 // Rebox before returning.
13175 return handle(*v8::Utils::OpenHandle(*result), isolate);
13176}
13177
13178
13179Maybe<bool> JSObject::HasRealNamedProperty(Handle<JSObject> object,
13180 Handle<Name> key) {
13181 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
13182 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
13183 if (!maybe_result.has_value) return Maybe<bool>();
13184 return maybe(it.IsFound());
13185}
13186
13187
13188Maybe<bool> JSObject::HasRealElementProperty(Handle<JSObject> object,
13189 uint32_t index) {
13190 Isolate* isolate = object->GetIsolate();
Steve Block44f0eee2011-05-26 01:26:41 +010013191 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000013192 // Check access rights if needed.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013193 if (object->IsAccessCheckNeeded()) {
13194 if (!isolate->MayIndexedAccess(object, index, v8::ACCESS_HAS)) {
13195 isolate->ReportFailedAccessCheck(object, v8::ACCESS_HAS);
13196 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Maybe<bool>());
13197 return maybe(false);
Ben Murdoch8b112d22011-06-08 16:22:53 +010013198 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013199 }
13200
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013201 if (object->IsJSGlobalProxy()) {
13202 HandleScope scope(isolate);
13203 PrototypeIterator iter(isolate, object);
13204 if (iter.IsAtEnd()) return maybe(false);
13205 DCHECK(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
13206 return HasRealElementProperty(
13207 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), index);
13208 }
13209
13210 Maybe<PropertyAttributes> result =
13211 GetElementAttributeWithoutInterceptor(object, object, index, false);
13212 if (!result.has_value) return Maybe<bool>();
13213 return maybe(result.value != ABSENT);
Steve Blocka7e24c12009-10-30 11:49:00 +000013214}
13215
13216
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013217Maybe<bool> JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
13218 Handle<Name> key) {
13219 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
13220 Maybe<PropertyAttributes> maybe_result = GetPropertyAttributes(&it);
13221 if (!maybe_result.has_value) return Maybe<bool>();
13222 return maybe(it.state() == LookupIterator::ACCESSOR);
Steve Blocka7e24c12009-10-30 11:49:00 +000013223}
13224
13225
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013226int JSObject::NumberOfOwnProperties(PropertyAttributes filter) {
13227 if (HasFastProperties()) {
13228 Map* map = this->map();
13229 if (filter == NONE) return map->NumberOfOwnDescriptors();
13230 if (filter & DONT_ENUM) {
13231 int result = map->EnumLength();
13232 if (result != kInvalidEnumCacheSentinel) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +010013233 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013234 return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013235 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013236 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013237}
13238
13239
13240void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
13241 Object* temp = get(i);
13242 set(i, get(j));
13243 set(j, temp);
13244 if (this != numbers) {
13245 temp = numbers->get(i);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013246 numbers->set(i, Smi::cast(numbers->get(j)));
13247 numbers->set(j, Smi::cast(temp));
Steve Blocka7e24c12009-10-30 11:49:00 +000013248 }
13249}
13250
13251
13252static void InsertionSortPairs(FixedArray* content,
13253 FixedArray* numbers,
13254 int len) {
13255 for (int i = 1; i < len; i++) {
13256 int j = i;
13257 while (j > 0 &&
13258 (NumberToUint32(numbers->get(j - 1)) >
13259 NumberToUint32(numbers->get(j)))) {
13260 content->SwapPairs(numbers, j - 1, j);
13261 j--;
13262 }
13263 }
13264}
13265
13266
13267void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
13268 // In-place heap sort.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013269 DCHECK(content->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000013270
13271 // Bottom-up max-heap construction.
13272 for (int i = 1; i < len; ++i) {
13273 int child_index = i;
13274 while (child_index > 0) {
13275 int parent_index = ((child_index + 1) >> 1) - 1;
13276 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13277 uint32_t child_value = NumberToUint32(numbers->get(child_index));
13278 if (parent_value < child_value) {
13279 content->SwapPairs(numbers, parent_index, child_index);
13280 } else {
13281 break;
13282 }
13283 child_index = parent_index;
13284 }
13285 }
13286
13287 // Extract elements and create sorted array.
13288 for (int i = len - 1; i > 0; --i) {
13289 // Put max element at the back of the array.
13290 content->SwapPairs(numbers, 0, i);
13291 // Sift down the new top element.
13292 int parent_index = 0;
13293 while (true) {
13294 int child_index = ((parent_index + 1) << 1) - 1;
13295 if (child_index >= i) break;
13296 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
13297 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
13298 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13299 if (child_index + 1 >= i || child1_value > child2_value) {
13300 if (parent_value > child1_value) break;
13301 content->SwapPairs(numbers, parent_index, child_index);
13302 parent_index = child_index;
13303 } else {
13304 if (parent_value > child2_value) break;
13305 content->SwapPairs(numbers, parent_index, child_index + 1);
13306 parent_index = child_index + 1;
13307 }
13308 }
13309 }
13310}
13311
13312
13313// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
13314void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013315 DCHECK(this->length() == numbers->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000013316 // For small arrays, simply use insertion sort.
13317 if (len <= 10) {
13318 InsertionSortPairs(this, numbers, len);
13319 return;
13320 }
13321 // Check the range of indices.
13322 uint32_t min_index = NumberToUint32(numbers->get(0));
13323 uint32_t max_index = min_index;
13324 uint32_t i;
13325 for (i = 1; i < len; i++) {
13326 if (NumberToUint32(numbers->get(i)) < min_index) {
13327 min_index = NumberToUint32(numbers->get(i));
13328 } else if (NumberToUint32(numbers->get(i)) > max_index) {
13329 max_index = NumberToUint32(numbers->get(i));
13330 }
13331 }
13332 if (max_index - min_index + 1 == len) {
13333 // Indices form a contiguous range, unless there are duplicates.
13334 // Do an in-place linear time sort assuming distinct numbers, but
13335 // avoid hanging in case they are not.
13336 for (i = 0; i < len; i++) {
13337 uint32_t p;
13338 uint32_t j = 0;
13339 // While the current element at i is not at its correct position p,
13340 // swap the elements at these two positions.
13341 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
13342 j++ < len) {
13343 SwapPairs(numbers, i, p);
13344 }
13345 }
13346 } else {
13347 HeapSortPairs(this, numbers, len);
13348 return;
13349 }
13350}
13351
13352
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013353// Fill in the names of own properties into the supplied storage. The main
Steve Blocka7e24c12009-10-30 11:49:00 +000013354// purpose of this function is to provide reflection information for the object
13355// mirrors.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013356void JSObject::GetOwnPropertyNames(
13357 FixedArray* storage, int index, PropertyAttributes filter) {
13358 DCHECK(storage->length() >= (NumberOfOwnProperties(filter) - index));
Steve Blocka7e24c12009-10-30 11:49:00 +000013359 if (HasFastProperties()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013360 int real_size = map()->NumberOfOwnDescriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +000013361 DescriptorArray* descs = map()->instance_descriptors();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013362 for (int i = 0; i < real_size; i++) {
13363 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
13364 !FilterKey(descs->GetKey(i), filter)) {
13365 storage->set(index++, descs->GetKey(i));
13366 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013367 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013368 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013369 property_dictionary()->CopyKeysTo(storage,
13370 index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013371 filter,
13372 NameDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000013373 }
13374}
13375
13376
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013377int JSObject::NumberOfOwnElements(PropertyAttributes filter) {
13378 return GetOwnElementKeys(NULL, filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013379}
13380
13381
13382int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +000013383 // Fast case for objects with no elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013384 if (!IsJSValue() && HasFastObjectElements()) {
Steve Blockd0582a62009-12-15 09:54:21 +000013385 uint32_t length = IsJSArray() ?
13386 static_cast<uint32_t>(
13387 Smi::cast(JSArray::cast(this)->length())->value()) :
13388 static_cast<uint32_t>(FixedArray::cast(elements())->length());
13389 if (length == 0) return 0;
13390 }
13391 // Compute the number of enumerable elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013392 return NumberOfOwnElements(static_cast<PropertyAttributes>(DONT_ENUM));
Steve Blocka7e24c12009-10-30 11:49:00 +000013393}
13394
13395
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013396int JSObject::GetOwnElementKeys(FixedArray* storage,
13397 PropertyAttributes filter) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013398 int counter = 0;
13399 switch (GetElementsKind()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013400 case FAST_SMI_ELEMENTS:
13401 case FAST_ELEMENTS:
13402 case FAST_HOLEY_SMI_ELEMENTS:
13403 case FAST_HOLEY_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +000013404 int length = IsJSArray() ?
13405 Smi::cast(JSArray::cast(this)->length())->value() :
13406 FixedArray::cast(elements())->length();
13407 for (int i = 0; i < length; i++) {
13408 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
13409 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000013410 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000013411 }
13412 counter++;
13413 }
13414 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013415 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013416 break;
13417 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013418 case FAST_DOUBLE_ELEMENTS:
13419 case FAST_HOLEY_DOUBLE_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013420 int length = IsJSArray() ?
13421 Smi::cast(JSArray::cast(this)->length())->value() :
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013422 FixedArrayBase::cast(elements())->length();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013423 for (int i = 0; i < length; i++) {
13424 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
13425 if (storage != NULL) {
13426 storage->set(counter, Smi::FromInt(i));
13427 }
13428 counter++;
13429 }
13430 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013431 DCHECK(!storage || storage->length() >= counter);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013432 break;
13433 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013434
13435#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
13436 case EXTERNAL_##TYPE##_ELEMENTS: \
13437 case TYPE##_ELEMENTS: \
13438
13439 TYPED_ARRAYS(TYPED_ARRAY_CASE)
13440#undef TYPED_ARRAY_CASE
13441 {
13442 int length = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000013443 while (counter < length) {
13444 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +000013445 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +000013446 }
13447 counter++;
13448 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013449 DCHECK(!storage || storage->length() >= counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013450 break;
13451 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013452
Steve Blocka7e24c12009-10-30 11:49:00 +000013453 case DICTIONARY_ELEMENTS: {
13454 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013455 element_dictionary()->CopyKeysTo(storage,
13456 filter,
Ben Murdochc7cc0282012-03-05 14:35:55 +000013457 SeededNumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +000013458 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013459 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013460 break;
13461 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013462 case SLOPPY_ARGUMENTS_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013463 FixedArray* parameter_map = FixedArray::cast(elements());
13464 int mapped_length = parameter_map->length() - 2;
13465 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
13466 if (arguments->IsDictionary()) {
13467 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
13468 // will insert in storage starting at index 0.
Ben Murdochc7cc0282012-03-05 14:35:55 +000013469 SeededNumberDictionary* dictionary =
13470 SeededNumberDictionary::cast(arguments);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013471 if (storage != NULL) {
Ben Murdochc7cc0282012-03-05 14:35:55 +000013472 dictionary->CopyKeysTo(
13473 storage, filter, SeededNumberDictionary::UNSORTED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013474 }
13475 counter += dictionary->NumberOfElementsFilterAttributes(filter);
13476 for (int i = 0; i < mapped_length; ++i) {
13477 if (!parameter_map->get(i + 2)->IsTheHole()) {
13478 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13479 ++counter;
13480 }
13481 }
13482 if (storage != NULL) storage->SortPairs(storage, counter);
13483
13484 } else {
13485 int backing_length = arguments->length();
13486 int i = 0;
13487 for (; i < mapped_length; ++i) {
13488 if (!parameter_map->get(i + 2)->IsTheHole()) {
13489 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13490 ++counter;
13491 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
13492 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13493 ++counter;
13494 }
13495 }
13496 for (; i < backing_length; ++i) {
13497 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13498 ++counter;
13499 }
13500 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013501 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013502 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013503 }
13504
13505 if (this->IsJSValue()) {
13506 Object* val = JSValue::cast(this)->value();
13507 if (val->IsString()) {
13508 String* str = String::cast(val);
13509 if (storage) {
13510 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000013511 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000013512 }
13513 }
13514 counter += str->length();
13515 }
13516 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013517 DCHECK(!storage || storage->length() == counter);
Steve Blocka7e24c12009-10-30 11:49:00 +000013518 return counter;
13519}
13520
13521
13522int JSObject::GetEnumElementKeys(FixedArray* storage) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013523 return GetOwnElementKeys(storage, static_cast<PropertyAttributes>(DONT_ENUM));
Steve Blocka7e24c12009-10-30 11:49:00 +000013524}
13525
13526
Steve Blocka7e24c12009-10-30 11:49:00 +000013527// StringSharedKeys are used as keys in the eval cache.
13528class StringSharedKey : public HashTableKey {
13529 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013530 StringSharedKey(Handle<String> source,
13531 Handle<SharedFunctionInfo> shared,
13532 StrictMode strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013533 int scope_position)
Steve Block1e0659c2011-05-24 12:43:12 +010013534 : source_(source),
13535 shared_(shared),
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013536 strict_mode_(strict_mode),
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013537 scope_position_(scope_position) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000013538
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013539 bool IsMatch(Object* other) OVERRIDE {
13540 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000013541 if (!other->IsFixedArray()) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013542 FixedArray* other_array = FixedArray::cast(other);
13543 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013544 if (shared != *shared_) return false;
13545 int strict_unchecked = Smi::cast(other_array->get(2))->value();
13546 DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
13547 StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
13548 if (strict_mode != strict_mode_) return false;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013549 int scope_position = Smi::cast(other_array->get(3))->value();
13550 if (scope_position != scope_position_) return false;
13551 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013552 return source->Equals(*source_);
Steve Blocka7e24c12009-10-30 11:49:00 +000013553 }
13554
13555 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +010013556 SharedFunctionInfo* shared,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013557 StrictMode strict_mode,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013558 int scope_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013559 uint32_t hash = source->Hash();
13560 if (shared->HasSourceCode()) {
13561 // Instead of using the SharedFunctionInfo pointer in the hash
13562 // code computation, we use a combination of the hash of the
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013563 // script source code and the start position of the calling scope.
13564 // We do this to ensure that the cache entries can survive garbage
Steve Blocka7e24c12009-10-30 11:49:00 +000013565 // collection.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013566 Script* script(Script::cast(shared->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +000013567 hash ^= String::cast(script->source())->Hash();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013568 if (strict_mode == STRICT) hash ^= 0x8000;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013569 hash += scope_position;
Steve Blocka7e24c12009-10-30 11:49:00 +000013570 }
13571 return hash;
13572 }
13573
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013574 uint32_t Hash() OVERRIDE {
13575 return StringSharedHashHelper(*source_, *shared_, strict_mode_,
13576 scope_position_);
Steve Blocka7e24c12009-10-30 11:49:00 +000013577 }
13578
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013579 uint32_t HashForObject(Object* obj) OVERRIDE {
13580 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013581 FixedArray* other_array = FixedArray::cast(obj);
13582 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
13583 String* source = String::cast(other_array->get(1));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013584 int strict_unchecked = Smi::cast(other_array->get(2))->value();
13585 DCHECK(strict_unchecked == SLOPPY || strict_unchecked == STRICT);
13586 StrictMode strict_mode = static_cast<StrictMode>(strict_unchecked);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013587 int scope_position = Smi::cast(other_array->get(3))->value();
13588 return StringSharedHashHelper(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013589 source, shared, strict_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000013590 }
13591
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013592
13593 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
13594 Handle<FixedArray> array = isolate->factory()->NewFixedArray(4);
13595 array->set(0, *shared_);
13596 array->set(1, *source_);
13597 array->set(2, Smi::FromInt(strict_mode_));
13598 array->set(3, Smi::FromInt(scope_position_));
13599 return array;
Steve Blocka7e24c12009-10-30 11:49:00 +000013600 }
13601
13602 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013603 Handle<String> source_;
13604 Handle<SharedFunctionInfo> shared_;
13605 StrictMode strict_mode_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013606 int scope_position_;
Steve Blocka7e24c12009-10-30 11:49:00 +000013607};
13608
13609
13610// RegExpKey carries the source and flags of a regular expression as key.
13611class RegExpKey : public HashTableKey {
13612 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013613 RegExpKey(Handle<String> string, JSRegExp::Flags flags)
Steve Blocka7e24c12009-10-30 11:49:00 +000013614 : string_(string),
13615 flags_(Smi::FromInt(flags.value())) { }
13616
Steve Block3ce2e202009-11-05 08:53:23 +000013617 // Rather than storing the key in the hash table, a pointer to the
13618 // stored value is stored where the key should be. IsMatch then
13619 // compares the search key to the found object, rather than comparing
13620 // a key to a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013621 bool IsMatch(Object* obj) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000013622 FixedArray* val = FixedArray::cast(obj);
13623 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
13624 && (flags_ == val->get(JSRegExp::kFlagsIndex));
13625 }
13626
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013627 uint32_t Hash() OVERRIDE { return RegExpHash(*string_, flags_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000013628
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013629 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000013630 // Plain hash maps, which is where regexp keys are used, don't
13631 // use this function.
13632 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013633 return MaybeHandle<Object>().ToHandleChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000013634 }
13635
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013636 uint32_t HashForObject(Object* obj) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000013637 FixedArray* val = FixedArray::cast(obj);
13638 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
13639 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
13640 }
13641
13642 static uint32_t RegExpHash(String* string, Smi* flags) {
13643 return string->Hash() + flags->value();
13644 }
13645
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013646 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000013647 Smi* flags_;
13648};
13649
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013650
13651Handle<Object> OneByteStringKey::AsHandle(Isolate* isolate) {
13652 if (hash_field_ == 0) Hash();
13653 return isolate->factory()->NewOneByteInternalizedString(string_, hash_field_);
13654}
13655
13656
13657Handle<Object> TwoByteStringKey::AsHandle(Isolate* isolate) {
13658 if (hash_field_ == 0) Hash();
13659 return isolate->factory()->NewTwoByteInternalizedString(string_, hash_field_);
13660}
13661
13662
13663Handle<Object> SeqOneByteSubStringKey::AsHandle(Isolate* isolate) {
13664 if (hash_field_ == 0) Hash();
13665 return isolate->factory()->NewOneByteInternalizedSubString(
13666 string_, from_, length_, hash_field_);
13667}
13668
13669
13670bool SeqOneByteSubStringKey::IsMatch(Object* string) {
13671 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
13672 return String::cast(string)->IsOneByteEqualTo(chars);
13673}
13674
13675
13676// InternalizedStringKey carries a string/internalized-string object as key.
13677class InternalizedStringKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000013678 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013679 explicit InternalizedStringKey(Handle<String> string)
Steve Block44f0eee2011-05-26 01:26:41 +010013680 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000013681
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013682 virtual bool IsMatch(Object* string) OVERRIDE {
13683 return String::cast(string)->Equals(*string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000013684 }
13685
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013686 virtual uint32_t Hash() OVERRIDE { return string_->Hash(); }
Steve Blocka7e24c12009-10-30 11:49:00 +000013687
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013688 virtual uint32_t HashForObject(Object* other) OVERRIDE {
Steve Blocka7e24c12009-10-30 11:49:00 +000013689 return String::cast(other)->Hash();
13690 }
13691
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013692 virtual Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
13693 // Internalize the string if possible.
13694 MaybeHandle<Map> maybe_map =
13695 isolate->factory()->InternalizedStringMapForString(string_);
13696 Handle<Map> map;
13697 if (maybe_map.ToHandle(&map)) {
13698 string_->set_map_no_write_barrier(*map);
13699 DCHECK(string_->IsInternalizedString());
Steve Blocka7e24c12009-10-30 11:49:00 +000013700 return string_;
13701 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013702 // Otherwise allocate a new internalized string.
13703 return isolate->factory()->NewInternalizedStringImpl(
13704 string_, string_->length(), string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000013705 }
13706
13707 static uint32_t StringHash(Object* obj) {
13708 return String::cast(obj)->Hash();
13709 }
13710
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013711 Handle<String> string_;
Steve Blocka7e24c12009-10-30 11:49:00 +000013712};
13713
13714
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013715template<typename Derived, typename Shape, typename Key>
13716void HashTable<Derived, Shape, Key>::IteratePrefix(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013717 IteratePointers(v, 0, kElementsStartOffset);
13718}
13719
13720
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013721template<typename Derived, typename Shape, typename Key>
13722void HashTable<Derived, Shape, Key>::IterateElements(ObjectVisitor* v) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013723 IteratePointers(v,
13724 kElementsStartOffset,
13725 kHeaderSize + length() * kPointerSize);
13726}
13727
13728
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013729template<typename Derived, typename Shape, typename Key>
13730Handle<Derived> HashTable<Derived, Shape, Key>::New(
13731 Isolate* isolate,
13732 int at_least_space_for,
13733 MinimumCapacity capacity_option,
13734 PretenureFlag pretenure) {
13735 DCHECK(0 <= at_least_space_for);
13736 DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
13737 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
13738 ? at_least_space_for
13739 : ComputeCapacity(at_least_space_for);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013740 if (capacity > HashTable::kMaxCapacity) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013741 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
Leon Clarkee46be812010-01-19 14:06:41 +000013742 }
13743
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013744 Factory* factory = isolate->factory();
13745 int length = EntryToIndex(capacity);
13746 Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
13747 array->set_map_no_write_barrier(*factory->hash_table_map());
13748 Handle<Derived> table = Handle<Derived>::cast(array);
13749
13750 table->SetNumberOfElements(0);
13751 table->SetNumberOfDeletedElements(0);
13752 table->SetCapacity(capacity);
13753 return table;
Steve Blocka7e24c12009-10-30 11:49:00 +000013754}
13755
13756
Leon Clarkee46be812010-01-19 14:06:41 +000013757// Find entry for key otherwise return kNotFound.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013758int NameDictionary::FindEntry(Handle<Name> key) {
13759 if (!key->IsUniqueName()) {
13760 return DerivedHashTable::FindEntry(key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010013761 }
13762
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013763 // Optimized for unique names. Knowledge of the key type allows:
13764 // 1. Move the check if the key is unique out of the loop.
13765 // 2. Avoid comparing hash codes in unique-to-unique comparison.
13766 // 3. Detect a case when a dictionary key is not unique but the key is.
13767 // In case of positive result the dictionary key may be replaced by the
13768 // internalized string with minimal performance penalty. It gives a chance
13769 // to perform further lookups in code stubs (and significant performance
13770 // boost a certain style of code).
Ben Murdoch3bec4d22010-07-22 14:51:16 +010013771
13772 // EnsureCapacity will guarantee the hash table is never full.
13773 uint32_t capacity = Capacity();
13774 uint32_t entry = FirstProbe(key->Hash(), capacity);
13775 uint32_t count = 1;
13776
13777 while (true) {
13778 int index = EntryToIndex(entry);
13779 Object* element = get(index);
13780 if (element->IsUndefined()) break; // Empty entry.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013781 if (*key == element) return entry;
13782 if (!element->IsUniqueName() &&
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013783 !element->IsTheHole() &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013784 Name::cast(element)->Equals(*key)) {
13785 // Replace a key that is a non-internalized string by the equivalent
13786 // internalized string for faster further lookups.
13787 set(index, *key);
Ben Murdoch3bec4d22010-07-22 14:51:16 +010013788 return entry;
13789 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013790 DCHECK(element->IsTheHole() || !Name::cast(element)->Equals(*key));
Ben Murdoch3bec4d22010-07-22 14:51:16 +010013791 entry = NextProbe(entry, count++, capacity);
13792 }
13793 return kNotFound;
13794}
13795
13796
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013797template<typename Derived, typename Shape, typename Key>
13798void HashTable<Derived, Shape, Key>::Rehash(
13799 Handle<Derived> new_table,
13800 Key key) {
13801 DCHECK(NumberOfElements() < new_table->Capacity());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013802
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013803 DisallowHeapAllocation no_gc;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013804 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
13805
13806 // Copy prefix to new array.
13807 for (int i = kPrefixStartIndex;
13808 i < kPrefixStartIndex + Shape::kPrefixSize;
13809 i++) {
13810 new_table->set(i, get(i), mode);
13811 }
13812
13813 // Rehash the elements.
13814 int capacity = Capacity();
13815 for (int i = 0; i < capacity; i++) {
13816 uint32_t from_index = EntryToIndex(i);
13817 Object* k = get(from_index);
13818 if (IsKey(k)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013819 uint32_t hash = HashTable::HashForObject(key, k);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013820 uint32_t insertion_index =
13821 EntryToIndex(new_table->FindInsertionEntry(hash));
13822 for (int j = 0; j < Shape::kEntrySize; j++) {
13823 new_table->set(insertion_index + j, get(from_index + j), mode);
13824 }
13825 }
13826 }
13827 new_table->SetNumberOfElements(NumberOfElements());
13828 new_table->SetNumberOfDeletedElements(0);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013829}
13830
13831
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013832template<typename Derived, typename Shape, typename Key>
13833uint32_t HashTable<Derived, Shape, Key>::EntryForProbe(
13834 Key key,
13835 Object* k,
13836 int probe,
13837 uint32_t expected) {
13838 uint32_t hash = HashTable::HashForObject(key, k);
13839 uint32_t capacity = Capacity();
13840 uint32_t entry = FirstProbe(hash, capacity);
13841 for (int i = 1; i < probe; i++) {
13842 if (entry == expected) return expected;
13843 entry = NextProbe(entry, i, capacity);
13844 }
13845 return entry;
13846}
13847
13848
13849template<typename Derived, typename Shape, typename Key>
13850void HashTable<Derived, Shape, Key>::Swap(uint32_t entry1,
13851 uint32_t entry2,
13852 WriteBarrierMode mode) {
13853 int index1 = EntryToIndex(entry1);
13854 int index2 = EntryToIndex(entry2);
13855 Object* temp[Shape::kEntrySize];
13856 for (int j = 0; j < Shape::kEntrySize; j++) {
13857 temp[j] = get(index1 + j);
13858 }
13859 for (int j = 0; j < Shape::kEntrySize; j++) {
13860 set(index1 + j, get(index2 + j), mode);
13861 }
13862 for (int j = 0; j < Shape::kEntrySize; j++) {
13863 set(index2 + j, temp[j], mode);
13864 }
13865}
13866
13867
13868template<typename Derived, typename Shape, typename Key>
13869void HashTable<Derived, Shape, Key>::Rehash(Key key) {
13870 DisallowHeapAllocation no_gc;
13871 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
13872 uint32_t capacity = Capacity();
13873 bool done = false;
13874 for (int probe = 1; !done; probe++) {
13875 // All elements at entries given by one of the first _probe_ probes
13876 // are placed correctly. Other elements might need to be moved.
13877 done = true;
13878 for (uint32_t current = 0; current < capacity; current++) {
13879 Object* current_key = get(EntryToIndex(current));
13880 if (IsKey(current_key)) {
13881 uint32_t target = EntryForProbe(key, current_key, probe, current);
13882 if (current == target) continue;
13883 Object* target_key = get(EntryToIndex(target));
13884 if (!IsKey(target_key) ||
13885 EntryForProbe(key, target_key, probe, target) != target) {
13886 // Put the current element into the correct position.
13887 Swap(current, target, mode);
13888 // The other element will be processed on the next iteration.
13889 current--;
13890 } else {
13891 // The place for the current element is occupied. Leave the element
13892 // for the next probe.
13893 done = false;
13894 }
13895 }
13896 }
13897 }
13898}
13899
13900
13901template<typename Derived, typename Shape, typename Key>
13902Handle<Derived> HashTable<Derived, Shape, Key>::EnsureCapacity(
13903 Handle<Derived> table,
13904 int n,
13905 Key key,
13906 PretenureFlag pretenure) {
13907 Isolate* isolate = table->GetIsolate();
13908 int capacity = table->Capacity();
13909 int nof = table->NumberOfElements() + n;
13910 int nod = table->NumberOfDeletedElements();
Leon Clarkee46be812010-01-19 14:06:41 +000013911 // Return if:
13912 // 50% is still free after adding n elements and
13913 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +010013914 if (nod <= (capacity - nof) >> 1) {
13915 int needed_free = nof >> 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013916 if (nof + needed_free <= capacity) return table;
Steve Block6ded16b2010-05-10 14:33:55 +010013917 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013918
Steve Block6ded16b2010-05-10 14:33:55 +010013919 const int kMinCapacityForPretenure = 256;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013920 bool should_pretenure = pretenure == TENURED ||
13921 ((capacity > kMinCapacityForPretenure) &&
13922 !isolate->heap()->InNewSpace(*table));
13923 Handle<Derived> new_table = HashTable::New(
13924 isolate,
13925 nof * 2,
13926 USE_DEFAULT_MINIMUM_CAPACITY,
13927 should_pretenure ? TENURED : NOT_TENURED);
Leon Clarke4515c472010-02-03 11:58:03 +000013928
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013929 table->Rehash(new_table, key);
13930 return new_table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013931}
Steve Blocka7e24c12009-10-30 11:49:00 +000013932
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013933
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013934template<typename Derived, typename Shape, typename Key>
13935Handle<Derived> HashTable<Derived, Shape, Key>::Shrink(Handle<Derived> table,
13936 Key key) {
13937 int capacity = table->Capacity();
13938 int nof = table->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013939
13940 // Shrink to fit the number of elements if only a quarter of the
13941 // capacity is filled with elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013942 if (nof > (capacity >> 2)) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013943 // Allocate a new dictionary with room for at least the current
13944 // number of elements. The allocation method will make sure that
13945 // there is extra room in the dictionary for additions. Don't go
13946 // lower than room for 16 elements.
13947 int at_least_room_for = nof;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013948 if (at_least_room_for < 16) return table;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013949
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013950 Isolate* isolate = table->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013951 const int kMinCapacityForPretenure = 256;
13952 bool pretenure =
13953 (at_least_room_for > kMinCapacityForPretenure) &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013954 !isolate->heap()->InNewSpace(*table);
13955 Handle<Derived> new_table = HashTable::New(
13956 isolate,
13957 at_least_room_for,
13958 USE_DEFAULT_MINIMUM_CAPACITY,
13959 pretenure ? TENURED : NOT_TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000013960
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013961 table->Rehash(new_table, key);
13962 return new_table;
Steve Blocka7e24c12009-10-30 11:49:00 +000013963}
13964
13965
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013966template<typename Derived, typename Shape, typename Key>
13967uint32_t HashTable<Derived, Shape, Key>::FindInsertionEntry(uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000013968 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000013969 uint32_t entry = FirstProbe(hash, capacity);
13970 uint32_t count = 1;
13971 // EnsureCapacity will guarantee the hash table is never full.
13972 while (true) {
13973 Object* element = KeyAt(entry);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013974 if (element->IsUndefined() || element->IsTheHole()) break;
Leon Clarkee46be812010-01-19 14:06:41 +000013975 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000013976 }
Steve Blocka7e24c12009-10-30 11:49:00 +000013977 return entry;
13978}
13979
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013980
Steve Blocka7e24c12009-10-30 11:49:00 +000013981// Force instantiation of template instances class.
13982// Please note this list is compiler dependent.
13983
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013984template class HashTable<StringTable, StringTableShape, HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000013985
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013986template class HashTable<CompilationCacheTable,
13987 CompilationCacheShape,
13988 HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000013989
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013990template class HashTable<MapCache, MapCacheShape, HashTableKey*>;
Steve Blocka7e24c12009-10-30 11:49:00 +000013991
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013992template class HashTable<ObjectHashTable,
13993 ObjectHashTableShape,
13994 Handle<Object> >;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010013995
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013996template class HashTable<WeakHashTable, WeakHashTableShape<2>, Handle<Object> >;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000013997
Ben Murdochb8a8cc12014-11-26 15:28:44 +000013998template class Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >;
Steve Blocka7e24c12009-10-30 11:49:00 +000013999
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014000template class Dictionary<SeededNumberDictionary,
14001 SeededNumberDictionaryShape,
14002 uint32_t>;
Steve Blocka7e24c12009-10-30 11:49:00 +000014003
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014004template class Dictionary<UnseededNumberDictionary,
14005 UnseededNumberDictionaryShape,
14006 uint32_t>;
Ben Murdochc7cc0282012-03-05 14:35:55 +000014007
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014008template Handle<SeededNumberDictionary>
14009Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14010 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014011
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014012template Handle<UnseededNumberDictionary>
14013Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14014 New(Isolate*, int at_least_space_for, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000014015
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014016template Handle<NameDictionary>
14017Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14018 New(Isolate*, int n, PretenureFlag pretenure);
Steve Blocka7e24c12009-10-30 11:49:00 +000014019
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014020template Handle<SeededNumberDictionary>
14021Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14022 AtPut(Handle<SeededNumberDictionary>, uint32_t, Handle<Object>);
Steve Blocka7e24c12009-10-30 11:49:00 +000014023
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014024template Handle<UnseededNumberDictionary>
14025Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14026 AtPut(Handle<UnseededNumberDictionary>, uint32_t, Handle<Object>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014027
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014028template Object*
14029Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014030 SlowReverseLookup(Object* value);
14031
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014032template Object*
14033Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000014034 SlowReverseLookup(Object* value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014035
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014036template void
14037Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14038 CopyKeysTo(
14039 FixedArray*,
14040 PropertyAttributes,
14041 Dictionary<SeededNumberDictionary,
14042 SeededNumberDictionaryShape,
14043 uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014044
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014045template Handle<Object>
14046Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::DeleteProperty(
14047 Handle<NameDictionary>, int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014048
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014049template Handle<Object>
14050Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14051 DeleteProperty(Handle<SeededNumberDictionary>, int, JSObject::DeleteMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014052
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014053template Handle<NameDictionary>
14054HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14055 New(Isolate*, int, MinimumCapacity, PretenureFlag);
Steve Blocka7e24c12009-10-30 11:49:00 +000014056
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014057template Handle<NameDictionary>
14058HashTable<NameDictionary, NameDictionaryShape, Handle<Name> >::
14059 Shrink(Handle<NameDictionary>, Handle<Name>);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014061template Handle<SeededNumberDictionary>
14062HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14063 Shrink(Handle<SeededNumberDictionary>, uint32_t);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014064
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014065template void Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14066 CopyKeysTo(
14067 FixedArray*,
14068 int,
14069 PropertyAttributes,
14070 Dictionary<
14071 NameDictionary, NameDictionaryShape, Handle<Name> >::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000014072
14073template int
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014074Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
Ben Murdochc7cc0282012-03-05 14:35:55 +000014075 NumberOfElementsFilterAttributes(PropertyAttributes);
Steve Blocka7e24c12009-10-30 11:49:00 +000014076
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014077template Handle<NameDictionary>
14078Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
14079 Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000014080
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014081template void
14082Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14083 GenerateNewEnumerationIndices(Handle<NameDictionary>);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014084
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014085template int
14086Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14087 NumberOfElementsFilterAttributes(PropertyAttributes);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014088
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014089template Handle<SeededNumberDictionary>
14090Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14091 Add(Handle<SeededNumberDictionary>,
14092 uint32_t,
14093 Handle<Object>,
14094 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000014095
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014096template Handle<UnseededNumberDictionary>
14097Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14098 Add(Handle<UnseededNumberDictionary>,
14099 uint32_t,
14100 Handle<Object>,
14101 PropertyDetails);
Steve Blocka7e24c12009-10-30 11:49:00 +000014102
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014103template Handle<SeededNumberDictionary>
14104Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14105 EnsureCapacity(Handle<SeededNumberDictionary>, int, uint32_t);
Ben Murdochc7cc0282012-03-05 14:35:55 +000014106
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014107template Handle<UnseededNumberDictionary>
14108Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
14109 EnsureCapacity(Handle<UnseededNumberDictionary>, int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000014110
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014111template Handle<NameDictionary>
14112Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14113 EnsureCapacity(Handle<NameDictionary>, int, Handle<Name>);
Steve Blocka7e24c12009-10-30 11:49:00 +000014114
14115template
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014116int Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14117 NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000014118
14119template
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014120int Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::
14121 NumberOfEnumElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000014122
Leon Clarkee46be812010-01-19 14:06:41 +000014123template
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014124int HashTable<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
14125 FindEntry(uint32_t);
Leon Clarkee46be812010-01-19 14:06:41 +000014126
14127
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014128Handle<Object> JSObject::PrepareSlowElementsForSort(
14129 Handle<JSObject> object, uint32_t limit) {
14130 DCHECK(object->HasDictionaryElements());
14131 Isolate* isolate = object->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000014132 // Must stay in dictionary mode, either because of requires_slow_elements,
14133 // or because we are not going to sort (and therefore compact) all of the
14134 // elements.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014135 Handle<SeededNumberDictionary> dict(object->element_dictionary(), isolate);
14136 Handle<SeededNumberDictionary> new_dict =
14137 SeededNumberDictionary::New(isolate, dict->NumberOfElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000014138
14139 uint32_t pos = 0;
14140 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010014141 int capacity = dict->Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014142 Handle<Smi> bailout(Smi::FromInt(-1), isolate);
14143 // Entry to the new dictionary does not cause it to grow, as we have
14144 // allocated one that is large enough for all entries.
14145 DisallowHeapAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +000014146 for (int i = 0; i < capacity; i++) {
14147 Object* k = dict->KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014148 if (!dict->IsKey(k)) continue;
14149
14150 DCHECK(k->IsNumber());
14151 DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
14152 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
14153 DCHECK(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
14154
14155 HandleScope scope(isolate);
14156 Handle<Object> value(dict->ValueAt(i), isolate);
14157 PropertyDetails details = dict->DetailsAt(i);
14158 if (details.type() == CALLBACKS || details.IsReadOnly()) {
14159 // Bail out and do the sorting of undefineds and array holes in JS.
14160 // Also bail out if the element is not supposed to be moved.
14161 return bailout;
14162 }
14163
14164 uint32_t key = NumberToUint32(k);
14165 if (key < limit) {
14166 if (value->IsUndefined()) {
14167 undefs++;
14168 } else if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14169 // Adding an entry with the key beyond smi-range requires
14170 // allocation. Bailout.
14171 return bailout;
Steve Blocka7e24c12009-10-30 11:49:00 +000014172 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014173 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14174 new_dict, pos, value, details);
14175 DCHECK(result.is_identical_to(new_dict));
14176 USE(result);
14177 pos++;
Steve Blocka7e24c12009-10-30 11:49:00 +000014178 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014179 } else if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
14180 // Adding an entry with the key beyond smi-range requires
14181 // allocation. Bailout.
14182 return bailout;
14183 } else {
14184 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14185 new_dict, key, value, details);
14186 DCHECK(result.is_identical_to(new_dict));
14187 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014188 }
14189 }
14190
14191 uint32_t result = pos;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014192 PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014193 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010014194 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14195 // Adding an entry with the key beyond smi-range requires
14196 // allocation. Bailout.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014197 return bailout;
Steve Block1e0659c2011-05-24 12:43:12 +010014198 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014199 HandleScope scope(isolate);
14200 Handle<Object> result = SeededNumberDictionary::AddNumberEntry(
14201 new_dict, pos, isolate->factory()->undefined_value(), no_details);
14202 DCHECK(result.is_identical_to(new_dict));
14203 USE(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014204 pos++;
14205 undefs--;
14206 }
14207
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014208 object->set_elements(*new_dict);
Steve Blocka7e24c12009-10-30 11:49:00 +000014209
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014210 AllowHeapAllocation allocate_return_value;
14211 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014212}
14213
14214
14215// Collects all defined (non-hole) and non-undefined (array) elements at
14216// the start of the elements array.
14217// If the object is in dictionary mode, it is converted to fast elements
14218// mode.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014219Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
14220 uint32_t limit) {
14221 Isolate* isolate = object->GetIsolate();
14222 if (object->HasSloppyArgumentsElements() ||
14223 object->map()->is_observed()) {
14224 return handle(Smi::FromInt(-1), isolate);
14225 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010014226
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014227 if (object->HasDictionaryElements()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014228 // Convert to fast elements containing only the existing properties.
14229 // Ordering is irrelevant, since we are going to sort anyway.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014230 Handle<SeededNumberDictionary> dict(object->element_dictionary());
14231 if (object->IsJSArray() || dict->requires_slow_elements() ||
Steve Blocka7e24c12009-10-30 11:49:00 +000014232 dict->max_number_key() >= limit) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014233 return JSObject::PrepareSlowElementsForSort(object, limit);
Steve Blocka7e24c12009-10-30 11:49:00 +000014234 }
14235 // Convert to fast elements.
14236
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014237 Handle<Map> new_map =
14238 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
Steve Block8defd9f2010-07-08 12:39:36 +010014239
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014240 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
14241 NOT_TENURED: TENURED;
14242 Handle<FixedArray> fast_elements =
14243 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
14244 dict->CopyValuesTo(*fast_elements);
14245 JSObject::ValidateElements(object);
Steve Block8defd9f2010-07-08 12:39:36 +010014246
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014247 JSObject::SetMapAndElements(object, new_map, fast_elements);
14248 } else if (object->HasExternalArrayElements() ||
14249 object->HasFixedTypedArrayElements()) {
14250 // Typed arrays cannot have holes or undefined elements.
14251 return handle(Smi::FromInt(
14252 FixedArrayBase::cast(object->elements())->length()), isolate);
14253 } else if (!object->HasFastDoubleElements()) {
14254 EnsureWritableFastElements(object);
Steve Blocka7e24c12009-10-30 11:49:00 +000014255 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014256 DCHECK(object->HasFastSmiOrObjectElements() ||
14257 object->HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000014258
14259 // Collect holes at the end, undefined before that and the rest at the
14260 // start, and return the number of non-hole, non-undefined values.
14261
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014262 Handle<FixedArrayBase> elements_base(object->elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014263 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000014264 if (limit > elements_length) {
14265 limit = elements_length ;
14266 }
14267 if (limit == 0) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014268 return handle(Smi::FromInt(0), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014269 }
14270
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014271 uint32_t result = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014272 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
14273 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014274 // Split elements into defined and the_hole, in that order.
14275 unsigned int holes = limit;
14276 // Assume most arrays contain no holes and undefined values, so minimize the
14277 // number of stores of non-undefined, non-the-hole values.
14278 for (unsigned int i = 0; i < holes; i++) {
14279 if (elements->is_the_hole(i)) {
14280 holes--;
14281 } else {
14282 continue;
14283 }
14284 // Position i needs to be filled.
14285 while (holes > i) {
14286 if (elements->is_the_hole(holes)) {
14287 holes--;
14288 } else {
14289 elements->set(i, elements->get_scalar(holes));
14290 break;
14291 }
14292 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014293 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014294 result = holes;
14295 while (holes < limit) {
14296 elements->set_the_hole(holes);
14297 holes++;
14298 }
14299 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014300 FixedArray* elements = FixedArray::cast(*elements_base);
14301 DisallowHeapAllocation no_gc;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014302
14303 // Split elements into defined, undefined and the_hole, in that order. Only
14304 // count locations for undefined and the hole, and fill them afterwards.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014305 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014306 unsigned int undefs = limit;
14307 unsigned int holes = limit;
14308 // Assume most arrays contain no holes and undefined values, so minimize the
14309 // number of stores of non-undefined, non-the-hole values.
14310 for (unsigned int i = 0; i < undefs; i++) {
14311 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000014312 if (current->IsTheHole()) {
14313 holes--;
14314 undefs--;
14315 } else if (current->IsUndefined()) {
14316 undefs--;
14317 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014318 continue;
14319 }
14320 // Position i needs to be filled.
14321 while (undefs > i) {
14322 current = elements->get(undefs);
14323 if (current->IsTheHole()) {
14324 holes--;
14325 undefs--;
14326 } else if (current->IsUndefined()) {
14327 undefs--;
14328 } else {
14329 elements->set(i, current, write_barrier);
14330 break;
14331 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014332 }
14333 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014334 result = undefs;
14335 while (undefs < holes) {
14336 elements->set_undefined(undefs);
14337 undefs++;
14338 }
14339 while (holes < limit) {
14340 elements->set_the_hole(holes);
14341 holes++;
14342 }
Steve Blocka7e24c12009-10-30 11:49:00 +000014343 }
14344
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014345 return isolate->factory()->NewNumberFromUint(result);
Steve Blocka7e24c12009-10-30 11:49:00 +000014346}
14347
14348
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014349ExternalArrayType JSTypedArray::type() {
14350 switch (elements()->map()->instance_type()) {
14351#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \
14352 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
14353 case FIXED_##TYPE##_ARRAY_TYPE: \
14354 return kExternal##Type##Array;
14355
14356 TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
14357#undef INSTANCE_TYPE_TO_ARRAY_TYPE
14358
14359 default:
14360 UNREACHABLE();
14361 return static_cast<ExternalArrayType>(-1);
14362 }
14363}
14364
14365
14366size_t JSTypedArray::element_size() {
14367 switch (elements()->map()->instance_type()) {
14368#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \
14369 case EXTERNAL_##TYPE##_ARRAY_TYPE: \
14370 return size;
14371
14372 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
14373#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
14374
14375 default:
14376 UNREACHABLE();
14377 return 0;
14378 }
14379}
14380
14381
14382Handle<Object> ExternalUint8ClampedArray::SetValue(
14383 Handle<ExternalUint8ClampedArray> array,
14384 uint32_t index,
14385 Handle<Object> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014386 uint8_t clamped_value = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014387 if (index < static_cast<uint32_t>(array->length())) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014388 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014389 int int_value = Handle<Smi>::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000014390 if (int_value < 0) {
14391 clamped_value = 0;
14392 } else if (int_value > 255) {
14393 clamped_value = 255;
14394 } else {
14395 clamped_value = static_cast<uint8_t>(int_value);
14396 }
14397 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014398 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000014399 if (!(double_value > 0)) {
14400 // NaN and less than zero clamp to zero.
14401 clamped_value = 0;
14402 } else if (double_value > 255) {
14403 // Greater than 255 clamp to 255.
14404 clamped_value = 255;
14405 } else {
14406 // Other doubles are rounded to the nearest integer.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014407 clamped_value = static_cast<uint8_t>(lrint(double_value));
Steve Blocka7e24c12009-10-30 11:49:00 +000014408 }
14409 } else {
14410 // Clamp undefined to zero (default). All other types have been
14411 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014412 DCHECK(value->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +000014413 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014414 array->set(index, clamped_value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014415 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014416 return handle(Smi::FromInt(clamped_value), array->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000014417}
14418
14419
Steve Block3ce2e202009-11-05 08:53:23 +000014420template<typename ExternalArrayClass, typename ValueType>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014421static Handle<Object> ExternalArrayIntSetter(
14422 Isolate* isolate,
14423 Handle<ExternalArrayClass> receiver,
14424 uint32_t index,
14425 Handle<Object> value) {
Steve Block3ce2e202009-11-05 08:53:23 +000014426 ValueType cast_value = 0;
14427 if (index < static_cast<uint32_t>(receiver->length())) {
14428 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014429 int int_value = Handle<Smi>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000014430 cast_value = static_cast<ValueType>(int_value);
14431 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014432 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000014433 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
14434 } else {
14435 // Clamp undefined to zero (default). All other types have been
14436 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014437 DCHECK(value->IsUndefined());
Steve Block3ce2e202009-11-05 08:53:23 +000014438 }
14439 receiver->set(index, cast_value);
14440 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014441 return isolate->factory()->NewNumberFromInt(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000014442}
14443
14444
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014445Handle<Object> ExternalInt8Array::SetValue(Handle<ExternalInt8Array> array,
14446 uint32_t index,
14447 Handle<Object> value) {
14448 return ExternalArrayIntSetter<ExternalInt8Array, int8_t>(
14449 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000014450}
14451
14452
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014453Handle<Object> ExternalUint8Array::SetValue(Handle<ExternalUint8Array> array,
14454 uint32_t index,
14455 Handle<Object> value) {
14456 return ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(
14457 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000014458}
14459
14460
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014461Handle<Object> ExternalInt16Array::SetValue(Handle<ExternalInt16Array> array,
14462 uint32_t index,
14463 Handle<Object> value) {
14464 return ExternalArrayIntSetter<ExternalInt16Array, int16_t>(
14465 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000014466}
14467
14468
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014469Handle<Object> ExternalUint16Array::SetValue(Handle<ExternalUint16Array> array,
14470 uint32_t index,
14471 Handle<Object> value) {
14472 return ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(
14473 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000014474}
14475
14476
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014477Handle<Object> ExternalInt32Array::SetValue(Handle<ExternalInt32Array> array,
14478 uint32_t index,
14479 Handle<Object> value) {
14480 return ExternalArrayIntSetter<ExternalInt32Array, int32_t>(
14481 array->GetIsolate(), array, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000014482}
14483
14484
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014485Handle<Object> ExternalUint32Array::SetValue(
14486 Handle<ExternalUint32Array> array,
14487 uint32_t index,
14488 Handle<Object> value) {
Steve Block3ce2e202009-11-05 08:53:23 +000014489 uint32_t cast_value = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014490 if (index < static_cast<uint32_t>(array->length())) {
Steve Block3ce2e202009-11-05 08:53:23 +000014491 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014492 int int_value = Handle<Smi>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000014493 cast_value = static_cast<uint32_t>(int_value);
14494 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014495 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000014496 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
14497 } else {
14498 // Clamp undefined to zero (default). All other types have been
14499 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014500 DCHECK(value->IsUndefined());
Steve Block3ce2e202009-11-05 08:53:23 +000014501 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014502 array->set(index, cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000014503 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014504 return array->GetIsolate()->factory()->NewNumberFromUint(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000014505}
14506
14507
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014508Handle<Object> ExternalFloat32Array::SetValue(
14509 Handle<ExternalFloat32Array> array,
14510 uint32_t index,
14511 Handle<Object> value) {
14512 float cast_value = static_cast<float>(base::OS::nan_value());
14513 if (index < static_cast<uint32_t>(array->length())) {
Steve Block3ce2e202009-11-05 08:53:23 +000014514 if (value->IsSmi()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014515 int int_value = Handle<Smi>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000014516 cast_value = static_cast<float>(int_value);
14517 } else if (value->IsHeapNumber()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014518 double double_value = Handle<HeapNumber>::cast(value)->value();
Steve Block3ce2e202009-11-05 08:53:23 +000014519 cast_value = static_cast<float>(double_value);
14520 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014521 // Clamp undefined to NaN (default). All other types have been
Steve Block3ce2e202009-11-05 08:53:23 +000014522 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014523 DCHECK(value->IsUndefined());
Steve Block3ce2e202009-11-05 08:53:23 +000014524 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014525 array->set(index, cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000014526 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014527 return array->GetIsolate()->factory()->NewNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000014528}
14529
14530
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014531Handle<Object> ExternalFloat64Array::SetValue(
14532 Handle<ExternalFloat64Array> array,
14533 uint32_t index,
14534 Handle<Object> value) {
14535 double double_value = base::OS::nan_value();
14536 if (index < static_cast<uint32_t>(array->length())) {
14537 if (value->IsNumber()) {
14538 double_value = value->Number();
Ben Murdoch257744e2011-11-30 15:57:28 +000014539 } else {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014540 // Clamp undefined to NaN (default). All other types have been
Ben Murdoch257744e2011-11-30 15:57:28 +000014541 // converted to a number type further up in the call chain.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014542 DCHECK(value->IsUndefined());
Ben Murdoch257744e2011-11-30 15:57:28 +000014543 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014544 array->set(index, double_value);
Ben Murdoch257744e2011-11-30 15:57:28 +000014545 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014546 return array->GetIsolate()->factory()->NewNumber(double_value);
Ben Murdoch257744e2011-11-30 15:57:28 +000014547}
14548
14549
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014550Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
14551 Handle<JSGlobalObject> global,
14552 Handle<Name> name) {
14553 DCHECK(!global->HasFastProperties());
14554 int entry = global->property_dictionary()->FindEntry(name);
14555 if (entry == NameDictionary::kNotFound) {
14556 Isolate* isolate = global->GetIsolate();
14557 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
14558 isolate->factory()->the_hole_value());
14559 PropertyDetails details(NONE, NORMAL, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014560 details = details.AsDeleted();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014561 Handle<NameDictionary> dictionary = NameDictionary::Add(
14562 handle(global->property_dictionary()), name, cell, details);
14563 global->set_properties(*dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000014564 return cell;
14565 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014566 Object* value = global->property_dictionary()->ValueAt(entry);
14567 DCHECK(value->IsPropertyCell());
14568 return handle(PropertyCell::cast(value));
Steve Blocka7e24c12009-10-30 11:49:00 +000014569 }
14570}
14571
14572
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014573// This class is used for looking up two character strings in the string table.
Steve Blockd0582a62009-12-15 09:54:21 +000014574// If we don't have a hit we don't want to waste much time so we unroll the
14575// string hash calculation loop here for speed. Doesn't work if the two
14576// characters form a decimal integer, since such strings have a different hash
14577// algorithm.
14578class TwoCharHashTableKey : public HashTableKey {
14579 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014580 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
Steve Blockd0582a62009-12-15 09:54:21 +000014581 : c1_(c1), c2_(c2) {
14582 // Char 1.
Ben Murdochc7cc0282012-03-05 14:35:55 +000014583 uint32_t hash = seed;
14584 hash += c1;
14585 hash += hash << 10;
Steve Blockd0582a62009-12-15 09:54:21 +000014586 hash ^= hash >> 6;
14587 // Char 2.
14588 hash += c2;
14589 hash += hash << 10;
14590 hash ^= hash >> 6;
14591 // GetHash.
14592 hash += hash << 3;
14593 hash ^= hash >> 11;
14594 hash += hash << 15;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014595 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
14596 hash_ = hash;
Steve Blockd0582a62009-12-15 09:54:21 +000014597#ifdef DEBUG
Steve Blockd0582a62009-12-15 09:54:21 +000014598 // If this assert fails then we failed to reproduce the two-character
14599 // version of the string hashing algorithm above. One reason could be
14600 // that we were passed two digits as characters, since the hash
14601 // algorithm is different in that case.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014602 uint16_t chars[2] = {c1, c2};
14603 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
14604 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
14605 DCHECK_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
Steve Blockd0582a62009-12-15 09:54:21 +000014606#endif
Steve Blockd0582a62009-12-15 09:54:21 +000014607 }
14608
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014609 bool IsMatch(Object* o) OVERRIDE {
Steve Blockd0582a62009-12-15 09:54:21 +000014610 if (!o->IsString()) return false;
14611 String* other = String::cast(o);
14612 if (other->length() != 2) return false;
14613 if (other->Get(0) != c1_) return false;
14614 return other->Get(1) == c2_;
14615 }
14616
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014617 uint32_t Hash() OVERRIDE { return hash_; }
14618 uint32_t HashForObject(Object* key) OVERRIDE {
Steve Blockd0582a62009-12-15 09:54:21 +000014619 if (!key->IsString()) return 0;
14620 return String::cast(key)->Hash();
14621 }
14622
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014623 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE {
14624 // The TwoCharHashTableKey is only used for looking in the string
Steve Blockd0582a62009-12-15 09:54:21 +000014625 // table, not for adding to it.
14626 UNREACHABLE();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014627 return MaybeHandle<Object>().ToHandleChecked();
Steve Blockd0582a62009-12-15 09:54:21 +000014628 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000014629
Steve Blockd0582a62009-12-15 09:54:21 +000014630 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014631 uint16_t c1_;
14632 uint16_t c2_;
Steve Blockd0582a62009-12-15 09:54:21 +000014633 uint32_t hash_;
14634};
14635
14636
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014637MaybeHandle<String> StringTable::InternalizeStringIfExists(
14638 Isolate* isolate,
14639 Handle<String> string) {
14640 if (string->IsInternalizedString()) {
14641 return string;
14642 }
14643 return LookupStringIfExists(isolate, string);
14644}
14645
14646
14647MaybeHandle<String> StringTable::LookupStringIfExists(
14648 Isolate* isolate,
14649 Handle<String> string) {
14650 Handle<StringTable> string_table = isolate->factory()->string_table();
14651 InternalizedStringKey key(string);
14652 int entry = string_table->FindEntry(&key);
Steve Blocka7e24c12009-10-30 11:49:00 +000014653 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014654 return MaybeHandle<String>();
Steve Blocka7e24c12009-10-30 11:49:00 +000014655 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014656 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
14657 DCHECK(StringShape(*result).IsInternalized());
14658 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +000014659 }
14660}
14661
14662
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014663MaybeHandle<String> StringTable::LookupTwoCharsStringIfExists(
14664 Isolate* isolate,
14665 uint16_t c1,
14666 uint16_t c2) {
14667 Handle<StringTable> string_table = isolate->factory()->string_table();
14668 TwoCharHashTableKey key(c1, c2, isolate->heap()->HashSeed());
14669 int entry = string_table->FindEntry(&key);
Steve Blockd0582a62009-12-15 09:54:21 +000014670 if (entry == kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014671 return MaybeHandle<String>();
Steve Blockd0582a62009-12-15 09:54:21 +000014672 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014673 Handle<String> result(String::cast(string_table->KeyAt(entry)), isolate);
14674 DCHECK(StringShape(*result).IsInternalized());
14675 return result;
Steve Blockd0582a62009-12-15 09:54:21 +000014676 }
14677}
14678
14679
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014680Handle<String> StringTable::LookupString(Isolate* isolate,
14681 Handle<String> string) {
14682 InternalizedStringKey key(string);
14683 return LookupKey(isolate, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000014684}
14685
14686
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014687Handle<String> StringTable::LookupKey(Isolate* isolate, HashTableKey* key) {
14688 Handle<StringTable> table = isolate->factory()->string_table();
14689 int entry = table->FindEntry(key);
Steve Block9fac8402011-05-12 15:51:54 +010014690
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014691 // String already in table.
Steve Blocka7e24c12009-10-30 11:49:00 +000014692 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014693 return handle(String::cast(table->KeyAt(entry)), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014694 }
14695
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014696 // Adding new string. Grow table if needed.
14697 table = StringTable::EnsureCapacity(table, 1, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000014698
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014699 // Create string object.
14700 Handle<Object> string = key->AsHandle(isolate);
14701 // There must be no attempts to internalize strings that could throw
14702 // InvalidStringLength error.
14703 CHECK(!string.is_null());
Steve Blocka7e24c12009-10-30 11:49:00 +000014704
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014705 // Add the new string and return it along with the string table.
Steve Blocka7e24c12009-10-30 11:49:00 +000014706 entry = table->FindInsertionEntry(key->Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014707 table->set(EntryToIndex(entry), *string);
Steve Blocka7e24c12009-10-30 11:49:00 +000014708 table->ElementAdded();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014709
14710 isolate->factory()->set_string_table(table);
14711 return Handle<String>::cast(string);
Steve Blocka7e24c12009-10-30 11:49:00 +000014712}
14713
14714
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014715Handle<Object> CompilationCacheTable::Lookup(Handle<String> src,
14716 Handle<Context> context) {
14717 Isolate* isolate = GetIsolate();
14718 Handle<SharedFunctionInfo> shared(context->closure()->shared());
14719 StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
14720 RelocInfo::kNoPosition);
Steve Blocka7e24c12009-10-30 11:49:00 +000014721 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014722 if (entry == kNotFound) return isolate->factory()->undefined_value();
14723 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014724}
14725
14726
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014727Handle<Object> CompilationCacheTable::LookupEval(
14728 Handle<String> src, Handle<SharedFunctionInfo> outer_info,
14729 StrictMode strict_mode, int scope_position) {
14730 Isolate* isolate = GetIsolate();
14731 // Cache key is the tuple (source, outer shared function info, scope position)
14732 // to unambiguously identify the context chain the cached eval code assumes.
14733 StringSharedKey key(src, outer_info, strict_mode, scope_position);
Steve Blocka7e24c12009-10-30 11:49:00 +000014734 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014735 if (entry == kNotFound) return isolate->factory()->undefined_value();
14736 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014737}
14738
14739
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014740Handle<Object> CompilationCacheTable::LookupRegExp(Handle<String> src,
14741 JSRegExp::Flags flags) {
14742 Isolate* isolate = GetIsolate();
14743 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000014744 RegExpKey key(src, flags);
14745 int entry = FindEntry(&key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014746 if (entry == kNotFound) return isolate->factory()->undefined_value();
14747 return Handle<Object>(get(EntryToIndex(entry) + 1), isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014748}
14749
14750
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014751Handle<CompilationCacheTable> CompilationCacheTable::Put(
14752 Handle<CompilationCacheTable> cache, Handle<String> src,
14753 Handle<Context> context, Handle<Object> value) {
14754 Isolate* isolate = cache->GetIsolate();
14755 Handle<SharedFunctionInfo> shared(context->closure()->shared());
14756 StringSharedKey key(src, shared, FLAG_use_strict ? STRICT : SLOPPY,
14757 RelocInfo::kNoPosition);
14758 cache = EnsureCapacity(cache, 1, &key);
14759 Handle<Object> k = key.AsHandle(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014760 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014761 cache->set(EntryToIndex(entry), *k);
14762 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014763 cache->ElementAdded();
14764 return cache;
14765}
14766
14767
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014768Handle<CompilationCacheTable> CompilationCacheTable::PutEval(
14769 Handle<CompilationCacheTable> cache, Handle<String> src,
14770 Handle<SharedFunctionInfo> outer_info, Handle<SharedFunctionInfo> value,
14771 int scope_position) {
14772 Isolate* isolate = cache->GetIsolate();
14773 StringSharedKey key(src, outer_info, value->strict_mode(), scope_position);
14774 cache = EnsureCapacity(cache, 1, &key);
14775 Handle<Object> k = key.AsHandle(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000014776 int entry = cache->FindInsertionEntry(key.Hash());
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014777 cache->set(EntryToIndex(entry), *k);
14778 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014779 cache->ElementAdded();
14780 return cache;
14781}
14782
14783
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014784Handle<CompilationCacheTable> CompilationCacheTable::PutRegExp(
14785 Handle<CompilationCacheTable> cache, Handle<String> src,
14786 JSRegExp::Flags flags, Handle<FixedArray> value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014787 RegExpKey key(src, flags);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014788 cache = EnsureCapacity(cache, 1, &key);
Steve Blocka7e24c12009-10-30 11:49:00 +000014789 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000014790 // We store the value in the key slot, and compare the search key
14791 // to the stored value with a custon IsMatch function during lookups.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014792 cache->set(EntryToIndex(entry), *value);
14793 cache->set(EntryToIndex(entry) + 1, *value);
Steve Blocka7e24c12009-10-30 11:49:00 +000014794 cache->ElementAdded();
14795 return cache;
14796}
14797
14798
Ben Murdochb0fe1622011-05-05 13:52:32 +010014799void CompilationCacheTable::Remove(Object* value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014800 DisallowHeapAllocation no_allocation;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014801 Object* the_hole_value = GetHeap()->the_hole_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010014802 for (int entry = 0, size = Capacity(); entry < size; entry++) {
14803 int entry_index = EntryToIndex(entry);
14804 int value_index = entry_index + 1;
14805 if (get(value_index) == value) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010014806 NoWriteBarrierSet(this, entry_index, the_hole_value);
14807 NoWriteBarrierSet(this, value_index, the_hole_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010014808 ElementRemoved();
14809 }
14810 }
14811 return;
14812}
14813
14814
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014815// StringsKey used for HashTable where key is array of internalized strings.
14816class StringsKey : public HashTableKey {
Steve Blocka7e24c12009-10-30 11:49:00 +000014817 public:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014818 explicit StringsKey(Handle<FixedArray> strings) : strings_(strings) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000014819
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014820 bool IsMatch(Object* strings) OVERRIDE {
14821 FixedArray* o = FixedArray::cast(strings);
14822 int len = strings_->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000014823 if (o->length() != len) return false;
14824 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014825 if (o->get(i) != strings_->get(i)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +000014826 }
14827 return true;
14828 }
14829
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014830 uint32_t Hash() OVERRIDE { return HashForObject(*strings_); }
Steve Blocka7e24c12009-10-30 11:49:00 +000014831
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014832 uint32_t HashForObject(Object* obj) OVERRIDE {
14833 FixedArray* strings = FixedArray::cast(obj);
14834 int len = strings->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000014835 uint32_t hash = 0;
14836 for (int i = 0; i < len; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014837 hash ^= String::cast(strings->get(i))->Hash();
Steve Blocka7e24c12009-10-30 11:49:00 +000014838 }
14839 return hash;
14840 }
14841
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014842 Handle<Object> AsHandle(Isolate* isolate) OVERRIDE { return strings_; }
Steve Blocka7e24c12009-10-30 11:49:00 +000014843
14844 private:
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014845 Handle<FixedArray> strings_;
Steve Blocka7e24c12009-10-30 11:49:00 +000014846};
14847
14848
14849Object* MapCache::Lookup(FixedArray* array) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014850 DisallowHeapAllocation no_alloc;
14851 StringsKey key(handle(array));
Steve Blocka7e24c12009-10-30 11:49:00 +000014852 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010014853 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000014854 return get(EntryToIndex(entry) + 1);
14855}
14856
14857
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014858Handle<MapCache> MapCache::Put(
14859 Handle<MapCache> map_cache, Handle<FixedArray> array, Handle<Map> value) {
14860 StringsKey key(array);
Steve Blocka7e24c12009-10-30 11:49:00 +000014861
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014862 Handle<MapCache> new_cache = EnsureCapacity(map_cache, 1, &key);
14863 int entry = new_cache->FindInsertionEntry(key.Hash());
14864 new_cache->set(EntryToIndex(entry), *array);
14865 new_cache->set(EntryToIndex(entry) + 1, *value);
14866 new_cache->ElementAdded();
14867 return new_cache;
Steve Blocka7e24c12009-10-30 11:49:00 +000014868}
14869
14870
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014871template<typename Derived, typename Shape, typename Key>
14872Handle<Derived> Dictionary<Derived, Shape, Key>::New(
14873 Isolate* isolate,
14874 int at_least_space_for,
14875 PretenureFlag pretenure) {
14876 DCHECK(0 <= at_least_space_for);
14877 Handle<Derived> dict = DerivedHashTable::New(isolate,
14878 at_least_space_for,
14879 USE_DEFAULT_MINIMUM_CAPACITY,
14880 pretenure);
14881
John Reck59135872010-11-02 12:39:01 -070014882 // Initialize the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014883 dict->SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
14884 return dict;
Steve Blocka7e24c12009-10-30 11:49:00 +000014885}
14886
14887
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014888template<typename Derived, typename Shape, typename Key>
14889void Dictionary<Derived, Shape, Key>::GenerateNewEnumerationIndices(
14890 Handle<Derived> dictionary) {
14891 Factory* factory = dictionary->GetIsolate()->factory();
14892 int length = dictionary->NumberOfElements();
Steve Blocka7e24c12009-10-30 11:49:00 +000014893
14894 // Allocate and initialize iteration order array.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014895 Handle<FixedArray> iteration_order = factory->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +000014896 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000014897 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000014898 }
14899
14900 // Allocate array with enumeration order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014901 Handle<FixedArray> enumeration_order = factory->NewFixedArray(length);
Steve Blocka7e24c12009-10-30 11:49:00 +000014902
14903 // Fill the enumeration order array with property details.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014904 int capacity = dictionary->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000014905 int pos = 0;
14906 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014907 if (dictionary->IsKey(dictionary->KeyAt(i))) {
14908 int index = dictionary->DetailsAt(i).dictionary_index();
14909 enumeration_order->set(pos++, Smi::FromInt(index));
Steve Blocka7e24c12009-10-30 11:49:00 +000014910 }
14911 }
14912
14913 // Sort the arrays wrt. enumeration order.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014914 iteration_order->SortPairs(*enumeration_order, enumeration_order->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000014915
14916 // Overwrite the enumeration_order with the enumeration indices.
14917 for (int i = 0; i < length; i++) {
14918 int index = Smi::cast(iteration_order->get(i))->value();
14919 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000014920 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000014921 }
14922
14923 // Update the dictionary with new indices.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014924 capacity = dictionary->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000014925 pos = 0;
14926 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014927 if (dictionary->IsKey(dictionary->KeyAt(i))) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014928 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014929 PropertyDetails details = dictionary->DetailsAt(i);
14930 PropertyDetails new_details = PropertyDetails(
14931 details.attributes(), details.type(), enum_index);
14932 dictionary->DetailsAtPut(i, new_details);
Steve Blocka7e24c12009-10-30 11:49:00 +000014933 }
14934 }
14935
14936 // Set the next enumeration index.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014937 dictionary->SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
Steve Blocka7e24c12009-10-30 11:49:00 +000014938}
14939
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014940
14941template<typename Derived, typename Shape, typename Key>
14942Handle<Derived> Dictionary<Derived, Shape, Key>::EnsureCapacity(
14943 Handle<Derived> dictionary, int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014944 // Check whether there are enough enumeration indices to add n elements.
14945 if (Shape::kIsEnumerable &&
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014946 !PropertyDetails::IsValidIndex(dictionary->NextEnumerationIndex() + n)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000014947 // If not, we generate new indices for the properties.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014948 GenerateNewEnumerationIndices(dictionary);
Steve Blocka7e24c12009-10-30 11:49:00 +000014949 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014950 return DerivedHashTable::EnsureCapacity(dictionary, n, key);
Steve Blocka7e24c12009-10-30 11:49:00 +000014951}
14952
14953
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014954template<typename Derived, typename Shape, typename Key>
14955Handle<Object> Dictionary<Derived, Shape, Key>::DeleteProperty(
14956 Handle<Derived> dictionary,
14957 int entry,
14958 JSObject::DeleteMode mode) {
14959 Factory* factory = dictionary->GetIsolate()->factory();
14960 PropertyDetails details = dictionary->DetailsAt(entry);
Steve Blocka7e24c12009-10-30 11:49:00 +000014961 // Ignore attributes if forcing a deletion.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014962 if (!details.IsConfigurable() && mode != JSReceiver::FORCE_DELETION) {
14963 return factory->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000014964 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014965
14966 dictionary->SetEntry(
14967 entry, factory->the_hole_value(), factory->the_hole_value());
14968 dictionary->ElementRemoved();
14969 return factory->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000014970}
14971
14972
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014973template<typename Derived, typename Shape, typename Key>
14974Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
14975 Handle<Derived> dictionary, Key key, Handle<Object> value) {
14976 int entry = dictionary->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000014977
14978 // If the entry is present set the value;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014979 if (entry != Dictionary::kNotFound) {
14980 dictionary->ValueAtPut(entry, *value);
14981 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000014982 }
14983
14984 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014985 dictionary = EnsureCapacity(dictionary, 1, key);
14986#ifdef DEBUG
14987 USE(Shape::AsHandle(dictionary->GetIsolate(), key));
14988#endif
14989 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000014990
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014991 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
14992 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000014993}
14994
14995
Ben Murdochb8a8cc12014-11-26 15:28:44 +000014996template<typename Derived, typename Shape, typename Key>
14997Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
14998 Handle<Derived> dictionary,
14999 Key key,
15000 Handle<Object> value,
15001 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015002 // Valdate key is absent.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015003 SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000015004 // Check whether the dictionary should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015005 dictionary = EnsureCapacity(dictionary, 1, key);
Ben Murdochc7cc0282012-03-05 14:35:55 +000015006
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015007 AddEntry(dictionary, key, value, details, dictionary->Hash(key));
15008 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +000015009}
15010
15011
15012// Add a key, value pair to the dictionary.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015013template<typename Derived, typename Shape, typename Key>
15014void Dictionary<Derived, Shape, Key>::AddEntry(
15015 Handle<Derived> dictionary,
15016 Key key,
15017 Handle<Object> value,
15018 PropertyDetails details,
15019 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015020 // Compute the key object.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015021 Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000015022
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015023 uint32_t entry = dictionary->FindInsertionEntry(hash);
Steve Blocka7e24c12009-10-30 11:49:00 +000015024 // Insert element at empty or deleted entry
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015025 if (!details.IsDeleted() &&
15026 details.dictionary_index() == 0 &&
15027 Shape::kIsEnumerable) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015028 // Assign an enumeration index to the property and update
15029 // SetNextEnumerationIndex.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015030 int index = dictionary->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +000015031 details = PropertyDetails(details.attributes(), details.type(), index);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015032 dictionary->SetNextEnumerationIndex(index + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000015033 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015034 dictionary->SetEntry(entry, k, value, details);
15035 DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
15036 dictionary->KeyAt(entry)->IsName()));
15037 dictionary->ElementAdded();
Steve Blocka7e24c12009-10-30 11:49:00 +000015038}
15039
15040
Ben Murdochc7cc0282012-03-05 14:35:55 +000015041void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015042 DisallowHeapAllocation no_allocation;
Steve Blocka7e24c12009-10-30 11:49:00 +000015043 // If the dictionary requires slow elements an element has already
15044 // been added at a high index.
15045 if (requires_slow_elements()) return;
15046 // Check if this index is high enough that we should require slow
15047 // elements.
15048 if (key > kRequiresSlowElementsLimit) {
15049 set_requires_slow_elements();
15050 return;
15051 }
15052 // Update max key value.
15053 Object* max_index_object = get(kMaxNumberKeyIndex);
15054 if (!max_index_object->IsSmi() || max_number_key() < key) {
15055 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000015056 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000015057 }
15058}
15059
15060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015061Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
15062 Handle<SeededNumberDictionary> dictionary,
15063 uint32_t key,
15064 Handle<Object> value,
15065 PropertyDetails details) {
15066 dictionary->UpdateMaxNumberKey(key);
15067 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
15068 return Add(dictionary, key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000015069}
15070
15071
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015072Handle<UnseededNumberDictionary> UnseededNumberDictionary::AddNumberEntry(
15073 Handle<UnseededNumberDictionary> dictionary,
15074 uint32_t key,
15075 Handle<Object> value) {
15076 SLOW_DCHECK(dictionary->FindEntry(key) == kNotFound);
15077 return Add(dictionary, key, value, PropertyDetails(NONE, NORMAL, 0));
Ben Murdochc7cc0282012-03-05 14:35:55 +000015078}
15079
15080
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015081Handle<SeededNumberDictionary> SeededNumberDictionary::AtNumberPut(
15082 Handle<SeededNumberDictionary> dictionary,
15083 uint32_t key,
15084 Handle<Object> value) {
15085 dictionary->UpdateMaxNumberKey(key);
15086 return AtPut(dictionary, key, value);
Steve Blocka7e24c12009-10-30 11:49:00 +000015087}
15088
15089
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015090Handle<UnseededNumberDictionary> UnseededNumberDictionary::AtNumberPut(
15091 Handle<UnseededNumberDictionary> dictionary,
15092 uint32_t key,
15093 Handle<Object> value) {
15094 return AtPut(dictionary, key, value);
Ben Murdochc7cc0282012-03-05 14:35:55 +000015095}
15096
15097
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015098Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
15099 Handle<SeededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015100 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015101 Handle<Object> value,
15102 PropertyDetails details) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015103 int entry = dictionary->FindEntry(key);
15104 if (entry == kNotFound) {
15105 return AddNumberEntry(dictionary, key, value, details);
15106 }
15107 // Preserve enumeration index.
15108 details = PropertyDetails(details.attributes(),
15109 details.type(),
15110 dictionary->DetailsAt(entry).dictionary_index());
15111 Handle<Object> object_key =
15112 SeededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15113 dictionary->SetEntry(entry, object_key, value, details);
15114 return dictionary;
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015115}
15116
15117
15118Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
15119 Handle<UnseededNumberDictionary> dictionary,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015120 uint32_t key,
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015121 Handle<Object> value) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015122 int entry = dictionary->FindEntry(key);
15123 if (entry == kNotFound) return AddNumberEntry(dictionary, key, value);
15124 Handle<Object> object_key =
15125 UnseededNumberDictionaryShape::AsHandle(dictionary->GetIsolate(), key);
15126 dictionary->SetEntry(entry, object_key, value);
15127 return dictionary;
Ben Murdochc7cc0282012-03-05 14:35:55 +000015128}
15129
15130
Steve Blocka7e24c12009-10-30 11:49:00 +000015131
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015132template<typename Derived, typename Shape, typename Key>
15133int Dictionary<Derived, Shape, Key>::NumberOfElementsFilterAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +000015134 PropertyAttributes filter) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015135 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015136 int result = 0;
15137 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015138 Object* k = DerivedHashTable::KeyAt(i);
15139 if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015140 PropertyDetails details = DetailsAt(i);
15141 if (details.IsDeleted()) continue;
15142 PropertyAttributes attr = details.attributes();
15143 if ((attr & filter) == 0) result++;
15144 }
15145 }
15146 return result;
15147}
15148
15149
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015150template<typename Derived, typename Shape, typename Key>
15151int Dictionary<Derived, Shape, Key>::NumberOfEnumElements() {
Steve Blocka7e24c12009-10-30 11:49:00 +000015152 return NumberOfElementsFilterAttributes(
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015153 static_cast<PropertyAttributes>(DONT_ENUM | SYMBOLIC));
Steve Blocka7e24c12009-10-30 11:49:00 +000015154}
15155
15156
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015157template<typename Derived, typename Shape, typename Key>
15158void Dictionary<Derived, Shape, Key>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015159 FixedArray* storage,
15160 PropertyAttributes filter,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015161 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15162 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
15163 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015164 int index = 0;
15165 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015166 Object* k = DerivedHashTable::KeyAt(i);
15167 if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015168 PropertyDetails details = DetailsAt(i);
15169 if (details.IsDeleted()) continue;
15170 PropertyAttributes attr = details.attributes();
15171 if ((attr & filter) == 0) storage->set(index++, k);
15172 }
15173 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015174 if (sort_mode == Dictionary::SORTED) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015175 storage->SortPairs(storage, index);
15176 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015177 DCHECK(storage->length() >= index);
Steve Blocka7e24c12009-10-30 11:49:00 +000015178}
15179
15180
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015181struct EnumIndexComparator {
15182 explicit EnumIndexComparator(NameDictionary* dict) : dict(dict) { }
15183 bool operator() (Smi* a, Smi* b) {
15184 PropertyDetails da(dict->DetailsAt(a->value()));
15185 PropertyDetails db(dict->DetailsAt(b->value()));
15186 return da.dictionary_index() < db.dictionary_index();
15187 }
15188 NameDictionary* dict;
15189};
15190
15191
15192void NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
15193 int length = storage->length();
Steve Blocka7e24c12009-10-30 11:49:00 +000015194 int capacity = Capacity();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015195 int properties = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +000015196 for (int i = 0; i < capacity; i++) {
15197 Object* k = KeyAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015198 if (IsKey(k) && !k->IsSymbol()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015199 PropertyDetails details = DetailsAt(i);
15200 if (details.IsDeleted() || details.IsDontEnum()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015201 storage->set(properties, Smi::FromInt(i));
15202 properties++;
15203 if (properties == length) break;
Steve Blocka7e24c12009-10-30 11:49:00 +000015204 }
15205 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015206 CHECK_EQ(length, properties);
15207 EnumIndexComparator cmp(this);
15208 Smi** start = reinterpret_cast<Smi**>(storage->GetFirstElementAddress());
15209 std::sort(start, start + length, cmp);
15210 for (int i = 0; i < length; i++) {
15211 int index = Smi::cast(storage->get(i))->value();
15212 storage->set(i, KeyAt(index));
15213 }
Steve Blocka7e24c12009-10-30 11:49:00 +000015214}
15215
15216
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015217template<typename Derived, typename Shape, typename Key>
15218void Dictionary<Derived, Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000015219 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015220 int index,
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015221 PropertyAttributes filter,
15222 typename Dictionary<Derived, Shape, Key>::SortMode sort_mode) {
15223 DCHECK(storage->length() >= NumberOfElementsFilterAttributes(filter));
15224 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015225 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015226 Object* k = DerivedHashTable::KeyAt(i);
15227 if (DerivedHashTable::IsKey(k) && !FilterKey(k, filter)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015228 PropertyDetails details = DetailsAt(i);
15229 if (details.IsDeleted()) continue;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015230 PropertyAttributes attr = details.attributes();
15231 if ((attr & filter) == 0) storage->set(index++, k);
Steve Blocka7e24c12009-10-30 11:49:00 +000015232 }
15233 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015234 if (sort_mode == Dictionary::SORTED) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015235 storage->SortPairs(storage, index);
15236 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015237 DCHECK(storage->length() >= index);
Steve Blocka7e24c12009-10-30 11:49:00 +000015238}
15239
15240
15241// Backwards lookup (slow).
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015242template<typename Derived, typename Shape, typename Key>
15243Object* Dictionary<Derived, Shape, Key>::SlowReverseLookup(Object* value) {
15244 int capacity = DerivedHashTable::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000015245 for (int i = 0; i < capacity; i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015246 Object* k = DerivedHashTable::KeyAt(i);
15247 if (Dictionary::IsKey(k)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000015248 Object* e = ValueAt(i);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015249 if (e->IsPropertyCell()) {
15250 e = PropertyCell::cast(e)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015251 }
15252 if (e == value) return k;
15253 }
15254 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015255 Heap* heap = Dictionary::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010015256 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015257}
15258
15259
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015260Object* ObjectHashTable::Lookup(Handle<Object> key) {
15261 DisallowHeapAllocation no_gc;
15262 DCHECK(IsKey(*key));
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015263
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015264 // If the object does not have an identity hash, it was never used as a key.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015265 Object* hash = key->GetHash();
15266 if (hash->IsUndefined()) {
15267 return GetHeap()->the_hole_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015268 }
15269 int entry = FindEntry(key);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015270 if (entry == kNotFound) return GetHeap()->the_hole_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015271 return get(EntryToIndex(entry) + 1);
15272}
15273
15274
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015275Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
15276 Handle<Object> key,
15277 Handle<Object> value) {
15278 DCHECK(table->IsKey(*key));
15279 DCHECK(!value->IsTheHole());
15280
15281 Isolate* isolate = table->GetIsolate();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015282
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015283 // Make sure the key object has an identity hash code.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015284 Handle<Smi> hash = Object::GetOrCreateHash(isolate, key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015285
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015286 int entry = table->FindEntry(key);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015287
15288 // Key is already in table, just overwrite value.
15289 if (entry != kNotFound) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015290 table->set(EntryToIndex(entry) + 1, *value);
15291 return table;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015292 }
15293
15294 // Check whether the hash table should be extended.
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015295 table = EnsureCapacity(table, 1, key);
15296 table->AddEntry(table->FindInsertionEntry(hash->value()),
15297 *key,
15298 *value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015299 return table;
15300}
15301
15302
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015303Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
15304 Handle<Object> key,
15305 bool* was_present) {
15306 DCHECK(table->IsKey(*key));
15307
15308 Object* hash = key->GetHash();
15309 if (hash->IsUndefined()) {
15310 *was_present = false;
15311 return table;
15312 }
15313
15314 int entry = table->FindEntry(key);
15315 if (entry == kNotFound) {
15316 *was_present = false;
15317 return table;
15318 }
15319
15320 *was_present = true;
15321 table->RemoveEntry(entry);
15322 return Shrink(table, key);
15323}
15324
15325
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015326void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015327 set(EntryToIndex(entry), key);
15328 set(EntryToIndex(entry) + 1, value);
15329 ElementAdded();
15330}
15331
15332
Ben Murdoch3ef787d2012-04-12 10:51:47 +010015333void ObjectHashTable::RemoveEntry(int entry) {
15334 set_the_hole(EntryToIndex(entry));
15335 set_the_hole(EntryToIndex(entry) + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000015336 ElementRemoved();
15337}
15338
15339
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015340Object* WeakHashTable::Lookup(Handle<Object> key) {
15341 DisallowHeapAllocation no_gc;
15342 DCHECK(IsKey(*key));
15343 int entry = FindEntry(key);
15344 if (entry == kNotFound) return GetHeap()->the_hole_value();
15345 return get(EntryToValueIndex(entry));
15346}
15347
15348
15349Handle<WeakHashTable> WeakHashTable::Put(Handle<WeakHashTable> table,
15350 Handle<Object> key,
15351 Handle<Object> value) {
15352 DCHECK(table->IsKey(*key));
15353 int entry = table->FindEntry(key);
15354 // Key is already in table, just overwrite value.
15355 if (entry != kNotFound) {
15356 // TODO(ulan): Skipping write barrier is a temporary solution to avoid
15357 // memory leaks. Remove this once we have special visitor for weak fixed
15358 // arrays.
15359 table->set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
15360 return table;
15361 }
15362
15363 // Check whether the hash table should be extended.
15364 table = EnsureCapacity(table, 1, key, TENURED);
15365
15366 table->AddEntry(table->FindInsertionEntry(table->Hash(key)), key, value);
15367 return table;
15368}
15369
15370
15371void WeakHashTable::AddEntry(int entry,
15372 Handle<Object> key,
15373 Handle<Object> value) {
15374 DisallowHeapAllocation no_allocation;
15375 // TODO(ulan): Skipping write barrier is a temporary solution to avoid
15376 // memory leaks. Remove this once we have special visitor for weak fixed
15377 // arrays.
15378 set(EntryToIndex(entry), *key, SKIP_WRITE_BARRIER);
15379 set(EntryToValueIndex(entry), *value, SKIP_WRITE_BARRIER);
15380 ElementAdded();
15381}
15382
15383
15384template<class Derived, class Iterator, int entrysize>
15385Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Allocate(
15386 Isolate* isolate, int capacity, PretenureFlag pretenure) {
15387 // Capacity must be a power of two, since we depend on being able
15388 // to divide and multiple by 2 (kLoadFactor) to derive capacity
15389 // from number of buckets. If we decide to change kLoadFactor
15390 // to something other than 2, capacity should be stored as another
15391 // field of this object.
15392 capacity = base::bits::RoundUpToPowerOfTwo32(Max(kMinCapacity, capacity));
15393 if (capacity > kMaxCapacity) {
15394 v8::internal::Heap::FatalProcessOutOfMemory("invalid table size", true);
15395 }
15396 int num_buckets = capacity / kLoadFactor;
15397 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArray(
15398 kHashTableStartIndex + num_buckets + (capacity * kEntrySize), pretenure);
15399 backing_store->set_map_no_write_barrier(
15400 isolate->heap()->ordered_hash_table_map());
15401 Handle<Derived> table = Handle<Derived>::cast(backing_store);
15402 for (int i = 0; i < num_buckets; ++i) {
15403 table->set(kHashTableStartIndex + i, Smi::FromInt(kNotFound));
15404 }
15405 table->SetNumberOfBuckets(num_buckets);
15406 table->SetNumberOfElements(0);
15407 table->SetNumberOfDeletedElements(0);
15408 return table;
15409}
15410
15411
15412template<class Derived, class Iterator, int entrysize>
15413Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::EnsureGrowable(
15414 Handle<Derived> table) {
15415 DCHECK(!table->IsObsolete());
15416
15417 int nof = table->NumberOfElements();
15418 int nod = table->NumberOfDeletedElements();
15419 int capacity = table->Capacity();
15420 if ((nof + nod) < capacity) return table;
15421 // Don't need to grow if we can simply clear out deleted entries instead.
15422 // Note that we can't compact in place, though, so we always allocate
15423 // a new table.
15424 return Rehash(table, (nod < (capacity >> 1)) ? capacity << 1 : capacity);
15425}
15426
15427
15428template<class Derived, class Iterator, int entrysize>
15429Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Shrink(
15430 Handle<Derived> table) {
15431 DCHECK(!table->IsObsolete());
15432
15433 int nof = table->NumberOfElements();
15434 int capacity = table->Capacity();
15435 if (nof >= (capacity >> 2)) return table;
15436 return Rehash(table, capacity / 2);
15437}
15438
15439
15440template<class Derived, class Iterator, int entrysize>
15441Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Clear(
15442 Handle<Derived> table) {
15443 DCHECK(!table->IsObsolete());
15444
15445 Handle<Derived> new_table =
15446 Allocate(table->GetIsolate(),
15447 kMinCapacity,
15448 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
15449
15450 table->SetNextTable(*new_table);
15451 table->SetNumberOfDeletedElements(-1);
15452
15453 return new_table;
15454}
15455
15456
15457template<class Derived, class Iterator, int entrysize>
15458Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Remove(
15459 Handle<Derived> table, Handle<Object> key, bool* was_present) {
15460 int entry = table->FindEntry(key);
15461 if (entry == kNotFound) {
15462 *was_present = false;
15463 return table;
15464 }
15465 *was_present = true;
15466 table->RemoveEntry(entry);
15467 return Shrink(table);
15468}
15469
15470
15471template<class Derived, class Iterator, int entrysize>
15472Handle<Derived> OrderedHashTable<Derived, Iterator, entrysize>::Rehash(
15473 Handle<Derived> table, int new_capacity) {
15474 DCHECK(!table->IsObsolete());
15475
15476 Handle<Derived> new_table =
15477 Allocate(table->GetIsolate(),
15478 new_capacity,
15479 table->GetHeap()->InNewSpace(*table) ? NOT_TENURED : TENURED);
15480 int nof = table->NumberOfElements();
15481 int nod = table->NumberOfDeletedElements();
15482 int new_buckets = new_table->NumberOfBuckets();
15483 int new_entry = 0;
15484 int removed_holes_index = 0;
15485
15486 for (int old_entry = 0; old_entry < (nof + nod); ++old_entry) {
15487 Object* key = table->KeyAt(old_entry);
15488 if (key->IsTheHole()) {
15489 table->SetRemovedIndexAt(removed_holes_index++, old_entry);
15490 continue;
15491 }
15492
15493 Object* hash = key->GetHash();
15494 int bucket = Smi::cast(hash)->value() & (new_buckets - 1);
15495 Object* chain_entry = new_table->get(kHashTableStartIndex + bucket);
15496 new_table->set(kHashTableStartIndex + bucket, Smi::FromInt(new_entry));
15497 int new_index = new_table->EntryToIndex(new_entry);
15498 int old_index = table->EntryToIndex(old_entry);
15499 for (int i = 0; i < entrysize; ++i) {
15500 Object* value = table->get(old_index + i);
15501 new_table->set(new_index + i, value);
15502 }
15503 new_table->set(new_index + kChainOffset, chain_entry);
15504 ++new_entry;
15505 }
15506
15507 DCHECK_EQ(nod, removed_holes_index);
15508
15509 new_table->SetNumberOfElements(nof);
15510 table->SetNextTable(*new_table);
15511
15512 return new_table;
15513}
15514
15515
15516template <class Derived, class Iterator, int entrysize>
15517int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
15518 Handle<Object> key, int hash) {
15519 DCHECK(!IsObsolete());
15520
15521 DisallowHeapAllocation no_gc;
15522 DCHECK(!key->IsTheHole());
15523 for (int entry = HashToEntry(hash); entry != kNotFound;
15524 entry = ChainAt(entry)) {
15525 Object* candidate = KeyAt(entry);
15526 if (candidate->SameValueZero(*key))
15527 return entry;
15528 }
15529 return kNotFound;
15530}
15531
15532
15533template <class Derived, class Iterator, int entrysize>
15534int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
15535 Handle<Object> key) {
15536 DisallowHeapAllocation no_gc;
15537 Object* hash = key->GetHash();
15538 if (!hash->IsSmi()) return kNotFound;
15539 return FindEntry(key, Smi::cast(hash)->value());
15540}
15541
15542
15543template <class Derived, class Iterator, int entrysize>
15544int OrderedHashTable<Derived, Iterator, entrysize>::AddEntry(int hash) {
15545 DCHECK(!IsObsolete());
15546
15547 int entry = UsedCapacity();
15548 int bucket = HashToBucket(hash);
15549 int index = EntryToIndex(entry);
15550 Object* chain_entry = get(kHashTableStartIndex + bucket);
15551 set(kHashTableStartIndex + bucket, Smi::FromInt(entry));
15552 set(index + kChainOffset, chain_entry);
15553 SetNumberOfElements(NumberOfElements() + 1);
15554 return index;
15555}
15556
15557
15558template<class Derived, class Iterator, int entrysize>
15559void OrderedHashTable<Derived, Iterator, entrysize>::RemoveEntry(int entry) {
15560 DCHECK(!IsObsolete());
15561
15562 int index = EntryToIndex(entry);
15563 for (int i = 0; i < entrysize; ++i) {
15564 set_the_hole(index + i);
15565 }
15566 SetNumberOfElements(NumberOfElements() - 1);
15567 SetNumberOfDeletedElements(NumberOfDeletedElements() + 1);
15568}
15569
15570
15571template Handle<OrderedHashSet>
15572OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Allocate(
15573 Isolate* isolate, int capacity, PretenureFlag pretenure);
15574
15575template Handle<OrderedHashSet>
15576OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::EnsureGrowable(
15577 Handle<OrderedHashSet> table);
15578
15579template Handle<OrderedHashSet>
15580OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Shrink(
15581 Handle<OrderedHashSet> table);
15582
15583template Handle<OrderedHashSet>
15584OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Clear(
15585 Handle<OrderedHashSet> table);
15586
15587template Handle<OrderedHashSet>
15588OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::Remove(
15589 Handle<OrderedHashSet> table, Handle<Object> key, bool* was_present);
15590
15591template int OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
15592 Handle<Object> key, int hash);
15593template int OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::FindEntry(
15594 Handle<Object> key);
15595
15596template int
15597OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::AddEntry(int hash);
15598
15599template void
15600OrderedHashTable<OrderedHashSet, JSSetIterator, 1>::RemoveEntry(int entry);
15601
15602
15603template Handle<OrderedHashMap>
15604OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Allocate(
15605 Isolate* isolate, int capacity, PretenureFlag pretenure);
15606
15607template Handle<OrderedHashMap>
15608OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::EnsureGrowable(
15609 Handle<OrderedHashMap> table);
15610
15611template Handle<OrderedHashMap>
15612OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Shrink(
15613 Handle<OrderedHashMap> table);
15614
15615template Handle<OrderedHashMap>
15616OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Clear(
15617 Handle<OrderedHashMap> table);
15618
15619template Handle<OrderedHashMap>
15620OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::Remove(
15621 Handle<OrderedHashMap> table, Handle<Object> key, bool* was_present);
15622
15623template int OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
15624 Handle<Object> key, int hash);
15625template int OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::FindEntry(
15626 Handle<Object> key);
15627
15628template int
15629OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::AddEntry(int hash);
15630
15631template void
15632OrderedHashTable<OrderedHashMap, JSMapIterator, 2>::RemoveEntry(int entry);
15633
15634
15635bool OrderedHashSet::Contains(Handle<Object> key) {
15636 return FindEntry(key) != kNotFound;
15637}
15638
15639
15640Handle<OrderedHashSet> OrderedHashSet::Add(Handle<OrderedHashSet> table,
15641 Handle<Object> key) {
15642 int hash = GetOrCreateHash(table->GetIsolate(), key)->value();
15643 if (table->FindEntry(key, hash) != kNotFound) return table;
15644
15645 table = EnsureGrowable(table);
15646
15647 int index = table->AddEntry(hash);
15648 table->set(index, *key);
15649 return table;
15650}
15651
15652
15653Object* OrderedHashMap::Lookup(Handle<Object> key) {
15654 DisallowHeapAllocation no_gc;
15655 int entry = FindEntry(key);
15656 if (entry == kNotFound) return GetHeap()->the_hole_value();
15657 return ValueAt(entry);
15658}
15659
15660
15661Handle<OrderedHashMap> OrderedHashMap::Put(Handle<OrderedHashMap> table,
15662 Handle<Object> key,
15663 Handle<Object> value) {
15664 DCHECK(!key->IsTheHole());
15665
15666 int hash = GetOrCreateHash(table->GetIsolate(), key)->value();
15667 int entry = table->FindEntry(key, hash);
15668
15669 if (entry != kNotFound) {
15670 table->set(table->EntryToIndex(entry) + kValueOffset, *value);
15671 return table;
15672 }
15673
15674 table = EnsureGrowable(table);
15675
15676 int index = table->AddEntry(hash);
15677 table->set(index, *key);
15678 table->set(index + kValueOffset, *value);
15679 return table;
15680}
15681
15682
15683template<class Derived, class TableType>
15684void OrderedHashTableIterator<Derived, TableType>::Transition() {
15685 DisallowHeapAllocation no_allocation;
15686 TableType* table = TableType::cast(this->table());
15687 if (!table->IsObsolete()) return;
15688
15689 int index = Smi::cast(this->index())->value();
15690 while (table->IsObsolete()) {
15691 TableType* next_table = table->NextTable();
15692
15693 if (index > 0) {
15694 int nod = table->NumberOfDeletedElements();
15695
15696 // When we clear the table we set the number of deleted elements to -1.
15697 if (nod == -1) {
15698 index = 0;
15699 } else {
15700 int old_index = index;
15701 for (int i = 0; i < nod; ++i) {
15702 int removed_index = table->RemovedIndexAt(i);
15703 if (removed_index >= old_index) break;
15704 --index;
15705 }
15706 }
15707 }
15708
15709 table = next_table;
15710 }
15711
15712 set_table(table);
15713 set_index(Smi::FromInt(index));
15714}
15715
15716
15717template<class Derived, class TableType>
15718bool OrderedHashTableIterator<Derived, TableType>::HasMore() {
15719 DisallowHeapAllocation no_allocation;
15720 if (this->table()->IsUndefined()) return false;
15721
15722 Transition();
15723
15724 TableType* table = TableType::cast(this->table());
15725 int index = Smi::cast(this->index())->value();
15726 int used_capacity = table->UsedCapacity();
15727
15728 while (index < used_capacity && table->KeyAt(index)->IsTheHole()) {
15729 index++;
15730 }
15731
15732 set_index(Smi::FromInt(index));
15733
15734 if (index < used_capacity) return true;
15735
15736 set_table(GetHeap()->undefined_value());
15737 return false;
15738}
15739
15740
15741template<class Derived, class TableType>
15742Smi* OrderedHashTableIterator<Derived, TableType>::Next(JSArray* value_array) {
15743 DisallowHeapAllocation no_allocation;
15744 if (HasMore()) {
15745 FixedArray* array = FixedArray::cast(value_array->elements());
15746 static_cast<Derived*>(this)->PopulateValueArray(array);
15747 MoveNext();
15748 return Smi::cast(kind());
15749 }
15750 return Smi::FromInt(0);
15751}
15752
15753
15754template Smi*
15755OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Next(
15756 JSArray* value_array);
15757
15758template bool
15759OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::HasMore();
15760
15761template void
15762OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::MoveNext();
15763
15764template Object*
15765OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::CurrentKey();
15766
15767template void
15768OrderedHashTableIterator<JSSetIterator, OrderedHashSet>::Transition();
15769
15770
15771template Smi*
15772OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Next(
15773 JSArray* value_array);
15774
15775template bool
15776OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::HasMore();
15777
15778template void
15779OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::MoveNext();
15780
15781template Object*
15782OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::CurrentKey();
15783
15784template void
15785OrderedHashTableIterator<JSMapIterator, OrderedHashMap>::Transition();
15786
15787
15788DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
15789 DeclaredAccessorDescriptor* descriptor)
15790 : array_(descriptor->serialized_data()->GetDataStartAddress()),
15791 length_(descriptor->serialized_data()->length()),
15792 offset_(0) {
15793}
15794
15795
15796const DeclaredAccessorDescriptorData*
15797 DeclaredAccessorDescriptorIterator::Next() {
15798 DCHECK(offset_ < length_);
15799 uint8_t* ptr = &array_[offset_];
15800 DCHECK(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
15801 const DeclaredAccessorDescriptorData* data =
15802 reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
15803 offset_ += sizeof(*data);
15804 DCHECK(offset_ <= length_);
15805 return data;
15806}
15807
15808
15809Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
15810 Isolate* isolate,
15811 const DeclaredAccessorDescriptorData& descriptor,
15812 Handle<DeclaredAccessorDescriptor> previous) {
15813 int previous_length =
15814 previous.is_null() ? 0 : previous->serialized_data()->length();
15815 int length = sizeof(descriptor) + previous_length;
15816 Handle<ByteArray> serialized_descriptor =
15817 isolate->factory()->NewByteArray(length);
15818 Handle<DeclaredAccessorDescriptor> value =
15819 isolate->factory()->NewDeclaredAccessorDescriptor();
15820 value->set_serialized_data(*serialized_descriptor);
15821 // Copy in the data.
15822 {
15823 DisallowHeapAllocation no_allocation;
15824 uint8_t* array = serialized_descriptor->GetDataStartAddress();
15825 if (previous_length != 0) {
15826 uint8_t* previous_array =
15827 previous->serialized_data()->GetDataStartAddress();
15828 MemCopy(array, previous_array, previous_length);
15829 array += previous_length;
15830 }
15831 DCHECK(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
15832 DeclaredAccessorDescriptorData* data =
15833 reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
15834 *data = descriptor;
15835 }
15836 return value;
15837}
15838
15839
Steve Blocka7e24c12009-10-30 11:49:00 +000015840// Check if there is a break point at this code position.
15841bool DebugInfo::HasBreakPoint(int code_position) {
15842 // Get the break point info object for this code position.
15843 Object* break_point_info = GetBreakPointInfo(code_position);
15844
15845 // If there is no break point info object or no break points in the break
15846 // point info object there is no break point at this code position.
15847 if (break_point_info->IsUndefined()) return false;
15848 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
15849}
15850
15851
15852// Get the break point info object for this code position.
15853Object* DebugInfo::GetBreakPointInfo(int code_position) {
15854 // Find the index of the break point info object for this code position.
15855 int index = GetBreakPointInfoIndex(code_position);
15856
15857 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010015858 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015859 return BreakPointInfo::cast(break_points()->get(index));
15860}
15861
15862
15863// Clear a break point at the specified code position.
15864void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
15865 int code_position,
15866 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015867 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
15868 debug_info->GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +000015869 if (break_point_info->IsUndefined()) return;
15870 BreakPointInfo::ClearBreakPoint(
15871 Handle<BreakPointInfo>::cast(break_point_info),
15872 break_point_object);
15873}
15874
15875
15876void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
15877 int code_position,
15878 int source_position,
15879 int statement_position,
15880 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015881 Isolate* isolate = debug_info->GetIsolate();
15882 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
15883 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +000015884 if (!break_point_info->IsUndefined()) {
15885 BreakPointInfo::SetBreakPoint(
15886 Handle<BreakPointInfo>::cast(break_point_info),
15887 break_point_object);
15888 return;
15889 }
15890
15891 // Adding a new break point for a code position which did not have any
15892 // break points before. Try to find a free slot.
15893 int index = kNoBreakPointInfo;
15894 for (int i = 0; i < debug_info->break_points()->length(); i++) {
15895 if (debug_info->break_points()->get(i)->IsUndefined()) {
15896 index = i;
15897 break;
15898 }
15899 }
15900 if (index == kNoBreakPointInfo) {
15901 // No free slot - extend break point info array.
15902 Handle<FixedArray> old_break_points =
15903 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000015904 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010015905 isolate->factory()->NewFixedArray(
15906 old_break_points->length() +
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015907 DebugInfo::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010015908
15909 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000015910 for (int i = 0; i < old_break_points->length(); i++) {
15911 new_break_points->set(i, old_break_points->get(i));
15912 }
15913 index = old_break_points->length();
15914 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015915 DCHECK(index != kNoBreakPointInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +000015916
15917 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010015918 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
15919 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000015920 new_break_point_info->set_code_position(Smi::FromInt(code_position));
15921 new_break_point_info->set_source_position(Smi::FromInt(source_position));
15922 new_break_point_info->
15923 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010015924 new_break_point_info->set_break_point_objects(
15925 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000015926 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
15927 debug_info->break_points()->set(index, *new_break_point_info);
15928}
15929
15930
15931// Get the break point objects for a code position.
15932Object* DebugInfo::GetBreakPointObjects(int code_position) {
15933 Object* break_point_info = GetBreakPointInfo(code_position);
15934 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010015935 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015936 }
15937 return BreakPointInfo::cast(break_point_info)->break_point_objects();
15938}
15939
15940
15941// Get the total number of break points.
15942int DebugInfo::GetBreakPointCount() {
15943 if (break_points()->IsUndefined()) return 0;
15944 int count = 0;
15945 for (int i = 0; i < break_points()->length(); i++) {
15946 if (!break_points()->get(i)->IsUndefined()) {
15947 BreakPointInfo* break_point_info =
15948 BreakPointInfo::cast(break_points()->get(i));
15949 count += break_point_info->GetBreakPointCount();
15950 }
15951 }
15952 return count;
15953}
15954
15955
15956Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
15957 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010015958 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010015959 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015960 for (int i = 0; i < debug_info->break_points()->length(); i++) {
15961 if (!debug_info->break_points()->get(i)->IsUndefined()) {
15962 Handle<BreakPointInfo> break_point_info =
15963 Handle<BreakPointInfo>(BreakPointInfo::cast(
15964 debug_info->break_points()->get(i)));
15965 if (BreakPointInfo::HasBreakPointObject(break_point_info,
15966 break_point_object)) {
15967 return *break_point_info;
15968 }
15969 }
15970 }
Steve Block44f0eee2011-05-26 01:26:41 +010015971 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000015972}
15973
15974
15975// Find the index of the break point info object for the specified code
15976// position.
15977int DebugInfo::GetBreakPointInfoIndex(int code_position) {
15978 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
15979 for (int i = 0; i < break_points()->length(); i++) {
15980 if (!break_points()->get(i)->IsUndefined()) {
15981 BreakPointInfo* break_point_info =
15982 BreakPointInfo::cast(break_points()->get(i));
15983 if (break_point_info->code_position()->value() == code_position) {
15984 return i;
15985 }
15986 }
15987 }
15988 return kNoBreakPointInfo;
15989}
15990
15991
15992// Remove the specified break point object.
15993void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
15994 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000015995 Isolate* isolate = break_point_info->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +000015996 // If there are no break points just ignore.
15997 if (break_point_info->break_point_objects()->IsUndefined()) return;
15998 // If there is a single break point clear it if it is the same.
15999 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16000 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010016001 break_point_info->set_break_point_objects(
16002 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000016003 }
16004 return;
16005 }
16006 // If there are multiple break points shrink the array
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016007 DCHECK(break_point_info->break_point_objects()->IsFixedArray());
Steve Blocka7e24c12009-10-30 11:49:00 +000016008 Handle<FixedArray> old_array =
16009 Handle<FixedArray>(
16010 FixedArray::cast(break_point_info->break_point_objects()));
16011 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010016012 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016013 int found_count = 0;
16014 for (int i = 0; i < old_array->length(); i++) {
16015 if (old_array->get(i) == *break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016016 DCHECK(found_count == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +000016017 found_count++;
16018 } else {
16019 new_array->set(i - found_count, old_array->get(i));
16020 }
16021 }
16022 // If the break point was found in the list change it.
16023 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
16024}
16025
16026
16027// Add the specified break point object.
16028void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
16029 Handle<Object> break_point_object) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016030 Isolate* isolate = break_point_info->GetIsolate();
16031
Steve Blocka7e24c12009-10-30 11:49:00 +000016032 // If there was no break point objects before just set it.
16033 if (break_point_info->break_point_objects()->IsUndefined()) {
16034 break_point_info->set_break_point_objects(*break_point_object);
16035 return;
16036 }
16037 // If the break point object is the same as before just ignore.
16038 if (break_point_info->break_point_objects() == *break_point_object) return;
16039 // If there was one break point object before replace with array.
16040 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016041 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000016042 array->set(0, break_point_info->break_point_objects());
16043 array->set(1, *break_point_object);
16044 break_point_info->set_break_point_objects(*array);
16045 return;
16046 }
16047 // If there was more than one break point before extend array.
16048 Handle<FixedArray> old_array =
16049 Handle<FixedArray>(
16050 FixedArray::cast(break_point_info->break_point_objects()));
16051 Handle<FixedArray> new_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016052 isolate->factory()->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000016053 for (int i = 0; i < old_array->length(); i++) {
16054 // If the break point was there before just ignore.
16055 if (old_array->get(i) == *break_point_object) return;
16056 new_array->set(i, old_array->get(i));
16057 }
16058 // Add the new break point.
16059 new_array->set(old_array->length(), *break_point_object);
16060 break_point_info->set_break_point_objects(*new_array);
16061}
16062
16063
16064bool BreakPointInfo::HasBreakPointObject(
16065 Handle<BreakPointInfo> break_point_info,
16066 Handle<Object> break_point_object) {
16067 // No break point.
16068 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016069 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000016070 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16071 return break_point_info->break_point_objects() == *break_point_object;
16072 }
16073 // Multiple break points.
16074 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
16075 for (int i = 0; i < array->length(); i++) {
16076 if (array->get(i) == *break_point_object) {
16077 return true;
16078 }
16079 }
16080 return false;
16081}
16082
16083
16084// Get the number of break points.
16085int BreakPointInfo::GetBreakPointCount() {
16086 // No break point.
16087 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016088 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000016089 if (!break_point_objects()->IsFixedArray()) return 1;
16090 // Multiple break points.
16091 return FixedArray::cast(break_point_objects())->length();
16092}
Steve Blocka7e24c12009-10-30 11:49:00 +000016093
16094
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016095Object* JSDate::GetField(Object* object, Smi* index) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016096 return JSDate::cast(object)->DoGetField(
16097 static_cast<FieldIndex>(index->value()));
16098}
16099
16100
16101Object* JSDate::DoGetField(FieldIndex index) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016102 DCHECK(index != kDateValue);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016103
16104 DateCache* date_cache = GetIsolate()->date_cache();
16105
16106 if (index < kFirstUncachedField) {
16107 Object* stamp = cache_stamp();
16108 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
16109 // Since the stamp is not NaN, the value is also not NaN.
16110 int64_t local_time_ms =
16111 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016112 SetCachedFields(local_time_ms, date_cache);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016113 }
16114 switch (index) {
16115 case kYear: return year();
16116 case kMonth: return month();
16117 case kDay: return day();
16118 case kWeekday: return weekday();
16119 case kHour: return hour();
16120 case kMinute: return min();
16121 case kSecond: return sec();
16122 default: UNREACHABLE();
16123 }
16124 }
16125
16126 if (index >= kFirstUTCField) {
16127 return GetUTCField(index, value()->Number(), date_cache);
16128 }
16129
16130 double time = value()->Number();
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016131 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016132
16133 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
16134 int days = DateCache::DaysFromTime(local_time_ms);
16135
16136 if (index == kDays) return Smi::FromInt(days);
16137
16138 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16139 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016140 DCHECK(index == kTimeInDay);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016141 return Smi::FromInt(time_in_day_ms);
16142}
16143
16144
16145Object* JSDate::GetUTCField(FieldIndex index,
16146 double value,
16147 DateCache* date_cache) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016148 DCHECK(index >= kFirstUTCField);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016149
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016150 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016151
16152 int64_t time_ms = static_cast<int64_t>(value);
16153
16154 if (index == kTimezoneOffset) {
16155 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
16156 }
16157
16158 int days = DateCache::DaysFromTime(time_ms);
16159
16160 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
16161
16162 if (index <= kDayUTC) {
16163 int year, month, day;
16164 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16165 if (index == kYearUTC) return Smi::FromInt(year);
16166 if (index == kMonthUTC) return Smi::FromInt(month);
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016167 DCHECK(index == kDayUTC);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016168 return Smi::FromInt(day);
16169 }
16170
16171 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
16172 switch (index) {
16173 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
16174 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
16175 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
16176 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
16177 case kDaysUTC: return Smi::FromInt(days);
16178 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
16179 default: UNREACHABLE();
16180 }
16181
16182 UNREACHABLE();
16183 return NULL;
16184}
16185
16186
16187void JSDate::SetValue(Object* value, bool is_value_nan) {
16188 set_value(value);
16189 if (is_value_nan) {
16190 HeapNumber* nan = GetIsolate()->heap()->nan_value();
16191 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
16192 set_year(nan, SKIP_WRITE_BARRIER);
16193 set_month(nan, SKIP_WRITE_BARRIER);
16194 set_day(nan, SKIP_WRITE_BARRIER);
16195 set_hour(nan, SKIP_WRITE_BARRIER);
16196 set_min(nan, SKIP_WRITE_BARRIER);
16197 set_sec(nan, SKIP_WRITE_BARRIER);
16198 set_weekday(nan, SKIP_WRITE_BARRIER);
16199 } else {
16200 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
16201 }
16202}
16203
16204
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016205void JSDate::SetCachedFields(int64_t local_time_ms, DateCache* date_cache) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010016206 int days = DateCache::DaysFromTime(local_time_ms);
16207 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16208 int year, month, day;
16209 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16210 int weekday = date_cache->Weekday(days);
16211 int hour = time_in_day_ms / (60 * 60 * 1000);
16212 int min = (time_in_day_ms / (60 * 1000)) % 60;
16213 int sec = (time_in_day_ms / 1000) % 60;
16214 set_cache_stamp(date_cache->stamp());
16215 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
16216 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
16217 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
16218 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
16219 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
16220 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
16221 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
16222}
16223
Ben Murdochb8a8cc12014-11-26 15:28:44 +000016224
16225void JSArrayBuffer::Neuter() {
16226 DCHECK(is_external());
16227 set_backing_store(NULL);
16228 set_byte_length(Smi::FromInt(0));
16229}
16230
16231
16232void JSArrayBufferView::NeuterView() {
16233 set_byte_offset(Smi::FromInt(0));
16234 set_byte_length(Smi::FromInt(0));
16235}
16236
16237
16238void JSDataView::Neuter() {
16239 NeuterView();
16240}
16241
16242
16243void JSTypedArray::Neuter() {
16244 NeuterView();
16245 set_length(Smi::FromInt(0));
16246 set_elements(GetHeap()->EmptyExternalArrayForMap(map()));
16247}
16248
16249
16250static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) {
16251 switch (elements_kind) {
16252#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
16253 case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS;
16254
16255 TYPED_ARRAYS(TYPED_ARRAY_CASE)
16256#undef TYPED_ARRAY_CASE
16257
16258 default:
16259 UNREACHABLE();
16260 return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND;
16261 }
16262}
16263
16264
16265Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
16266 Handle<JSTypedArray> typed_array) {
16267
16268 Handle<Map> map(typed_array->map());
16269 Isolate* isolate = typed_array->GetIsolate();
16270
16271 DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind()));
16272
16273 Handle<Map> new_map = Map::TransitionElementsTo(
16274 map,
16275 FixedToExternalElementsKind(map->elements_kind()));
16276
16277 Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
16278 Handle<FixedTypedArrayBase> fixed_typed_array(
16279 FixedTypedArrayBase::cast(typed_array->elements()));
16280 Runtime::SetupArrayBufferAllocatingData(isolate, buffer,
16281 fixed_typed_array->DataSize(), false);
16282 memcpy(buffer->backing_store(),
16283 fixed_typed_array->DataPtr(),
16284 fixed_typed_array->DataSize());
16285 Handle<ExternalArray> new_elements =
16286 isolate->factory()->NewExternalArray(
16287 fixed_typed_array->length(), typed_array->type(),
16288 static_cast<uint8_t*>(buffer->backing_store()));
16289
16290 buffer->set_weak_first_view(*typed_array);
16291 DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value());
16292 typed_array->set_buffer(*buffer);
16293 JSObject::SetMapAndElements(typed_array, new_map, new_elements);
16294
16295 return buffer;
16296}
16297
16298
16299Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
16300 Handle<Object> result(buffer(), GetIsolate());
16301 if (*result != Smi::FromInt(0)) {
16302 DCHECK(IsExternalArrayElementsKind(map()->elements_kind()));
16303 return Handle<JSArrayBuffer>::cast(result);
16304 }
16305 Handle<JSTypedArray> self(this);
16306 return MaterializeArrayBuffer(self);
16307}
16308
16309
16310HeapType* PropertyCell::type() {
16311 return static_cast<HeapType*>(type_raw());
16312}
16313
16314
16315void PropertyCell::set_type(HeapType* type, WriteBarrierMode ignored) {
16316 DCHECK(IsPropertyCell());
16317 set_type_raw(type, ignored);
16318}
16319
16320
16321Handle<HeapType> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
16322 Handle<Object> value) {
16323 Isolate* isolate = cell->GetIsolate();
16324 Handle<HeapType> old_type(cell->type(), isolate);
16325 Handle<HeapType> new_type = HeapType::Constant(value, isolate);
16326
16327 if (new_type->Is(old_type)) return old_type;
16328
16329 cell->dependent_code()->DeoptimizeDependentCodeGroup(
16330 isolate, DependentCode::kPropertyCellChangedGroup);
16331
16332 if (old_type->Is(HeapType::None()) || old_type->Is(HeapType::Undefined())) {
16333 return new_type;
16334 }
16335
16336 return HeapType::Any(isolate);
16337}
16338
16339
16340void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
16341 Handle<Object> value) {
16342 cell->set_value(*value);
16343 if (!HeapType::Any()->Is(cell->type())) {
16344 Handle<HeapType> new_type = UpdatedType(cell, value);
16345 cell->set_type(*new_type);
16346 }
16347}
16348
16349
16350// static
16351void PropertyCell::AddDependentCompilationInfo(Handle<PropertyCell> cell,
16352 CompilationInfo* info) {
16353 Handle<DependentCode> codes =
16354 DependentCode::Insert(handle(cell->dependent_code(), info->isolate()),
16355 DependentCode::kPropertyCellChangedGroup,
16356 info->object_wrapper());
16357 if (*codes != cell->dependent_code()) cell->set_dependent_code(*codes);
16358 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
16359 cell, info->zone());
16360}
16361
Steve Blocka7e24c12009-10-30 11:49:00 +000016362} } // namespace v8::internal