blob: 6cb5e212026de06051e8d83d9000964d4e3a7ba5 [file] [log] [blame]
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001// Copyright 2013 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000030#include "accessors.h"
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000031#include "allocation-site-scopes.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "api.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000033#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "bootstrapper.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "codegen.h"
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000036#include "cpu-profiler.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000039#include "date.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000040#include "elements.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "full-codegen.h"
43#include "hydrogen.h"
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000044#include "isolate-inl.h"
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000045#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000047#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000048#include "objects-visiting-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049#include "macro-assembler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000050#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000053#include "utils.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000054
mads.s.ager31e71382008-08-13 09:32:07 +000055#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000056#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000057#include "disassembler.h"
58#endif
59
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000063
lrn@chromium.org303ada72010-10-27 09:33:13 +000064MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
65 Object* value) {
66 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 { MaybeObject* maybe_result =
68 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +000069 if (!maybe_result->ToObject(&result)) return maybe_result;
70 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000071 JSValue::cast(result)->set_value(value);
72 return result;
73}
74
75
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000076MaybeObject* Object::ToObject(Context* native_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077 if (IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000078 return CreateJSValue(native_context->number_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000079 } else if (IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000080 return CreateJSValue(native_context->boolean_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000081 } else if (IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000082 return CreateJSValue(native_context->string_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083 }
84 ASSERT(IsJSObject());
85 return this;
86}
87
88
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000089MaybeObject* Object::ToObject(Isolate* isolate) {
lrn@chromium.org34e60782011-09-15 07:25:40 +000090 if (IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091 return this;
92 } else if (IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000093 Context* native_context = isolate->context()->native_context();
94 return CreateJSValue(native_context->number_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000095 } else if (IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000096 Context* native_context = isolate->context()->native_context();
97 return CreateJSValue(native_context->boolean_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 } else if (IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000099 Context* native_context = isolate->context()->native_context();
100 return CreateJSValue(native_context->string_function(), this);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000101 } else if (IsSymbol()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000102 Context* native_context = isolate->context()->native_context();
103 return CreateJSValue(native_context->symbol_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104 }
105
106 // Throw a type error.
107 return Failure::InternalError();
108}
109
110
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000111bool Object::BooleanValue() {
112 if (IsBoolean()) return IsTrue();
113 if (IsSmi()) return Smi::cast(this)->value() != 0;
114 if (IsUndefined() || IsNull()) return false;
115 if (IsUndetectableObject()) return false; // Undetectable object is false.
116 if (IsString()) return String::cast(this)->length() != 0;
117 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
118 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119}
120
121
ulan@chromium.org750145a2013-03-07 15:14:13 +0000122void Object::Lookup(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 Object* holder = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000124 if (IsJSReceiver()) {
125 holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000126 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000127 Context* native_context = result->isolate()->context()->native_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000128 if (IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000129 holder = native_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000130 } else if (IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000131 holder = native_context->string_function()->instance_prototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000132 } else if (IsSymbol()) {
133 holder = native_context->symbol_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000134 } else if (IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000135 holder = native_context->boolean_function()->instance_prototype();
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000136 } else {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000137 result->isolate()->PushStackTraceAndDie(
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000138 0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000141 ASSERT(holder != NULL); // Cannot handle null or undefined.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000142 JSReceiver::cast(holder)->Lookup(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143}
144
145
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000146Handle<Object> Object::GetPropertyWithReceiver(
147 Handle<Object> object,
148 Handle<Object> receiver,
149 Handle<Name> name,
150 PropertyAttributes* attributes) {
151 LookupResult lookup(name->GetIsolate());
152 object->Lookup(*name, &lookup);
153 Handle<Object> result =
154 GetProperty(object, receiver, &lookup, name, attributes);
155 ASSERT(*attributes <= ABSENT);
156 return result;
157}
158
159
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000161 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000162 PropertyAttributes* attributes) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000163 LookupResult result(name->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000166 ASSERT(*attributes <= ABSENT);
167 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168}
169
170
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000171bool Object::ToInt32(int32_t* value) {
172 if (IsSmi()) {
173 *value = Smi::cast(this)->value();
174 return true;
175 }
176 if (IsHeapNumber()) {
177 double num = HeapNumber::cast(this)->value();
178 if (FastI2D(FastD2I(num)) == num) {
179 *value = FastD2I(num);
180 return true;
181 }
182 }
183 return false;
184}
185
186
187bool Object::ToUint32(uint32_t* value) {
188 if (IsSmi()) {
189 int num = Smi::cast(this)->value();
190 if (num >= 0) {
191 *value = static_cast<uint32_t>(num);
192 return true;
193 }
194 }
195 if (IsHeapNumber()) {
196 double num = HeapNumber::cast(this)->value();
197 if (num >= 0 && FastUI2D(FastD2UI(num)) == num) {
198 *value = FastD2UI(num);
199 return true;
200 }
201 }
202 return false;
203}
204
205
ulan@chromium.org750145a2013-03-07 15:14:13 +0000206template<typename To>
207static inline To* CheckedCast(void *from) {
208 uintptr_t temp = reinterpret_cast<uintptr_t>(from);
209 ASSERT(temp % sizeof(To) == 0);
210 return reinterpret_cast<To*>(temp);
211}
212
213
214static MaybeObject* PerformCompare(const BitmaskCompareDescriptor& descriptor,
215 char* ptr,
216 Heap* heap) {
217 uint32_t bitmask = descriptor.bitmask;
218 uint32_t compare_value = descriptor.compare_value;
219 uint32_t value;
220 switch (descriptor.size) {
221 case 1:
222 value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
223 compare_value &= 0xff;
224 bitmask &= 0xff;
225 break;
226 case 2:
227 value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
228 compare_value &= 0xffff;
229 bitmask &= 0xffff;
230 break;
231 case 4:
232 value = *CheckedCast<uint32_t>(ptr);
233 break;
234 default:
235 UNREACHABLE();
236 return NULL;
237 }
238 return heap->ToBoolean((bitmask & value) == (bitmask & compare_value));
239}
240
241
242static MaybeObject* PerformCompare(const PointerCompareDescriptor& descriptor,
243 char* ptr,
244 Heap* heap) {
245 uintptr_t compare_value =
246 reinterpret_cast<uintptr_t>(descriptor.compare_value);
247 uintptr_t value = *CheckedCast<uintptr_t>(ptr);
248 return heap->ToBoolean(compare_value == value);
249}
250
251
252static MaybeObject* GetPrimitiveValue(
253 const PrimitiveValueDescriptor& descriptor,
254 char* ptr,
255 Heap* heap) {
256 int32_t int32_value = 0;
257 switch (descriptor.data_type) {
258 case kDescriptorInt8Type:
259 int32_value = *CheckedCast<int8_t>(ptr);
260 break;
261 case kDescriptorUint8Type:
262 int32_value = *CheckedCast<uint8_t>(ptr);
263 break;
264 case kDescriptorInt16Type:
265 int32_value = *CheckedCast<int16_t>(ptr);
266 break;
267 case kDescriptorUint16Type:
268 int32_value = *CheckedCast<uint16_t>(ptr);
269 break;
270 case kDescriptorInt32Type:
271 int32_value = *CheckedCast<int32_t>(ptr);
272 break;
273 case kDescriptorUint32Type: {
274 uint32_t value = *CheckedCast<uint32_t>(ptr);
275 return heap->NumberFromUint32(value);
276 }
277 case kDescriptorBoolType: {
278 uint8_t byte = *CheckedCast<uint8_t>(ptr);
279 return heap->ToBoolean(byte & (0x1 << descriptor.bool_offset));
280 }
281 case kDescriptorFloatType: {
282 float value = *CheckedCast<float>(ptr);
283 return heap->NumberFromDouble(value);
284 }
285 case kDescriptorDoubleType: {
286 double value = *CheckedCast<double>(ptr);
287 return heap->NumberFromDouble(value);
288 }
289 }
290 return heap->NumberFromInt32(int32_value);
291}
292
293
294static MaybeObject* GetDeclaredAccessorProperty(Object* receiver,
295 DeclaredAccessorInfo* info,
296 Isolate* isolate) {
297 char* current = reinterpret_cast<char*>(receiver);
298 DeclaredAccessorDescriptorIterator iterator(info->descriptor());
299 while (true) {
300 const DeclaredAccessorDescriptorData* data = iterator.Next();
301 switch (data->type) {
302 case kDescriptorReturnObject: {
303 ASSERT(iterator.Complete());
304 current = *CheckedCast<char*>(current);
305 return *CheckedCast<Object*>(current);
306 }
307 case kDescriptorPointerDereference:
308 ASSERT(!iterator.Complete());
309 current = *reinterpret_cast<char**>(current);
310 break;
311 case kDescriptorPointerShift:
312 ASSERT(!iterator.Complete());
313 current += data->pointer_shift_descriptor.byte_offset;
314 break;
315 case kDescriptorObjectDereference: {
316 ASSERT(!iterator.Complete());
317 Object* object = CheckedCast<Object>(current);
318 int field = data->object_dereference_descriptor.internal_field;
319 Object* smi = JSObject::cast(object)->GetInternalField(field);
320 ASSERT(smi->IsSmi());
321 current = reinterpret_cast<char*>(smi);
322 break;
323 }
324 case kDescriptorBitmaskCompare:
325 ASSERT(iterator.Complete());
326 return PerformCompare(data->bitmask_compare_descriptor,
327 current,
328 isolate->heap());
329 case kDescriptorPointerCompare:
330 ASSERT(iterator.Complete());
331 return PerformCompare(data->pointer_compare_descriptor,
332 current,
333 isolate->heap());
334 case kDescriptorPrimitiveValue:
335 ASSERT(iterator.Complete());
336 return GetPrimitiveValue(data->primitive_value_descriptor,
337 current,
338 isolate->heap());
339 }
340 }
341 UNREACHABLE();
342 return NULL;
343}
344
345
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +0000346Handle<FixedArray> JSObject::EnsureWritableFastElements(
347 Handle<JSObject> object) {
348 CALL_HEAP_FUNCTION(object->GetIsolate(),
349 object->EnsureWritableFastElements(),
350 FixedArray);
351}
352
353
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000354Handle<Object> JSObject::GetPropertyWithCallback(Handle<JSObject> object,
355 Handle<Object> receiver,
356 Handle<Object> structure,
357 Handle<Name> name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000360 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000361 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000362 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000364 reinterpret_cast<AccessorDescriptor*>(
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000365 Handle<Foreign>::cast(structure)->foreign_address());
366 CALL_HEAP_FUNCTION(isolate,
367 (callback->getter)(isolate, *receiver, callback->data),
368 Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000369 }
370
371 // api style callbacks.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000372 if (structure->IsAccessorInfo()) {
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000373 Handle<AccessorInfo> accessor_info = Handle<AccessorInfo>::cast(structure);
374 if (!accessor_info->IsCompatibleReceiver(*receiver)) {
375 Handle<Object> args[2] = { name, receiver };
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000376 Handle<Object> error =
377 isolate->factory()->NewTypeError("incompatible_method_receiver",
378 HandleVector(args,
379 ARRAY_SIZE(args)));
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000380 isolate->Throw(*error);
381 return Handle<Object>::null();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000382 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000383 // TODO(rossberg): Handling symbols in the API requires changing the API,
384 // so we do not support it for now.
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000385 if (name->IsSymbol()) return isolate->factory()->undefined_value();
ulan@chromium.org750145a2013-03-07 15:14:13 +0000386 if (structure->IsDeclaredAccessorInfo()) {
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000387 CALL_HEAP_FUNCTION(
388 isolate,
389 GetDeclaredAccessorProperty(*receiver,
390 DeclaredAccessorInfo::cast(*structure),
391 isolate),
392 Object);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000393 }
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000394
395 Handle<ExecutableAccessorInfo> data =
396 Handle<ExecutableAccessorInfo>::cast(structure);
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000397 v8::AccessorGetterCallback call_fun =
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000398 v8::ToCData<v8::AccessorGetterCallback>(data->getter());
399 if (call_fun == NULL) return isolate->factory()->undefined_value();
400
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000401 HandleScope scope(isolate);
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000402 Handle<JSObject> self = Handle<JSObject>::cast(receiver);
403 Handle<String> key = Handle<String>::cast(name);
404 LOG(isolate, ApiNamedPropertyAccess("load", *self, *name));
405 PropertyCallbackArguments args(isolate, data->data(), *self, *object);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000406 v8::Handle<v8::Value> result =
407 args.Call(call_fun, v8::Utils::ToLocal(key));
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000408 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 if (result.IsEmpty()) {
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000410 return isolate->factory()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 }
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000412 Handle<Object> return_value = v8::Utils::OpenHandle(*result);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000413 return_value->VerifyApiCallResultType();
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000414 return scope.CloseAndEscape(return_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000415 }
416
417 // __defineGetter__ callback
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000418 Handle<Object> getter(Handle<AccessorPair>::cast(structure)->getter(),
419 isolate);
420 if (getter->IsSpecFunction()) {
421 // TODO(rossberg): nicer would be to cast to some JSCallable here...
422 CALL_HEAP_FUNCTION(
423 isolate,
424 object->GetPropertyWithDefinedGetter(*receiver,
425 JSReceiver::cast(*getter)),
426 Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000427 }
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000428 // Getter is not a function.
429 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000430}
431
432
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000433MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000434 Name* name_raw) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000435 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000436 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000437 Handle<Object> receiver(receiver_raw, isolate);
438 Handle<Object> name(name_raw, isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000439
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000440 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
441 if (name->IsSymbol()) return isolate->heap()->undefined_value();
442
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000443 Handle<Object> args[] = { receiver, name };
444 Handle<Object> result = CallTrap(
445 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000446 if (isolate->has_pending_exception()) return Failure::Exception();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000447
448 return *result;
449}
450
451
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000452Handle<Object> Object::GetProperty(Handle<Object> object,
453 Handle<Name> name) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000454 // TODO(rossberg): The index test should not be here but in the GetProperty
455 // method (or somewhere else entirely). Needs more global clean-up.
456 uint32_t index;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000457 Isolate* isolate = name->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +0000458 if (name->AsArrayIndex(&index))
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000459 return GetElement(isolate, object, index);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000460 CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object);
461}
462
463
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000464Handle<Object> Object::GetElement(Isolate* isolate,
465 Handle<Object> object,
466 uint32_t index) {
467 CALL_HEAP_FUNCTION(isolate, object->GetElement(isolate, index), Object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000468}
469
470
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000471MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
472 uint32_t index) {
473 String* name;
474 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
475 if (!maybe->To<String>(&name)) return maybe;
476 return GetPropertyWithHandler(receiver, name);
477}
478
479
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000480Handle<Object> JSProxy::SetElementWithHandler(Handle<JSProxy> proxy,
481 Handle<JSReceiver> receiver,
482 uint32_t index,
483 Handle<Object> value,
484 StrictModeFlag strict_mode) {
485 Isolate* isolate = proxy->GetIsolate();
486 Handle<String> name = isolate->factory()->Uint32ToString(index);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000487 return SetPropertyWithHandler(
488 proxy, receiver, name, value, NONE, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000489}
490
491
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000492bool JSProxy::HasElementWithHandler(Handle<JSProxy> proxy, uint32_t index) {
493 Isolate* isolate = proxy->GetIsolate();
494 Handle<String> name = isolate->factory()->Uint32ToString(index);
495 return HasPropertyWithHandler(proxy, name);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000496}
497
498
lrn@chromium.org303ada72010-10-27 09:33:13 +0000499MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000500 JSReceiver* getter) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000501 Isolate* isolate = getter->GetIsolate();
502 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000503 Handle<JSReceiver> fun(getter);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000504 Handle<Object> self(receiver, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000505#ifdef ENABLE_DEBUGGER_SUPPORT
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000506 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000507 // Handle stepping into a getter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000508 // TODO(rossberg): should this apply to getters that are function proxies?
509 if (debug->StepInActive() && fun->IsJSFunction()) {
510 debug->HandleStepIn(
511 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000512 }
513#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000514
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000515 bool has_pending_exception;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +0000516 Handle<Object> result = Execution::Call(
517 isolate, fun, self, 0, NULL, &has_pending_exception, true);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 // Check for pending exception and return the result.
519 if (has_pending_exception) return Failure::Exception();
520 return *result;
521}
522
523
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524// Only deal with CALLBACKS and INTERCEPTOR
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000525Handle<Object> JSObject::GetPropertyWithFailedAccessCheck(
526 Handle<JSObject> object,
527 Handle<Object> receiver,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000528 LookupResult* result,
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000529 Handle<Name> name,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000530 PropertyAttributes* attributes) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000531 Isolate* isolate = name->GetIsolate();
ager@chromium.org5c838252010-02-19 08:53:10 +0000532 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533 switch (result->type()) {
534 case CALLBACKS: {
535 // Only allow API accessors.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000536 Handle<Object> callback_obj(result->GetCallbackObject(), isolate);
537 if (callback_obj->IsAccessorInfo()) {
538 if (!AccessorInfo::cast(*callback_obj)->all_can_read()) break;
539 *attributes = result->GetAttributes();
540 // Fall through to GetPropertyWithCallback.
541 } else if (callback_obj->IsAccessorPair()) {
542 if (!AccessorPair::cast(*callback_obj)->all_can_read()) break;
543 // Fall through to GetPropertyWithCallback.
544 } else {
545 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 }
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000547 Handle<JSObject> holder(result->holder(), isolate);
548 return GetPropertyWithCallback(holder, receiver, callback_obj, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000549 }
550 case NORMAL:
551 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000552 case CONSTANT: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553 // Search ALL_CAN_READ accessors in prototype chain.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000554 LookupResult r(isolate);
555 result->holder()->LookupRealNamedPropertyInPrototypes(*name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000556 if (r.IsProperty()) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000557 return GetPropertyWithFailedAccessCheck(
558 object, receiver, &r, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 }
560 break;
561 }
562 case INTERCEPTOR: {
563 // If the object has an interceptor, try real named properties.
564 // No access check in GetPropertyAttributeWithInterceptor.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000565 LookupResult r(isolate);
566 result->holder()->LookupRealNamedProperty(*name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000567 if (r.IsProperty()) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000568 return GetPropertyWithFailedAccessCheck(
569 object, receiver, &r, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000571 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000572 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000573 default:
574 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575 }
576 }
577
ager@chromium.org8bb60582008-12-11 12:02:20 +0000578 // No accessible property found.
579 *attributes = ABSENT;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000580 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_GET);
581 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
582 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583}
584
585
ager@chromium.org870a0b62008-11-04 11:43:05 +0000586PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
587 Object* receiver,
588 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000589 Name* name,
ager@chromium.org870a0b62008-11-04 11:43:05 +0000590 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000591 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000592 switch (result->type()) {
593 case CALLBACKS: {
594 // Only allow API accessors.
595 Object* obj = result->GetCallbackObject();
596 if (obj->IsAccessorInfo()) {
597 AccessorInfo* info = AccessorInfo::cast(obj);
598 if (info->all_can_read()) {
599 return result->GetAttributes();
600 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000601 } else if (obj->IsAccessorPair()) {
602 AccessorPair* pair = AccessorPair::cast(obj);
603 if (pair->all_can_read()) {
604 return result->GetAttributes();
605 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000606 }
607 break;
608 }
609
610 case NORMAL:
611 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000612 case CONSTANT: {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000613 if (!continue_search) break;
614 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000615 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000616 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000617 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000618 return GetPropertyAttributeWithFailedAccessCheck(receiver,
619 &r,
620 name,
621 continue_search);
622 }
623 break;
624 }
625
626 case INTERCEPTOR: {
627 // If the object has an interceptor, try real named properties.
628 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000629 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000630 if (continue_search) {
631 result->holder()->LookupRealNamedProperty(name, &r);
632 } else {
633 result->holder()->LocalLookupRealNamedProperty(name, &r);
634 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000635 if (!r.IsFound()) break;
636 return GetPropertyAttributeWithFailedAccessCheck(receiver,
637 &r,
638 name,
639 continue_search);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000640 }
641
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000642 case HANDLER:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000643 case TRANSITION:
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000644 case NONEXISTENT:
ager@chromium.org5c838252010-02-19 08:53:10 +0000645 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000646 }
647 }
648
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000649 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000650 return ABSENT;
651}
652
653
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000654Object* JSObject::GetNormalizedProperty(LookupResult* result) {
655 ASSERT(!HasFastProperties());
656 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
657 if (IsGlobalObject()) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000658 value = PropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000659 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000660 ASSERT(!value->IsPropertyCell() && !value->IsCell());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000661 return value;
662}
663
664
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000665void JSObject::SetNormalizedProperty(Handle<JSObject> object,
666 LookupResult* result,
667 Handle<Object> value) {
668 ASSERT(!object->HasFastProperties());
669 NameDictionary* property_dictionary = object->property_dictionary();
670 if (object->IsGlobalObject()) {
671 Handle<PropertyCell> cell(PropertyCell::cast(
672 property_dictionary->ValueAt(result->GetDictionaryEntry())));
673 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000674 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000675 property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000676 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000677}
678
679
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000680// TODO(mstarzinger): Temporary wrapper until handlified.
681static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict,
682 Handle<Name> name,
683 Handle<Object> value,
684 PropertyDetails details) {
685 CALL_HEAP_FUNCTION(dict->GetIsolate(),
686 dict->Add(*name, *value, details),
687 NameDictionary);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000688}
689
690
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000691void JSObject::SetNormalizedProperty(Handle<JSObject> object,
692 Handle<Name> name,
693 Handle<Object> value,
694 PropertyDetails details) {
695 ASSERT(!object->HasFastProperties());
696 Handle<NameDictionary> property_dictionary(object->property_dictionary());
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000697
698 if (!name->IsUniqueName()) {
699 name = object->GetIsolate()->factory()->InternalizedStringFromString(
700 Handle<String>::cast(name));
701 }
702
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000703 int entry = property_dictionary->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000704 if (entry == NameDictionary::kNotFound) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000705 Handle<Object> store_value = value;
706 if (object->IsGlobalObject()) {
707 store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000708 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000709
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000710 property_dictionary =
711 NameDictionaryAdd(property_dictionary, name, store_value, details);
712 object->set_properties(*property_dictionary);
713 return;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000714 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000715
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000716 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000717 int enumeration_index;
718 // Preserve the enumeration index unless the property was deleted.
719 if (original_details.IsDeleted()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000720 enumeration_index = property_dictionary->NextEnumerationIndex();
721 property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000722 } else {
723 enumeration_index = original_details.dictionary_index();
724 ASSERT(enumeration_index > 0);
725 }
726
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000727 details = PropertyDetails(
728 details.attributes(), details.type(), enumeration_index);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000729
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000730 if (object->IsGlobalObject()) {
731 Handle<PropertyCell> cell(
732 PropertyCell::cast(property_dictionary->ValueAt(entry)));
733 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000734 // Please note we have to update the property details.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000735 property_dictionary->DetailsAtPut(entry, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000736 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000737 property_dictionary->SetEntry(entry, *name, *value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000738 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000739}
740
741
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000742// TODO(mstarzinger): Temporary wrapper until target is handlified.
743Handle<NameDictionary> NameDictionaryShrink(Handle<NameDictionary> dict,
744 Handle<Name> name) {
745 CALL_HEAP_FUNCTION(dict->GetIsolate(), dict->Shrink(*name), NameDictionary);
746}
747
748
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000749Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
750 Handle<Name> name,
751 DeleteMode mode) {
752 ASSERT(!object->HasFastProperties());
753 Isolate* isolate = object->GetIsolate();
754 Handle<NameDictionary> dictionary(object->property_dictionary());
755 int entry = dictionary->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000756 if (entry != NameDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000757 // If we have a global object set the cell to the hole.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000758 if (object->IsGlobalObject()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000759 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000760 if (details.IsDontDelete()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000761 if (mode != FORCE_DELETION) return isolate->factory()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000762 // When forced to delete global properties, we have to make a
763 // map change to invalidate any ICs that think they can load
764 // from the DontDelete cell without checking if it contains
765 // the hole value.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000766 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
erik.corry@gmail.com88767242012-08-08 14:43:45 +0000767 ASSERT(new_map->is_dictionary_map());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000768 object->set_map(*new_map);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000769 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000770 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000771 Handle<Object> value = isolate->factory()->the_hole_value();
772 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000773 dictionary->DetailsAtPut(entry, details.AsDeleted());
774 } else {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000775 Handle<Object> deleted(dictionary->DeleteProperty(entry, mode), isolate);
776 if (*deleted == isolate->heap()->true_value()) {
777 Handle<NameDictionary> new_properties =
778 NameDictionaryShrink(dictionary, name);
779 object->set_properties(*new_properties);
ager@chromium.org04921a82011-06-27 13:21:41 +0000780 }
781 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000782 }
783 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000784 return isolate->factory()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000785}
786
787
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000788bool JSObject::IsDirty() {
789 Object* cons_obj = map()->constructor();
790 if (!cons_obj->IsJSFunction())
791 return true;
792 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000793 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000794 return true;
795 // If the object is fully fast case and has the same map it was
796 // created with then no changes can have been made to it.
797 return map() != fun->initial_map()
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000798 || !HasFastObjectElements()
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000799 || !HasFastProperties();
800}
801
802
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000803Handle<Object> Object::GetProperty(Handle<Object> object,
804 Handle<Object> receiver,
805 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000806 Handle<Name> key,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000807 PropertyAttributes* attributes) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000808 Isolate* isolate = result->isolate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000809 CALL_HEAP_FUNCTION(
810 isolate,
811 object->GetProperty(*receiver, result, *key, attributes),
812 Object);
813}
814
815
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000816MaybeObject* Object::GetPropertyOrFail(Handle<Object> object,
817 Handle<Object> receiver,
818 LookupResult* result,
819 Handle<Name> key,
820 PropertyAttributes* attributes) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000821 Isolate* isolate = result->isolate();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000822 CALL_HEAP_FUNCTION_PASS_EXCEPTION(
823 isolate,
824 object->GetProperty(*receiver, result, *key, attributes));
825}
826
827
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000828// TODO(yangguo): handlify this and get rid of.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000829MaybeObject* Object::GetProperty(Object* receiver,
830 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000831 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000832 PropertyAttributes* attributes) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000833 Isolate* isolate = name->GetIsolate();
834 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000836#ifdef DEBUG
837 // TODO(mstarzinger): Only because of the AssertNoContextChange, drop as soon
838 // as this method has been fully handlified.
839 HandleScope scope(isolate);
840#endif
841
842 // Make sure that the top context does not change when doing
843 // callbacks or interceptor calls.
844 AssertNoContextChange ncc(isolate);
845
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000846 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000847 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848 // objects more than once in case of interceptors, because the
849 // holder will always be the interceptor holder and the search may
850 // only continue with a current object just after the interceptor
851 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000852 // Proxy handlers do not use the proxy's prototype, so we can skip this.
853 if (!result->IsHandler()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000854 Object* last = result->IsProperty()
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000855 ? result->holder()
856 : Object::cast(heap->null_value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000857 ASSERT(this != this->GetPrototype(isolate));
858 for (Object* current = this;
859 true;
860 current = current->GetPrototype(isolate)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000861 if (current->IsAccessCheckNeeded()) {
862 // Check if we're allowed to read from the current object. Note
863 // that even though we may not actually end up loading the named
864 // property from the current object, we still check that we have
865 // access to it.
866 JSObject* checked = JSObject::cast(current);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000867 if (!isolate->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
868 HandleScope scope(isolate);
869 Handle<Object> value = JSObject::GetPropertyWithFailedAccessCheck(
870 handle(checked, isolate),
871 handle(receiver, isolate),
872 result,
873 handle(name, isolate),
874 attributes);
875 RETURN_IF_EMPTY_HANDLE(isolate, value);
876 return *value;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000879 // Stop traversing the chain once we reach the last object in the
880 // chain; either the holder of the result or null in case of an
881 // absent property.
882 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884 }
885
kasper.lund44510672008-07-25 07:37:58 +0000886 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000889 }
890 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892 switch (result->type()) {
893 case NORMAL:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000894 value = result->holder()->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 return value->IsTheHole() ? heap->undefined_value() : value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000897 case FIELD: {
898 MaybeObject* maybe_result = result->holder()->FastPropertyAt(
899 result->representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000900 result->GetFieldIndex().field_index());
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000901 if (!maybe_result->To(&value)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 return value->IsTheHole() ? heap->undefined_value() : value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000904 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000905 case CONSTANT:
906 return result->GetConstant();
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +0000907 case CALLBACKS: {
908 HandleScope scope(isolate);
909 Handle<Object> value = JSObject::GetPropertyWithCallback(
910 handle(result->holder(), isolate),
911 handle(receiver, isolate),
912 handle(result->GetCallbackObject(), isolate),
913 handle(name, isolate));
914 RETURN_IF_EMPTY_HANDLE(isolate, value);
915 return *value;
916 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917 case HANDLER:
918 return result->proxy()->GetPropertyWithHandler(receiver, name);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000919 case INTERCEPTOR: {
920 HandleScope scope(isolate);
921 Handle<Object> value = JSObject::GetPropertyWithInterceptor(
922 handle(result->holder(), isolate),
923 handle(receiver, isolate),
924 handle(name, isolate),
925 attributes);
926 RETURN_IF_EMPTY_HANDLE(isolate, value);
927 return *value;
928 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000929 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000930 case NONEXISTENT:
931 UNREACHABLE();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000932 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000933 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000934 UNREACHABLE();
935 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000936}
937
938
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000939MaybeObject* Object::GetElementWithReceiver(Isolate* isolate,
940 Object* receiver,
941 uint32_t index) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000942 Heap* heap = isolate->heap();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000943 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000944
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000945 // Iterate up the prototype chain until an element is found or the null
946 // prototype is encountered.
947 for (holder = this;
948 holder != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000949 holder = holder->GetPrototype(isolate)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000950 if (!holder->IsJSObject()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000951 Context* native_context = isolate->context()->native_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000952 if (holder->IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000953 holder = native_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000954 } else if (holder->IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000955 holder = native_context->string_function()->instance_prototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000956 } else if (holder->IsSymbol()) {
957 holder = native_context->symbol_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000958 } else if (holder->IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000959 holder = native_context->boolean_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000960 } else if (holder->IsJSProxy()) {
961 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
962 } else {
963 // Undefined and null have no indexed properties.
964 ASSERT(holder->IsUndefined() || holder->IsNull());
965 return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000966 }
967 }
968
969 // Inline the case for JSObjects. Doing so significantly improves the
970 // performance of fetching elements where checking the prototype chain is
971 // necessary.
972 JSObject* js_object = JSObject::cast(holder);
973
974 // Check access rights if needed.
975 if (js_object->IsAccessCheckNeeded()) {
976 Isolate* isolate = heap->isolate();
977 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
978 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
danno@chromium.org169691d2013-07-15 08:01:13 +0000979 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000980 return heap->undefined_value();
981 }
982 }
983
984 if (js_object->HasIndexedInterceptor()) {
985 return js_object->GetElementWithInterceptor(receiver, index);
986 }
987
988 if (js_object->elements() != heap->empty_fixed_array()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000989 MaybeObject* result = js_object->GetElementsAccessor()->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000990 receiver, js_object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000991 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000993 }
994
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000995 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000996}
997
998
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000999Object* Object::GetPrototype(Isolate* isolate) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001000 if (IsSmi()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001001 Context* context = isolate->context()->native_context();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001002 return context->number_function()->instance_prototype();
1003 }
1004
1005 HeapObject* heap_object = HeapObject::cast(this);
1006
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001007 // The object is either a number, a string, a boolean,
1008 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001009 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001010 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001011 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001012 Context* context = isolate->context()->native_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001014 if (heap_object->IsHeapNumber()) {
1015 return context->number_function()->instance_prototype();
1016 }
1017 if (heap_object->IsString()) {
1018 return context->string_function()->instance_prototype();
1019 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001020 if (heap_object->IsSymbol()) {
1021 return context->symbol_function()->instance_prototype();
1022 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001023 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024 return context->boolean_function()->instance_prototype();
1025 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001026 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027 }
1028}
1029
1030
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001031Map* Object::GetMarkerMap(Isolate* isolate) {
1032 if (IsSmi()) return isolate->heap()->heap_number_map();
1033 return HeapObject::cast(this)->map();
1034}
1035
1036
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001037Object* Object::GetHash() {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001038 // The object is either a number, a name, an odd-ball,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001039 // a real JS object, or a Harmony proxy.
1040 if (IsNumber()) {
1041 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
1042 return Smi::FromInt(hash & Smi::kMaxValue);
1043 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001044 if (IsName()) {
1045 uint32_t hash = Name::cast(this)->Hash();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001046 return Smi::FromInt(hash);
1047 }
1048 if (IsOddball()) {
1049 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
1050 return Smi::FromInt(hash);
1051 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001052
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001053 ASSERT(IsJSReceiver());
1054 return JSReceiver::cast(this)->GetIdentityHash();
1055}
1056
1057
1058Handle<Object> Object::GetOrCreateHash(Handle<Object> object,
1059 Isolate* isolate) {
1060 Handle<Object> hash(object->GetHash(), isolate);
1061 if (hash->IsSmi())
1062 return hash;
1063
1064 ASSERT(object->IsJSReceiver());
1065 return JSReceiver::GetOrCreateIdentityHash(Handle<JSReceiver>::cast(object));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001066}
1067
1068
1069bool Object::SameValue(Object* other) {
1070 if (other == this) return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001071
ulan@chromium.org750145a2013-03-07 15:14:13 +00001072 // The object is either a number, a name, an odd-ball,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001073 // a real JS object, or a Harmony proxy.
1074 if (IsNumber() && other->IsNumber()) {
1075 double this_value = Number();
1076 double other_value = other->Number();
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001077 bool equal = this_value == other_value;
1078 // SameValue(NaN, NaN) is true.
1079 if (!equal) return std::isnan(this_value) && std::isnan(other_value);
1080 // SameValue(0.0, -0.0) is false.
1081 return (this_value != 0) || ((1 / this_value) == (1 / other_value));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001082 }
1083 if (IsString() && other->IsString()) {
1084 return String::cast(this)->Equals(String::cast(other));
1085 }
1086 return false;
1087}
1088
1089
whesse@chromium.org023421e2010-12-21 12:19:12 +00001090void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 HeapStringAllocator allocator;
1092 StringStream accumulator(&allocator);
1093 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001094 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001095}
1096
1097
1098void Object::ShortPrint(StringStream* accumulator) {
1099 if (IsSmi()) {
1100 Smi::cast(this)->SmiPrint(accumulator);
1101 } else if (IsFailure()) {
1102 Failure::cast(this)->FailurePrint(accumulator);
1103 } else {
1104 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
1105 }
1106}
1107
1108
whesse@chromium.org023421e2010-12-21 12:19:12 +00001109void Smi::SmiPrint(FILE* out) {
1110 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111}
1112
1113
1114void Smi::SmiPrint(StringStream* accumulator) {
1115 accumulator->Add("%d", value());
1116}
1117
1118
1119void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001120 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121}
1122
1123
whesse@chromium.org023421e2010-12-21 12:19:12 +00001124void Failure::FailurePrint(FILE* out) {
1125 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126}
1127
1128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1130// English? Returns false for non-ASCII or words that don't start with
1131// a capital letter. The a/an rule follows pronunciation in English.
1132// We don't use the BBC's overcorrect "an historic occasion" though if
1133// you speak a dialect you may well say "an 'istoric occasion".
1134static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001135 if (str->length() == 0) return false; // A nothing.
1136 int c0 = str->Get(0);
1137 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138 if (c0 == 'U') {
1139 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001140 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 }
1142 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001143 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1145 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1146 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001147 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 }
1149 return false;
1150}
1151
1152
lrn@chromium.org303ada72010-10-27 09:33:13 +00001153MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001154#ifdef DEBUG
1155 // Do not attempt to flatten in debug mode when allocation is not
1156 // allowed. This is to avoid an assertion failure when allocating.
1157 // Flattening strings is the only case where we always allow
1158 // allocation because no GC is performed if the allocation fails.
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001159 if (!AllowHeapAllocation::IsAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001160#endif
1161
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001163 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164 case kConsStringTag: {
1165 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001166 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001167 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 }
1169 // There's little point in putting the flat string in new space if the
1170 // cons string is in old space. It can never get GCed until there is
1171 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001173 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001174 Object* object;
1175 String* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001176 if (IsOneByteRepresentation()) {
1177 { MaybeObject* maybe_object =
1178 heap->AllocateRawOneByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001179 if (!maybe_object->ToObject(&object)) return maybe_object;
1180 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001181 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001182 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001183 int first_length = first->length();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001184 uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001185 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001186 String* second = cs->second();
1187 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001188 dest + first_length,
1189 0,
1190 len - first_length);
1191 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001192 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001194 if (!maybe_object->ToObject(&object)) return maybe_object;
1195 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001196 result = String::cast(object);
1197 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001198 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001199 int first_length = first->length();
1200 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001201 String* second = cs->second();
1202 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001203 dest + first_length,
1204 0,
1205 len - first_length);
1206 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 cs->set_first(result);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001208 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001209 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210 }
1211 default:
1212 return this;
1213 }
1214}
1215
1216
ager@chromium.org6f10e412009-02-13 10:11:16 +00001217bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00001218 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001219 // prohibited by the API.
1220 ASSERT(!this->IsExternalString());
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00001221#ifdef ENABLE_SLOW_ASSERTS
ager@chromium.org3811b432009-10-28 14:53:37 +00001222 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001223 // Assert that the resource and the string are equivalent.
1224 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001225 ScopedVector<uc16> smart_chars(this->length());
1226 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1227 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001228 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001229 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001230 }
1231#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001232 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001233 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001234 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001235 return false;
1236 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001237 bool is_ascii = this->IsOneByteRepresentation();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001238 bool is_internalized = this->IsInternalizedString();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001239
1240 // Morph the object to an external string by adjusting the map and
1241 // reinitializing the fields.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001242 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001243 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001244 is_internalized
1245 ? (is_ascii
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001246 ? heap->external_internalized_string_with_one_byte_data_map()
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001247 : heap->external_internalized_string_map())
1248 : (is_ascii
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001249 ? heap->external_string_with_one_byte_data_map()
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001250 : heap->external_string_map()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001251 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001252 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001253 is_internalized
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001254 ? (is_ascii
1255 ? heap->
1256 short_external_internalized_string_with_one_byte_data_map()
1257 : heap->short_external_internalized_string_map())
1258 : (is_ascii
1259 ? heap->short_external_string_with_one_byte_data_map()
1260 : heap->short_external_string_map()));
ager@chromium.org6f10e412009-02-13 10:11:16 +00001261 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001262 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1263 self->set_resource(resource);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001264 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001265
1266 // Fill the remainder of the string with dead wood.
1267 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001268 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001269 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001270 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1271 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001272 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001273 return true;
1274}
1275
1276
1277bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00001278#ifdef ENABLE_SLOW_ASSERTS
ager@chromium.org3811b432009-10-28 14:53:37 +00001279 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001280 // Assert that the resource and the string are equivalent.
1281 ASSERT(static_cast<size_t>(this->length()) == resource->length());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00001282 if (this->IsTwoByteRepresentation()) {
1283 ScopedVector<uint16_t> smart_chars(this->length());
1284 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1285 ASSERT(String::IsOneByte(smart_chars.start(), this->length()));
1286 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001287 ScopedVector<char> smart_chars(this->length());
1288 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1289 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001290 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001291 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001292 }
1293#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001294 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001295 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001296 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001297 return false;
1298 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001299 bool is_internalized = this->IsInternalizedString();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001300
1301 // Morph the object to an external string by adjusting the map and
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001302 // reinitializing the fields. Use short version if space is limited.
1303 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001304 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001305 is_internalized ? heap->external_ascii_internalized_string_map()
1306 : heap->external_ascii_string_map());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001307 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001308 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001309 is_internalized ? heap->short_external_ascii_internalized_string_map()
1310 : heap->short_external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001311 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001312 ExternalAsciiString* self = ExternalAsciiString::cast(this);
1313 self->set_resource(resource);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001314 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001315
1316 // Fill the remainder of the string with dead wood.
1317 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001319 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001320 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1321 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001323 return true;
1324}
1325
1326
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001328 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001329 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 accumulator->Add("<Very long string[%u]>", len);
1331 return;
1332 }
1333
1334 if (!LooksValid()) {
1335 accumulator->Add("<Invalid String>");
1336 return;
1337 }
1338
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001339 ConsStringIteratorOp op;
1340 StringCharacterStream stream(this, &op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341
1342 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +00001343 if (len > kMaxShortPrintLength) {
1344 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 truncated = true;
1346 }
1347 bool ascii = true;
1348 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001349 uint16_t c = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350
1351 if (c < 32 || c >= 127) {
1352 ascii = false;
1353 }
1354 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001355 stream.Reset(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001357 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001359 accumulator->Put(static_cast<char>(stream.GetNext()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 }
1361 accumulator->Put('>');
1362 } else {
1363 // Backslash indicates that the string contains control
1364 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001365 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001366 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001367 uint16_t c = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 if (c == '\n') {
1369 accumulator->Add("\\n");
1370 } else if (c == '\r') {
1371 accumulator->Add("\\r");
1372 } else if (c == '\\') {
1373 accumulator->Add("\\\\");
1374 } else if (c < 32 || c > 126) {
1375 accumulator->Add("\\x%02x", c);
1376 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001377 accumulator->Put(static_cast<char>(c));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378 }
1379 }
1380 if (truncated) {
1381 accumulator->Put('.');
1382 accumulator->Put('.');
1383 accumulator->Put('.');
1384 }
1385 accumulator->Put('>');
1386 }
1387 return;
1388}
1389
1390
1391void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1392 switch (map()->instance_type()) {
1393 case JS_ARRAY_TYPE: {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001394 double length = JSArray::cast(this)->length()->IsUndefined()
1395 ? 0
1396 : JSArray::cast(this)->length()->Number();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001397 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001398 break;
1399 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001400 case JS_WEAK_MAP_TYPE: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 accumulator->Add("<JS WeakMap>");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001402 break;
1403 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001404 case JS_WEAK_SET_TYPE: {
1405 accumulator->Add("<JS WeakSet>");
1406 break;
1407 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001408 case JS_REGEXP_TYPE: {
1409 accumulator->Add("<JS RegExp>");
1410 break;
1411 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 case JS_FUNCTION_TYPE: {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001413 JSFunction* function = JSFunction::cast(this);
1414 Object* fun_name = function->shared()->DebugName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 bool printed = false;
1416 if (fun_name->IsString()) {
1417 String* str = String::cast(fun_name);
1418 if (str->length() > 0) {
1419 accumulator->Add("<JS Function ");
1420 accumulator->Put(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421 printed = true;
1422 }
1423 }
1424 if (!printed) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001425 accumulator->Add("<JS Function");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001427 accumulator->Add(" (SharedFunctionInfo %p)",
1428 reinterpret_cast<void*>(function->shared()));
1429 accumulator->Put('>');
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 break;
1431 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001432 case JS_GENERATOR_OBJECT_TYPE: {
1433 accumulator->Add("<JS Generator>");
1434 break;
1435 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001436 case JS_MODULE_TYPE: {
1437 accumulator->Add("<JS Module>");
1438 break;
1439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001441 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001443 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001444 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001445 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 bool printed = false;
1447 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001448 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1450 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001451 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001453 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001454 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1455 } else {
1456 Object* constructor_name =
1457 JSFunction::cast(constructor)->shared()->name();
1458 if (constructor_name->IsString()) {
1459 String* str = String::cast(constructor_name);
1460 if (str->length() > 0) {
1461 bool vowel = AnWord(str);
1462 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001463 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 vowel ? "n" : "");
1465 accumulator->Put(str);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001466 accumulator->Add(" with %smap %p",
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001467 map_of_this->is_deprecated() ? "deprecated " : "",
1468 map_of_this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001469 printed = true;
1470 }
1471 }
1472 }
1473 }
1474 if (!printed) {
1475 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1476 }
1477 }
1478 if (IsJSValue()) {
1479 accumulator->Add(" value = ");
1480 JSValue::cast(this)->value()->ShortPrint(accumulator);
1481 }
1482 accumulator->Put('>');
1483 break;
1484 }
1485 }
1486}
1487
1488
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001489void JSObject::PrintElementsTransition(
1490 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1491 ElementsKind to_kind, FixedArrayBase* to_elements) {
1492 if (from_kind != to_kind) {
1493 PrintF(file, "elements transition [");
1494 PrintElementsKind(file, from_kind);
1495 PrintF(file, " -> ");
1496 PrintElementsKind(file, to_kind);
1497 PrintF(file, "] in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001498 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001499 PrintF(file, " for ");
1500 ShortPrint(file);
1501 PrintF(file, " from ");
1502 from_elements->ShortPrint(file);
1503 PrintF(file, " to ");
1504 to_elements->ShortPrint(file);
1505 PrintF(file, "\n");
1506 }
1507}
1508
1509
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001510void Map::PrintGeneralization(FILE* file,
rossberg@chromium.org92597162013-08-23 13:28:00 +00001511 const char* reason,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001512 int modify_index,
1513 int split,
1514 int descriptors,
rossberg@chromium.org92597162013-08-23 13:28:00 +00001515 bool constant_to_field,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001516 Representation old_representation,
1517 Representation new_representation) {
1518 PrintF(file, "[generalizing ");
1519 constructor_name()->PrintOn(file);
1520 PrintF(file, "] ");
1521 String::cast(instance_descriptors()->GetKey(modify_index))->PrintOn(file);
rossberg@chromium.org92597162013-08-23 13:28:00 +00001522 if (constant_to_field) {
1523 PrintF(file, ":c->f");
1524 } else {
1525 PrintF(file, ":%s->%s",
1526 old_representation.Mnemonic(),
1527 new_representation.Mnemonic());
1528 }
1529 PrintF(file, " (");
1530 if (strlen(reason) > 0) {
1531 PrintF(file, "%s", reason);
1532 } else {
1533 PrintF(file, "+%i maps", descriptors - split);
1534 }
1535 PrintF(file, ") [");
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001536 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
1537 PrintF(file, "]\n");
1538}
1539
1540
1541void JSObject::PrintInstanceMigration(FILE* file,
1542 Map* original_map,
1543 Map* new_map) {
1544 PrintF(file, "[migrating ");
1545 map()->constructor_name()->PrintOn(file);
1546 PrintF(file, "] ");
1547 DescriptorArray* o = original_map->instance_descriptors();
1548 DescriptorArray* n = new_map->instance_descriptors();
1549 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
1550 Representation o_r = o->GetDetails(i).representation();
1551 Representation n_r = n->GetDetails(i).representation();
1552 if (!o_r.Equals(n_r)) {
1553 String::cast(o->GetKey(i))->PrintOn(file);
1554 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
1555 } else if (o->GetDetails(i).type() == CONSTANT &&
1556 n->GetDetails(i).type() == FIELD) {
1557 Name* name = o->GetKey(i);
1558 if (name->IsString()) {
1559 String::cast(name)->PrintOn(file);
1560 } else {
1561 PrintF(file, "???");
1562 }
1563 PrintF(file, " ");
1564 }
1565 }
1566 PrintF(file, "\n");
1567}
1568
1569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001570void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 Heap* heap = GetHeap();
1572 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573 accumulator->Add("!!!INVALID POINTER!!!");
1574 return;
1575 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001576 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 accumulator->Add("!!!INVALID MAP!!!");
1578 return;
1579 }
1580
1581 accumulator->Add("%p ", this);
1582
1583 if (IsString()) {
1584 String::cast(this)->StringShortPrint(accumulator);
1585 return;
1586 }
1587 if (IsJSObject()) {
1588 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1589 return;
1590 }
1591 switch (map()->instance_type()) {
1592 case MAP_TYPE:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001593 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 break;
1595 case FIXED_ARRAY_TYPE:
1596 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1597 break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001598 case FIXED_DOUBLE_ARRAY_TYPE:
1599 accumulator->Add("<FixedDoubleArray[%u]>",
1600 FixedDoubleArray::cast(this)->length());
1601 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 case BYTE_ARRAY_TYPE:
1603 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1604 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001605 case FREE_SPACE_TYPE:
1606 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1607 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001608 case EXTERNAL_PIXEL_ARRAY_TYPE:
1609 accumulator->Add("<ExternalPixelArray[%u]>",
1610 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001611 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001612 case EXTERNAL_BYTE_ARRAY_TYPE:
1613 accumulator->Add("<ExternalByteArray[%u]>",
1614 ExternalByteArray::cast(this)->length());
1615 break;
1616 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1617 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1618 ExternalUnsignedByteArray::cast(this)->length());
1619 break;
1620 case EXTERNAL_SHORT_ARRAY_TYPE:
1621 accumulator->Add("<ExternalShortArray[%u]>",
1622 ExternalShortArray::cast(this)->length());
1623 break;
1624 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1625 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1626 ExternalUnsignedShortArray::cast(this)->length());
1627 break;
1628 case EXTERNAL_INT_ARRAY_TYPE:
1629 accumulator->Add("<ExternalIntArray[%u]>",
1630 ExternalIntArray::cast(this)->length());
1631 break;
1632 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1633 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1634 ExternalUnsignedIntArray::cast(this)->length());
1635 break;
1636 case EXTERNAL_FLOAT_ARRAY_TYPE:
1637 accumulator->Add("<ExternalFloatArray[%u]>",
1638 ExternalFloatArray::cast(this)->length());
1639 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001640 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1641 accumulator->Add("<ExternalDoubleArray[%u]>",
1642 ExternalDoubleArray::cast(this)->length());
1643 break;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001644 case SHARED_FUNCTION_INFO_TYPE: {
1645 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
1646 SmartArrayPointer<char> debug_name =
1647 shared->DebugName()->ToCString();
1648 if (debug_name[0] != 0) {
1649 accumulator->Add("<SharedFunctionInfo %s>", *debug_name);
1650 } else {
1651 accumulator->Add("<SharedFunctionInfo>");
1652 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001653 break;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001654 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001655 case JS_MESSAGE_OBJECT_TYPE:
1656 accumulator->Add("<JSMessageObject>");
1657 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658#define MAKE_STRUCT_CASE(NAME, Name, name) \
1659 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001660 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001661 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001662 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663 break;
1664 STRUCT_LIST(MAKE_STRUCT_CASE)
1665#undef MAKE_STRUCT_CASE
1666 case CODE_TYPE:
1667 accumulator->Add("<Code>");
1668 break;
1669 case ODDBALL_TYPE: {
1670 if (IsUndefined())
1671 accumulator->Add("<undefined>");
1672 else if (IsTheHole())
1673 accumulator->Add("<the hole>");
1674 else if (IsNull())
1675 accumulator->Add("<null>");
1676 else if (IsTrue())
1677 accumulator->Add("<true>");
1678 else if (IsFalse())
1679 accumulator->Add("<false>");
1680 else
1681 accumulator->Add("<Odd Oddball>");
1682 break;
1683 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001684 case SYMBOL_TYPE: {
1685 Symbol* symbol = Symbol::cast(this);
1686 accumulator->Add("<Symbol: %d", symbol->Hash());
1687 if (!symbol->name()->IsUndefined()) {
1688 accumulator->Add(" ");
1689 String::cast(symbol->name())->StringShortPrint(accumulator);
1690 }
1691 accumulator->Add(">");
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001692 break;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001693 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 case HEAP_NUMBER_TYPE:
1695 accumulator->Add("<Number: ");
1696 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1697 accumulator->Put('>');
1698 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001699 case JS_PROXY_TYPE:
1700 accumulator->Add("<JSProxy>");
1701 break;
1702 case JS_FUNCTION_PROXY_TYPE:
1703 accumulator->Add("<JSFunctionProxy>");
1704 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001705 case FOREIGN_TYPE:
1706 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001707 break;
danno@chromium.org41728482013-06-12 22:31:22 +00001708 case CELL_TYPE:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001709 accumulator->Add("Cell for ");
danno@chromium.org41728482013-06-12 22:31:22 +00001710 Cell::cast(this)->value()->ShortPrint(accumulator);
1711 break;
1712 case PROPERTY_CELL_TYPE:
1713 accumulator->Add("PropertyCell for ");
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001714 PropertyCell::cast(this)->value()->ShortPrint(accumulator);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001715 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001716 default:
1717 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1718 break;
1719 }
1720}
1721
1722
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723void HeapObject::Iterate(ObjectVisitor* v) {
1724 // Handle header
1725 IteratePointer(v, kMapOffset);
1726 // Handle object body
1727 Map* m = map();
1728 IterateBody(m->instance_type(), SizeFromMap(m), v);
1729}
1730
1731
1732void HeapObject::IterateBody(InstanceType type, int object_size,
1733 ObjectVisitor* v) {
1734 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1735 // During GC, the map pointer field is encoded.
1736 if (type < FIRST_NONSTRING_TYPE) {
1737 switch (type & kStringRepresentationMask) {
1738 case kSeqStringTag:
1739 break;
1740 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001741 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001742 break;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001743 case kSlicedStringTag:
1744 SlicedString::BodyDescriptor::IterateBody(this, v);
1745 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001746 case kExternalStringTag:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001747 if ((type & kStringEncodingMask) == kOneByteStringTag) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001748 reinterpret_cast<ExternalAsciiString*>(this)->
1749 ExternalAsciiStringIterateBody(v);
1750 } else {
1751 reinterpret_cast<ExternalTwoByteString*>(this)->
1752 ExternalTwoByteStringIterateBody(v);
1753 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 break;
1755 }
1756 return;
1757 }
1758
1759 switch (type) {
1760 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001761 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 break;
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001763 case CONSTANT_POOL_ARRAY_TYPE:
1764 reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
1765 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001766 case FIXED_DOUBLE_ARRAY_TYPE:
1767 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001769 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001770 case JS_GENERATOR_OBJECT_TYPE:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001771 case JS_MODULE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 case JS_VALUE_TYPE:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001773 case JS_DATE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 case JS_ARRAY_TYPE:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001775 case JS_ARRAY_BUFFER_TYPE:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001776 case JS_TYPED_ARRAY_TYPE:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001777 case JS_DATA_VIEW_TYPE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001778 case JS_SET_TYPE:
1779 case JS_MAP_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001780 case JS_WEAK_MAP_TYPE:
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001781 case JS_WEAK_SET_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001782 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001783 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001786 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001787 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001788 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001789 case JS_FUNCTION_TYPE:
1790 reinterpret_cast<JSFunction*>(this)
1791 ->JSFunctionIterateBody(object_size, v);
1792 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001793 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001794 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001796 case JS_PROXY_TYPE:
1797 JSProxy::BodyDescriptor::IterateBody(this, v);
1798 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001799 case JS_FUNCTION_PROXY_TYPE:
1800 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1801 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001802 case FOREIGN_TYPE:
1803 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 break;
1805 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001806 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 break;
1808 case CODE_TYPE:
1809 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1810 break;
danno@chromium.org41728482013-06-12 22:31:22 +00001811 case CELL_TYPE:
1812 Cell::BodyDescriptor::IterateBody(this, v);
1813 break;
1814 case PROPERTY_CELL_TYPE:
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001815 PropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001816 break;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001817 case SYMBOL_TYPE:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001818 Symbol::BodyDescriptor::IterateBody(this, v);
1819 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001820 case HEAP_NUMBER_TYPE:
1821 case FILLER_TYPE:
1822 case BYTE_ARRAY_TYPE:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001823 case FREE_SPACE_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001824 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001825 case EXTERNAL_BYTE_ARRAY_TYPE:
1826 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1827 case EXTERNAL_SHORT_ARRAY_TYPE:
1828 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1829 case EXTERNAL_INT_ARRAY_TYPE:
1830 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1831 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001832 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001834 case SHARED_FUNCTION_INFO_TYPE: {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00001835 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001837 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001838
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839#define MAKE_STRUCT_CASE(NAME, Name, name) \
1840 case NAME##_TYPE:
1841 STRUCT_LIST(MAKE_STRUCT_CASE)
1842#undef MAKE_STRUCT_CASE
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001843 if (type == ALLOCATION_SITE_TYPE) {
1844 AllocationSite::BodyDescriptor::IterateBody(this, v);
1845 } else {
1846 StructBodyDescriptor::IterateBody(this, object_size, v);
1847 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001848 break;
1849 default:
1850 PrintF("Unknown type: %d\n", type);
1851 UNREACHABLE();
1852 }
1853}
1854
1855
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001856bool HeapNumber::HeapNumberBooleanValue() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001858#if __BYTE_ORDER == __LITTLE_ENDIAN
1859 union IeeeDoubleLittleEndianArchType u;
1860#elif __BYTE_ORDER == __BIG_ENDIAN
1861 union IeeeDoubleBigEndianArchType u;
1862#endif
1863 u.d = value();
1864 if (u.bits.exp == 2047) {
1865 // Detect NaN for IEEE double precision floating point.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001866 if ((u.bits.man_low | u.bits.man_high) != 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001868 if (u.bits.exp == 0) {
1869 // Detect +0, and -0 for IEEE double precision floating point.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001870 if ((u.bits.man_low | u.bits.man_high) == 0) return false;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001871 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001872 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873}
1874
1875
whesse@chromium.org023421e2010-12-21 12:19:12 +00001876void HeapNumber::HeapNumberPrint(FILE* out) {
1877 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878}
1879
1880
1881void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1882 // The Windows version of vsnprintf can allocate when printing a %g string
1883 // into a buffer that may not be big enough. We don't want random memory
1884 // allocation when producing post-crash stack traces, so we print into a
1885 // buffer that is plenty big enough for any floating point number, then
1886 // print that using vsnprintf (which may truncate but never allocate if
1887 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001888 EmbeddedVector<char, 100> buffer;
1889 OS::SNPrintF(buffer, "%.16g", Number());
1890 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891}
1892
1893
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001894String* JSReceiver::class_name() {
1895 if (IsJSFunction() && IsJSFunctionProxy()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001896 return GetHeap()->function_class_string();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001898 if (map()->constructor()->IsJSFunction()) {
1899 JSFunction* constructor = JSFunction::cast(map()->constructor());
1900 return String::cast(constructor->shared()->instance_class_name());
1901 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001902 // If the constructor is not present, return "Object".
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001903 return GetHeap()->Object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904}
1905
1906
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001907String* Map::constructor_name() {
1908 if (constructor()->IsJSFunction()) {
1909 JSFunction* constructor = JSFunction::cast(this->constructor());
ager@chromium.orga1645e22009-09-09 19:27:10 +00001910 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001911 if (name->length() > 0) return name;
1912 String* inferred_name = constructor->shared()->inferred_name();
1913 if (inferred_name->length() > 0) return inferred_name;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001914 Object* proto = prototype();
vegorov@chromium.org42841962010-10-18 11:18:59 +00001915 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001916 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001917 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001918 // If the constructor is not present, return "Object".
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001919 return GetHeap()->Object_string();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001920}
1921
1922
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001923String* JSReceiver::constructor_name() {
1924 return map()->constructor_name();
1925}
1926
1927
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001928// TODO(mstarzinger): Temporary wrapper until handlified.
1929static Handle<Object> NewStorageFor(Isolate* isolate,
1930 Handle<Object> object,
1931 Representation representation) {
1932 Heap* heap = isolate->heap();
1933 CALL_HEAP_FUNCTION(isolate,
1934 object->AllocateNewStorageFor(heap, representation),
1935 Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936}
1937
1938
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001939void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object,
1940 Handle<Map> new_map,
1941 Handle<Name> name,
1942 Handle<Object> value,
1943 int field_index,
1944 Representation representation) {
1945 Isolate* isolate = object->GetIsolate();
1946
1947 // This method is used to transition to a field. If we are transitioning to a
1948 // double field, allocate new storage.
1949 Handle<Object> storage = NewStorageFor(isolate, value, representation);
1950
1951 if (object->map()->unused_property_fields() == 0) {
1952 int new_unused = new_map->unused_property_fields();
1953 Handle<FixedArray> properties(object->properties());
1954 Handle<FixedArray> values = isolate->factory()->CopySizeFixedArray(
1955 properties, properties->length() + new_unused + 1);
1956 object->set_properties(*values);
1957 }
1958
1959 object->set_map(*new_map);
1960 object->FastPropertyAtPut(field_index, *storage);
1961}
1962
1963
1964static MaybeObject* CopyAddFieldDescriptor(Map* map,
1965 Name* name,
1966 int index,
1967 PropertyAttributes attributes,
1968 Representation representation,
1969 TransitionFlag flag) {
1970 Map* new_map;
1971 FieldDescriptor new_field_desc(name, index, attributes, representation);
1972 MaybeObject* maybe_map = map->CopyAddDescriptor(&new_field_desc, flag);
1973 if (!maybe_map->To(&new_map)) return maybe_map;
1974 int unused_property_fields = map->unused_property_fields() - 1;
1975 if (unused_property_fields < 0) {
1976 unused_property_fields += JSObject::kFieldsAdded;
1977 }
1978 new_map->set_unused_property_fields(unused_property_fields);
1979 return new_map;
1980}
1981
1982
1983static Handle<Map> CopyAddFieldDescriptor(Handle<Map> map,
1984 Handle<Name> name,
1985 int index,
1986 PropertyAttributes attributes,
1987 Representation representation,
1988 TransitionFlag flag) {
1989 CALL_HEAP_FUNCTION(map->GetIsolate(),
1990 CopyAddFieldDescriptor(
1991 *map, *name, index, attributes, representation, flag),
1992 Map);
1993}
1994
1995
1996void JSObject::AddFastProperty(Handle<JSObject> object,
1997 Handle<Name> name,
1998 Handle<Object> value,
1999 PropertyAttributes attributes,
2000 StoreFromKeyed store_mode,
2001 ValueType value_type,
2002 TransitionFlag flag) {
2003 ASSERT(!object->IsJSGlobalProxy());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002004 ASSERT(DescriptorArray::kNotFound ==
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002005 object->map()->instance_descriptors()->Search(
2006 *name, object->map()->NumberOfOwnDescriptors()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002007
ulan@chromium.org750145a2013-03-07 15:14:13 +00002008 // Normalize the object if the name is an actual name (not the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002009 // hidden strings) and is not a real identifier.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002010 // Normalize the object if it will have too many fast properties.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002011 Isolate* isolate = object->GetIsolate();
2012 if (!name->IsCacheable(isolate) ||
2013 object->TooManyFastProperties(store_mode)) {
2014 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
2015 AddSlowProperty(object, name, value, attributes);
2016 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017 }
2018
2019 // Compute the new index for new field.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002020 int index = object->map()->NextFreePropertyIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021
2022 // Allocate new instance descriptors with (name, index) added
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002023 if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED;
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002024 Representation representation = value->OptimalRepresentation(value_type);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002025 Handle<Map> new_map = CopyAddFieldDescriptor(
2026 handle(object->map()), name, index, attributes, representation, flag);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002027
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002028 AddFastPropertyUsingMap(object, new_map, name, value, index, representation);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029}
2030
2031
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002032static MaybeObject* CopyAddConstantDescriptor(Map* map,
2033 Name* name,
2034 Object* value,
2035 PropertyAttributes attributes,
2036 TransitionFlag flag) {
2037 ConstantDescriptor new_constant_desc(name, value, attributes);
2038 return map->CopyAddDescriptor(&new_constant_desc, flag);
2039}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002040
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002041
2042static Handle<Map> CopyAddConstantDescriptor(Handle<Map> map,
2043 Handle<Name> name,
2044 Handle<Object> value,
2045 PropertyAttributes attributes,
2046 TransitionFlag flag) {
2047 CALL_HEAP_FUNCTION(map->GetIsolate(),
2048 CopyAddConstantDescriptor(
2049 *map, *name, *value, attributes, flag),
2050 Map);
2051}
2052
2053
2054void JSObject::AddConstantProperty(Handle<JSObject> object,
2055 Handle<Name> name,
2056 Handle<Object> constant,
2057 PropertyAttributes attributes,
2058 TransitionFlag initial_flag) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002059 TransitionFlag flag =
rossberg@chromium.org92597162013-08-23 13:28:00 +00002060 // Do not add transitions to global objects.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002061 (object->IsGlobalObject() ||
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002062 // Don't add transitions to special properties with non-trivial
2063 // attributes.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002064 attributes != NONE)
2065 ? OMIT_TRANSITION
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002066 : initial_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002067
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002068 // Allocate new instance descriptors with (name, constant) added.
2069 Handle<Map> new_map = CopyAddConstantDescriptor(
2070 handle(object->map()), name, constant, attributes, flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002072 object->set_map(*new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073}
2074
2075
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002076void JSObject::AddSlowProperty(Handle<JSObject> object,
2077 Handle<Name> name,
2078 Handle<Object> value,
2079 PropertyAttributes attributes) {
2080 ASSERT(!object->HasFastProperties());
2081 Isolate* isolate = object->GetIsolate();
2082 Handle<NameDictionary> dict(object->property_dictionary());
2083 if (object->IsGlobalObject()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002084 // In case name is an orphaned property reuse the cell.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002085 int entry = dict->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002086 if (entry != NameDictionary::kNotFound) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002087 Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
2088 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002089 // Assign an enumeration index to the property and update
2090 // SetNextEnumerationIndex.
2091 int index = dict->NextEnumerationIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002092 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002093 dict->SetNextEnumerationIndex(index + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002094 dict->SetEntry(entry, *name, *cell, details);
2095 return;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002096 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002097 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
2098 PropertyCell::SetValueInferType(cell, value);
2099 value = cell;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002100 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002101 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002102 Handle<NameDictionary> result = NameDictionaryAdd(dict, name, value, details);
2103 if (*dict != *result) object->set_properties(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002104}
2105
2106
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002107Handle<Object> JSObject::AddProperty(Handle<JSObject> object,
2108 Handle<Name> name,
2109 Handle<Object> value,
2110 PropertyAttributes attributes,
2111 StrictModeFlag strict_mode,
2112 JSReceiver::StoreFromKeyed store_mode,
2113 ExtensibilityCheck extensibility_check,
2114 ValueType value_type,
2115 StoreMode mode,
2116 TransitionFlag transition_flag) {
2117 ASSERT(!object->IsJSGlobalProxy());
2118 Isolate* isolate = object->GetIsolate();
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00002119
2120 if (!name->IsUniqueName()) {
2121 name = isolate->factory()->InternalizedStringFromString(
2122 Handle<String>::cast(name));
2123 }
2124
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00002125 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002126 !object->map()->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002127 if (strict_mode == kNonStrictMode) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002128 return value;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002129 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002130 Handle<Object> args[1] = { name };
2131 Handle<Object> error = isolate->factory()->NewTypeError(
2132 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
2133 isolate->Throw(*error);
2134 return Handle<Object>();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002135 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002136 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002137
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002138 if (object->HasFastProperties()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002139 // Ensure the descriptor array does not get too big.
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002140 if (object->map()->NumberOfOwnDescriptors() <= kMaxNumberOfDescriptors) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002141 // TODO(verwaest): Support other constants.
2142 // if (mode == ALLOW_AS_CONSTANT &&
2143 // !value->IsTheHole() &&
2144 // !value->IsConsString()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002145 if (value->IsJSFunction()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002146 AddConstantProperty(object, name, value, attributes, transition_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002148 AddFastProperty(object, name, value, attributes, store_mode,
2149 value_type, transition_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002150 }
2151 } else {
2152 // Normalize the object to prevent very large instance descriptors.
2153 // This eliminates unwanted N^2 allocation and lookup behavior.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002154 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
2155 AddSlowProperty(object, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002157 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002158 AddSlowProperty(object, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002160
mstarzinger@chromium.org69008382013-10-18 10:34:25 +00002161 if (FLAG_harmony_observation &&
2162 object->map()->is_observed() &&
2163 *name != isolate->heap()->hidden_string()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002164 Handle<Object> old_value = isolate->factory()->the_hole_value();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00002165 EnqueueChangeRecord(object, "add", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002166 }
2167
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002168 return value;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002169}
2170
2171
2172void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
2173 const char* type_str,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002174 Handle<Name> name,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002175 Handle<Object> old_value) {
2176 Isolate* isolate = object->GetIsolate();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002177 HandleScope scope(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002178 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002179 if (object->IsJSGlobalObject()) {
2180 object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
2181 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002182 Handle<Object> args[] = { type, object, name, old_value };
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002183 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002184 bool threw;
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002185
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002186 Execution::Call(isolate,
2187 Handle<JSFunction>(isolate->observers_notify_change()),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002188 isolate->factory()->undefined_value(),
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002189 argc, args,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002190 &threw);
2191 ASSERT(!threw);
2192}
2193
2194
2195void JSObject::DeliverChangeRecords(Isolate* isolate) {
2196 ASSERT(isolate->observer_delivery_pending());
2197 bool threw = false;
2198 Execution::Call(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002199 isolate,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002200 isolate->observers_deliver_changes(),
2201 isolate->factory()->undefined_value(),
2202 0,
2203 NULL,
2204 &threw);
2205 ASSERT(!threw);
2206 isolate->set_observer_delivery_pending(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002207}
2208
2209
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002210Handle<Object> JSObject::SetPropertyPostInterceptor(
2211 Handle<JSObject> object,
2212 Handle<Name> name,
2213 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002214 PropertyAttributes attributes,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002215 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 // Check local property, ignore interceptor.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002217 LookupResult result(object->GetIsolate());
2218 object->LocalLookupRealNamedProperty(*name, &result);
2219 if (!result.IsFound()) {
2220 object->map()->LookupTransition(*object, *name, &result);
2221 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002222 if (result.IsFound()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002223 // An existing property or a map transition was found. Use set property to
2224 // handle all these cases.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002225 return SetPropertyForResult(object, &result, name, value, attributes,
2226 strict_mode, MAY_BE_STORE_FROM_KEYED);
ager@chromium.org5c838252010-02-19 08:53:10 +00002227 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002228 bool done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002229 Handle<Object> result_object = SetPropertyViaPrototypes(
2230 object, name, value, attributes, strict_mode, &done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002231 if (done) return result_object;
ager@chromium.org5c838252010-02-19 08:53:10 +00002232 // Add a new real property.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002233 return AddProperty(object, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002234}
2235
2236
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002237static void ReplaceSlowProperty(Handle<JSObject> object,
2238 Handle<Name> name,
2239 Handle<Object> value,
2240 PropertyAttributes attributes) {
2241 NameDictionary* dictionary = object->property_dictionary();
2242 int old_index = dictionary->FindEntry(*name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002243 int new_enumeration_index = 0; // 0 means "Use the next available index."
2244 if (old_index != -1) {
2245 // All calls to ReplaceSlowProperty have had all transitions removed.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002246 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002247 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002248
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002249 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002250 JSObject::SetNormalizedProperty(object, name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002251}
2252
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002253
danno@chromium.orgf005df62013-04-30 16:36:45 +00002254const char* Representation::Mnemonic() const {
2255 switch (kind_) {
2256 case kNone: return "v";
2257 case kTagged: return "t";
2258 case kSmi: return "s";
2259 case kDouble: return "d";
2260 case kInteger32: return "i";
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002261 case kHeapObject: return "h";
danno@chromium.orgf005df62013-04-30 16:36:45 +00002262 case kExternal: return "x";
2263 default:
2264 UNREACHABLE();
2265 return NULL;
2266 }
2267}
2268
2269
2270enum RightTrimMode { FROM_GC, FROM_MUTATOR };
2271
2272
2273static void ZapEndOfFixedArray(Address new_end, int to_trim) {
2274 // If we are doing a big trim in old space then we zap the space.
2275 Object** zap = reinterpret_cast<Object**>(new_end);
2276 zap++; // Header of filler must be at least one word so skip that.
2277 for (int i = 1; i < to_trim; i++) {
2278 *zap++ = Smi::FromInt(0);
2279 }
2280}
2281
2282
2283template<RightTrimMode trim_mode>
2284static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002285 ASSERT(elms->map() != heap->fixed_cow_array_map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002286 // For now this trick is only applied to fixed arrays in new and paged space.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002287 ASSERT(!heap->lo_space()->Contains(elms));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002288
2289 const int len = elms->length();
2290
2291 ASSERT(to_trim < len);
2292
2293 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
2294
2295 if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002296 ZapEndOfFixedArray(new_end, to_trim);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002297 }
2298
2299 int size_delta = to_trim * kPointerSize;
2300
2301 // Technically in new space this write might be omitted (except for
2302 // debug mode which iterates through the heap), but to play safer
2303 // we still do it.
2304 heap->CreateFillerObjectAt(new_end, size_delta);
2305
2306 elms->set_length(len - to_trim);
2307
2308 // Maintain marking consistency for IncrementalMarking.
2309 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
2310 if (trim_mode == FROM_GC) {
2311 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
2312 } else {
2313 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
2314 }
2315 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002316
2317 // The array may not be moved during GC,
2318 // and size has to be adjusted nevertheless.
2319 HeapProfiler* profiler = heap->isolate()->heap_profiler();
2320 if (profiler->is_tracking_allocations()) {
2321 profiler->UpdateObjectSizeEvent(elms->address(), elms->Size());
2322 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002323}
2324
2325
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002326bool Map::InstancesNeedRewriting(Map* target,
2327 int target_number_of_fields,
danno@chromium.orgf005df62013-04-30 16:36:45 +00002328 int target_inobject,
2329 int target_unused) {
2330 // If fields were added (or removed), rewrite the instance.
2331 int number_of_fields = NumberOfFields();
2332 ASSERT(target_number_of_fields >= number_of_fields);
2333 if (target_number_of_fields != number_of_fields) return true;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002334
2335 if (FLAG_track_double_fields) {
2336 // If smi descriptors were replaced by double descriptors, rewrite.
2337 DescriptorArray* old_desc = instance_descriptors();
2338 DescriptorArray* new_desc = target->instance_descriptors();
2339 int limit = NumberOfOwnDescriptors();
2340 for (int i = 0; i < limit; i++) {
2341 if (new_desc->GetDetails(i).representation().IsDouble() &&
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002342 !old_desc->GetDetails(i).representation().IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002343 return true;
2344 }
2345 }
2346 }
2347
danno@chromium.orgf005df62013-04-30 16:36:45 +00002348 // If no fields were added, and no inobject properties were removed, setting
2349 // the map is sufficient.
2350 if (target_inobject == inobject_properties()) return false;
2351 // In-object slack tracking may have reduced the object size of the new map.
2352 // In that case, succeed if all existing fields were inobject, and they still
2353 // fit within the new inobject size.
2354 ASSERT(target_inobject < inobject_properties());
2355 if (target_number_of_fields <= target_inobject) {
2356 ASSERT(target_number_of_fields + target_unused == target_inobject);
2357 return false;
2358 }
2359 // Otherwise, properties will need to be moved to the backing store.
2360 return true;
2361}
2362
2363
2364// To migrate an instance to a map:
2365// - First check whether the instance needs to be rewritten. If not, simply
2366// change the map.
2367// - Otherwise, allocate a fixed array large enough to hold all fields, in
2368// addition to unused space.
2369// - Copy all existing properties in, in the following order: backing store
2370// properties, unused fields, inobject properties.
2371// - If all allocation succeeded, commit the state atomically:
2372// * Copy inobject properties from the backing store back into the object.
2373// * Trim the difference in instance size of the object. This also cleanly
2374// frees inobject properties that moved to the backing store.
2375// * If there are properties left in the backing store, trim of the space used
2376// to temporarily store the inobject properties.
2377// * If there are properties left in the backing store, install the backing
2378// store.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002379void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
2380 Isolate* isolate = object->GetIsolate();
2381 Handle<Map> old_map(object->map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002382 int number_of_fields = new_map->NumberOfFields();
2383 int inobject = new_map->inobject_properties();
2384 int unused = new_map->unused_property_fields();
2385
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002386 // Nothing to do if no functions were converted to fields and no smis were
2387 // converted to doubles.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002388 if (!old_map->InstancesNeedRewriting(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002389 *new_map, number_of_fields, inobject, unused)) {
2390 object->set_map(*new_map);
2391 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002392 }
2393
2394 int total_size = number_of_fields + unused;
2395 int external = total_size - inobject;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002396 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002397
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002398 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2399 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002400 int descriptors = new_map->NumberOfOwnDescriptors();
2401
2402 for (int i = 0; i < descriptors; i++) {
2403 PropertyDetails details = new_descriptors->GetDetails(i);
2404 if (details.type() != FIELD) continue;
2405 PropertyDetails old_details = old_descriptors->GetDetails(i);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002406 if (old_details.type() == CALLBACKS) {
2407 ASSERT(details.representation().IsTagged());
2408 continue;
2409 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002410 ASSERT(old_details.type() == CONSTANT ||
danno@chromium.orgf005df62013-04-30 16:36:45 +00002411 old_details.type() == FIELD);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002412 Object* raw_value = old_details.type() == CONSTANT
danno@chromium.orgf005df62013-04-30 16:36:45 +00002413 ? old_descriptors->GetValue(i)
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002414 : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i));
2415 Handle<Object> value(raw_value, isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002416 if (FLAG_track_double_fields &&
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002417 !old_details.representation().IsDouble() &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002418 details.representation().IsDouble()) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002419 if (old_details.representation().IsNone()) {
2420 value = handle(Smi::FromInt(0), isolate);
2421 }
2422 value = NewStorageFor(isolate, value, details.representation());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002423 }
2424 ASSERT(!(FLAG_track_double_fields &&
2425 details.representation().IsDouble() &&
2426 value->IsSmi()));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002427 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2428 if (target_index < 0) target_index += total_size;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002429 array->set(target_index, *value);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002430 }
2431
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002432 // From here on we cannot fail and we shouldn't GC anymore.
2433 DisallowHeapAllocation no_allocation;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002434
2435 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2436 // avoid overwriting |one_pointer_filler_map|.
2437 int limit = Min(inobject, number_of_fields);
2438 for (int i = 0; i < limit; i++) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002439 object->FastPropertyAtPut(i, array->get(external + i));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002440 }
2441
2442 // Create filler object past the new instance size.
2443 int new_instance_size = new_map->instance_size();
2444 int instance_size_delta = old_map->instance_size() - new_instance_size;
2445 ASSERT(instance_size_delta >= 0);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002446 Address address = object->address() + new_instance_size;
2447 isolate->heap()->CreateFillerObjectAt(address, instance_size_delta);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002448
2449 // If there are properties in the new backing store, trim it to the correct
2450 // size and install the backing store into the object.
2451 if (external > 0) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002452 RightTrimFixedArray<FROM_MUTATOR>(isolate->heap(), *array, inobject);
2453 object->set_properties(*array);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002454 }
2455
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002456 object->set_map(*new_map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002457}
2458
2459
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00002460Handle<TransitionArray> Map::AddTransition(Handle<Map> map,
2461 Handle<Name> key,
2462 Handle<Map> target,
2463 SimpleTransitionFlag flag) {
2464 CALL_HEAP_FUNCTION(map->GetIsolate(),
2465 map->AddTransition(*key, *target, flag),
2466 TransitionArray);
2467}
2468
2469
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002470void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
2471 int modify_index,
2472 Representation new_representation,
2473 StoreMode store_mode) {
2474 Handle<Map> new_map = Map::GeneralizeRepresentation(
2475 handle(object->map()), modify_index, new_representation, store_mode);
2476 if (object->map() == *new_map) return;
2477 return MigrateToMap(object, new_map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002478}
2479
2480
2481int Map::NumberOfFields() {
2482 DescriptorArray* descriptors = instance_descriptors();
2483 int result = 0;
2484 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2485 if (descriptors->GetDetails(i).type() == FIELD) result++;
2486 }
2487 return result;
2488}
2489
2490
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002491Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2492 int modify_index,
2493 StoreMode store_mode,
2494 PropertyAttributes attributes,
2495 const char* reason) {
2496 Handle<Map> new_map = Copy(map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002497
rossberg@chromium.org92597162013-08-23 13:28:00 +00002498 DescriptorArray* descriptors = new_map->instance_descriptors();
2499 descriptors->InitializeRepresentations(Representation::Tagged());
2500
2501 // Unless the instance is being migrated, ensure that modify_index is a field.
2502 PropertyDetails details = descriptors->GetDetails(modify_index);
2503 if (store_mode == FORCE_FIELD && details.type() != FIELD) {
2504 FieldDescriptor d(descriptors->GetKey(modify_index),
2505 new_map->NumberOfFields(),
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002506 attributes,
rossberg@chromium.org92597162013-08-23 13:28:00 +00002507 Representation::Tagged());
2508 d.SetSortedKeyIndex(details.pointer());
2509 descriptors->Set(modify_index, &d);
2510 int unused_property_fields = new_map->unused_property_fields() - 1;
2511 if (unused_property_fields < 0) {
2512 unused_property_fields += JSObject::kFieldsAdded;
2513 }
2514 new_map->set_unused_property_fields(unused_property_fields);
2515 }
2516
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002517 if (FLAG_trace_generalization) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002518 map->PrintGeneralization(stdout, reason, modify_index,
rossberg@chromium.org92597162013-08-23 13:28:00 +00002519 new_map->NumberOfOwnDescriptors(),
2520 new_map->NumberOfOwnDescriptors(),
2521 details.type() == CONSTANT && store_mode == FORCE_FIELD,
2522 Representation::Tagged(), Representation::Tagged());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002523 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002524 return new_map;
2525}
2526
2527
2528void Map::DeprecateTransitionTree() {
2529 if (!FLAG_track_fields) return;
2530 if (is_deprecated()) return;
2531 if (HasTransitionArray()) {
2532 TransitionArray* transitions = this->transitions();
2533 for (int i = 0; i < transitions->number_of_transitions(); i++) {
2534 transitions->GetTarget(i)->DeprecateTransitionTree();
2535 }
2536 }
2537 deprecate();
2538 dependent_code()->DeoptimizeDependentCodeGroup(
2539 GetIsolate(), DependentCode::kTransitionGroup);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002540 NotifyLeafMapLayoutChange();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002541}
2542
2543
2544// Invalidates a transition target at |key|, and installs |new_descriptors| over
2545// the current instance_descriptors to ensure proper sharing of descriptor
2546// arrays.
2547void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
2548 if (HasTransitionArray()) {
2549 TransitionArray* transitions = this->transitions();
2550 int transition = transitions->Search(key);
2551 if (transition != TransitionArray::kNotFound) {
2552 transitions->GetTarget(transition)->DeprecateTransitionTree();
2553 }
2554 }
2555
2556 // Don't overwrite the empty descriptor array.
2557 if (NumberOfOwnDescriptors() == 0) return;
2558
2559 DescriptorArray* to_replace = instance_descriptors();
2560 Map* current = this;
2561 while (current->instance_descriptors() == to_replace) {
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00002562 current->SetEnumLength(kInvalidEnumCacheSentinel);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002563 current->set_instance_descriptors(new_descriptors);
2564 Object* next = current->GetBackPointer();
2565 if (next->IsUndefined()) break;
2566 current = Map::cast(next);
2567 }
2568
2569 set_owns_descriptors(false);
2570}
2571
2572
2573Map* Map::FindRootMap() {
2574 Map* result = this;
2575 while (true) {
2576 Object* back = result->GetBackPointer();
2577 if (back->IsUndefined()) return result;
2578 result = Map::cast(back);
2579 }
2580}
2581
2582
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002583// Returns NULL if the updated map is incompatible.
danno@chromium.orgf005df62013-04-30 16:36:45 +00002584Map* Map::FindUpdatedMap(int verbatim,
2585 int length,
2586 DescriptorArray* descriptors) {
2587 // This can only be called on roots of transition trees.
2588 ASSERT(GetBackPointer()->IsUndefined());
2589
2590 Map* current = this;
2591
2592 for (int i = verbatim; i < length; i++) {
2593 if (!current->HasTransitionArray()) break;
2594 Name* name = descriptors->GetKey(i);
2595 TransitionArray* transitions = current->transitions();
2596 int transition = transitions->Search(name);
2597 if (transition == TransitionArray::kNotFound) break;
2598 current = transitions->GetTarget(transition);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002599 PropertyDetails details = descriptors->GetDetails(i);
2600 PropertyDetails target_details =
2601 current->instance_descriptors()->GetDetails(i);
2602 if (details.attributes() != target_details.attributes()) return NULL;
2603 if (details.type() == CALLBACKS) {
2604 if (target_details.type() != CALLBACKS) return NULL;
2605 if (descriptors->GetValue(i) !=
2606 current->instance_descriptors()->GetValue(i)) {
2607 return NULL;
2608 }
2609 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002610 }
2611
2612 return current;
2613}
2614
2615
2616Map* Map::FindLastMatchMap(int verbatim,
2617 int length,
2618 DescriptorArray* descriptors) {
2619 // This can only be called on roots of transition trees.
2620 ASSERT(GetBackPointer()->IsUndefined());
2621
2622 Map* current = this;
2623
2624 for (int i = verbatim; i < length; i++) {
2625 if (!current->HasTransitionArray()) break;
2626 Name* name = descriptors->GetKey(i);
2627 TransitionArray* transitions = current->transitions();
2628 int transition = transitions->Search(name);
2629 if (transition == TransitionArray::kNotFound) break;
2630
2631 Map* next = transitions->GetTarget(transition);
2632 DescriptorArray* next_descriptors = next->instance_descriptors();
2633
2634 if (next_descriptors->GetValue(i) != descriptors->GetValue(i)) break;
2635
2636 PropertyDetails details = descriptors->GetDetails(i);
2637 PropertyDetails next_details = next_descriptors->GetDetails(i);
2638 if (details.type() != next_details.type()) break;
2639 if (details.attributes() != next_details.attributes()) break;
2640 if (!details.representation().Equals(next_details.representation())) break;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002641
2642 current = next;
2643 }
2644 return current;
2645}
2646
2647
2648// Generalize the representation of the descriptor at |modify_index|.
2649// This method rewrites the transition tree to reflect the new change. To avoid
2650// high degrees over polymorphism, and to stabilize quickly, on every rewrite
2651// the new type is deduced by merging the current type with any potential new
2652// (partial) version of the type in the transition tree.
2653// To do this, on each rewrite:
2654// - Search the root of the transition tree using FindRootMap.
2655// - Find |updated|, the newest matching version of this map using
2656// FindUpdatedMap. This uses the keys in the own map's descriptor array to
2657// walk the transition tree.
2658// - Merge/generalize the descriptor array of the current map and |updated|.
2659// - Generalize the |modify_index| descriptor using |new_representation|.
2660// - Walk the tree again starting from the root towards |updated|. Stop at
2661// |split_map|, the first map who's descriptor array does not match the merged
2662// descriptor array.
2663// - If |updated| == |split_map|, |updated| is in the expected state. Return it.
2664// - Otherwise, invalidate the outdated transition target from |updated|, and
2665// replace its transition tree with a new branch for the updated descriptors.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002666Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
2667 int modify_index,
2668 Representation new_representation,
2669 StoreMode store_mode) {
2670 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002671 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2672 Representation old_representation = old_details.representation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002673
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002674 // It's fine to transition from None to anything but double without any
2675 // modification to the object, because the default uninitialized value for
2676 // representation None can be overwritten by both smi and tagged values.
2677 // Doubles, however, would require a box allocation.
2678 if (old_representation.IsNone() &&
2679 !new_representation.IsNone() &&
2680 !new_representation.IsDouble()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00002681 old_descriptors->SetRepresentation(modify_index, new_representation);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002682 return old_map;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002683 }
2684
2685 int descriptors = old_map->NumberOfOwnDescriptors();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002686 Handle<Map> root_map(old_map->FindRootMap());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002687
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002688 // Check the state of the root map.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002689 if (!old_map->EquivalentToForTransition(*root_map)) {
2690 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2691 old_details.attributes(), "not equivalent");
danno@chromium.orgf005df62013-04-30 16:36:45 +00002692 }
2693
2694 int verbatim = root_map->NumberOfOwnDescriptors();
2695
rossberg@chromium.org92597162013-08-23 13:28:00 +00002696 if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002697 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002698 old_details.attributes(), "root modification");
rossberg@chromium.org92597162013-08-23 13:28:00 +00002699 }
2700
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002701 Map* raw_updated = root_map->FindUpdatedMap(
2702 verbatim, descriptors, *old_descriptors);
2703 if (raw_updated == NULL) {
2704 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2705 old_details.attributes(), "incompatible");
rossberg@chromium.org92597162013-08-23 13:28:00 +00002706 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002707
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002708 Handle<Map> updated(raw_updated);
2709 Handle<DescriptorArray> updated_descriptors(updated->instance_descriptors());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002710
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002711 int valid = updated->NumberOfOwnDescriptors();
rossberg@chromium.org92597162013-08-23 13:28:00 +00002712
2713 // Directly change the map if the target map is more general. Ensure that the
2714 // target type of the modify_index is a FIELD, unless we are migrating.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002715 if (updated_descriptors->IsMoreGeneralThan(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002716 verbatim, valid, descriptors, *old_descriptors) &&
rossberg@chromium.org92597162013-08-23 13:28:00 +00002717 (store_mode == ALLOW_AS_CONSTANT ||
2718 updated_descriptors->GetDetails(modify_index).type() == FIELD)) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002719 Representation updated_representation =
2720 updated_descriptors->GetDetails(modify_index).representation();
rossberg@chromium.org92597162013-08-23 13:28:00 +00002721 if (new_representation.fits_into(updated_representation)) return updated;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002722 }
2723
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002724 Handle<DescriptorArray> new_descriptors = DescriptorArray::Merge(
2725 updated_descriptors, verbatim, valid, descriptors, modify_index,
2726 store_mode, old_descriptors);
rossberg@chromium.org92597162013-08-23 13:28:00 +00002727 ASSERT(store_mode == ALLOW_AS_CONSTANT ||
2728 new_descriptors->GetDetails(modify_index).type() == FIELD);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002729
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002730 old_representation =
danno@chromium.orgf005df62013-04-30 16:36:45 +00002731 new_descriptors->GetDetails(modify_index).representation();
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002732 Representation updated_representation =
2733 new_representation.generalize(old_representation);
2734 if (!updated_representation.Equals(old_representation)) {
2735 new_descriptors->SetRepresentation(modify_index, updated_representation);
2736 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002737
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002738 Handle<Map> split_map(root_map->FindLastMatchMap(
2739 verbatim, descriptors, *new_descriptors));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002740
2741 int split_descriptors = split_map->NumberOfOwnDescriptors();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002742 // This is shadowed by |updated_descriptors| being more general than
2743 // |old_descriptors|.
2744 ASSERT(descriptors != split_descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002745
2746 int descriptor = split_descriptors;
2747 split_map->DeprecateTarget(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002748 old_descriptors->GetKey(descriptor), *new_descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002749
rossberg@chromium.org92597162013-08-23 13:28:00 +00002750 if (FLAG_trace_generalization) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002751 old_map->PrintGeneralization(
rossberg@chromium.org92597162013-08-23 13:28:00 +00002752 stdout, "", modify_index, descriptor, descriptors,
2753 old_descriptors->GetDetails(modify_index).type() == CONSTANT &&
2754 store_mode == FORCE_FIELD,
2755 old_representation, updated_representation);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002756 }
2757
danno@chromium.orgf005df62013-04-30 16:36:45 +00002758 // Add missing transitions.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002759 Handle<Map> new_map = split_map;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002760 for (; descriptor < descriptors; descriptor++) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002761 new_map = Map::CopyInstallDescriptors(new_map, descriptor, new_descriptors);
danno@chromium.org59400602013-08-13 17:09:37 +00002762 new_map->set_migration_target(true);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002763 }
2764
2765 new_map->set_owns_descriptors(true);
2766 return new_map;
2767}
2768
ager@chromium.org7c537e22008-10-16 08:43:32 +00002769
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00002770// Generalize the representation of all FIELD descriptors.
2771Handle<Map> Map::GeneralizeAllFieldRepresentations(
2772 Handle<Map> map,
2773 Representation new_representation) {
2774 Handle<DescriptorArray> descriptors(map->instance_descriptors());
2775 for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
2776 PropertyDetails details = descriptors->GetDetails(i);
2777 if (details.type() == FIELD) {
2778 map = GeneralizeRepresentation(map, i, new_representation, FORCE_FIELD);
2779 }
2780 }
2781 return map;
2782}
2783
2784
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002785Map* Map::CurrentMapForDeprecated() {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002786 DisallowHeapAllocation no_allocation;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002787 if (!is_deprecated()) return this;
2788
2789 DescriptorArray* old_descriptors = instance_descriptors();
2790
2791 int descriptors = NumberOfOwnDescriptors();
2792 Map* root_map = FindRootMap();
2793
2794 // Check the state of the root map.
2795 if (!EquivalentToForTransition(root_map)) return NULL;
2796 int verbatim = root_map->NumberOfOwnDescriptors();
2797
2798 Map* updated = root_map->FindUpdatedMap(
2799 verbatim, descriptors, old_descriptors);
2800 if (updated == NULL) return NULL;
2801
2802 DescriptorArray* updated_descriptors = updated->instance_descriptors();
2803 int valid = updated->NumberOfOwnDescriptors();
2804 if (!updated_descriptors->IsMoreGeneralThan(
2805 verbatim, valid, descriptors, old_descriptors)) {
2806 return NULL;
2807 }
2808
2809 return updated;
2810}
2811
2812
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002813Handle<Object> JSObject::SetPropertyWithInterceptor(
2814 Handle<JSObject> object,
2815 Handle<Name> name,
2816 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002817 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002818 StrictModeFlag strict_mode) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002819 // TODO(rossberg): Support symbols in the API.
2820 if (name->IsSymbol()) return value;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002821 Isolate* isolate = object->GetIsolate();
2822 Handle<String> name_string = Handle<String>::cast(name);
2823 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002824 if (!interceptor->setter()->IsUndefined()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002825 LOG(isolate,
2826 ApiNamedPropertyAccess("interceptor-named-set", *object, *name));
2827 PropertyCallbackArguments args(
2828 isolate, interceptor->data(), *object, *object);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002829 v8::NamedPropertySetterCallback setter =
2830 v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002831 Handle<Object> value_unhole = value->IsTheHole()
2832 ? Handle<Object>(isolate->factory()->undefined_value()) : value;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002833 v8::Handle<v8::Value> result = args.Call(setter,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002834 v8::Utils::ToLocal(name_string),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002835 v8::Utils::ToLocal(value_unhole));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002836 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2837 if (!result.IsEmpty()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002839 Handle<Object> result =
2840 SetPropertyPostInterceptor(object, name, value, attributes, strict_mode);
2841 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2842 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002843}
2844
2845
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002846Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002847 Handle<Name> name,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002848 Handle<Object> value,
2849 PropertyAttributes attributes,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002850 StrictModeFlag strict_mode,
2851 StoreFromKeyed store_mode) {
2852 LookupResult result(object->GetIsolate());
2853 object->LocalLookup(*name, &result, true);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002854 if (!result.IsFound()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002855 object->map()->LookupTransition(JSObject::cast(*object), *name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002856 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002857 return SetProperty(object, &result, name, value, attributes, strict_mode,
2858 store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002859}
2860
2861
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002862Handle<Object> JSObject::SetPropertyWithCallback(Handle<JSObject> object,
2863 Handle<Object> structure,
2864 Handle<Name> name,
2865 Handle<Object> value,
2866 Handle<JSObject> holder,
2867 StrictModeFlag strict_mode) {
2868 Isolate* isolate = object->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869
2870 // We should never get here to initialize a const with the hole
2871 // value since a const declaration would conflict with the setter.
2872 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002873
2874 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002875 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002876 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002877 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002878 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002879 reinterpret_cast<AccessorDescriptor*>(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002880 Handle<Foreign>::cast(structure)->foreign_address());
2881 CALL_AND_RETRY_OR_DIE(isolate,
2882 (callback->setter)(
2883 isolate, *object, *value, callback->data),
2884 break,
2885 return Handle<Object>());
2886 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2887 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002888 }
2889
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002890 if (structure->IsExecutableAccessorInfo()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891 // api style callbacks
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002892 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
2893 if (!data->IsCompatibleReceiver(*object)) {
2894 Handle<Object> args[2] = { name, object };
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002895 Handle<Object> error =
2896 isolate->factory()->NewTypeError("incompatible_method_receiver",
2897 HandleVector(args,
2898 ARRAY_SIZE(args)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002899 isolate->Throw(*error);
2900 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002901 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00002902 // TODO(rossberg): Support symbols in the API.
2903 if (name->IsSymbol()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904 Object* call_obj = data->setter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002905 v8::AccessorSetterCallback call_fun =
2906 v8::ToCData<v8::AccessorSetterCallback>(call_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002907 if (call_fun == NULL) return value;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002908 Handle<String> key = Handle<String>::cast(name);
2909 LOG(isolate, ApiNamedPropertyAccess("store", *object, *name));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002910 PropertyCallbackArguments args(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002911 isolate, data->data(), *object, JSObject::cast(*holder));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002912 args.Call(call_fun,
2913 v8::Utils::ToLocal(key),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002914 v8::Utils::ToLocal(value));
2915 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2916 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002917 }
2918
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002919 if (structure->IsAccessorPair()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002920 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002921 if (setter->IsSpecFunction()) {
2922 // TODO(rossberg): nicer would be to cast to some JSCallable here...
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002923 return SetPropertyWithDefinedSetter(
2924 object, Handle<JSReceiver>::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002925 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002926 if (strict_mode == kNonStrictMode) {
2927 return value;
2928 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002929 Handle<Object> args[2] = { name, holder };
2930 Handle<Object> error =
2931 isolate->factory()->NewTypeError("no_setter_in_callback",
2932 HandleVector(args, 2));
2933 isolate->Throw(*error);
2934 return Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002936 }
2937
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002938 // TODO(dcarney): Handle correctly.
2939 if (structure->IsDeclaredAccessorInfo()) {
2940 return value;
2941 }
2942
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002943 UNREACHABLE();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002944 return Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002945}
2946
2947
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002948Handle<Object> JSReceiver::SetPropertyWithDefinedSetter(
2949 Handle<JSReceiver> object,
2950 Handle<JSReceiver> setter,
2951 Handle<Object> value) {
2952 Isolate* isolate = object->GetIsolate();
2953
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002954#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002955 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002956 // Handle stepping into a setter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002957 // TODO(rossberg): should this apply to getters that are function proxies?
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002958 if (debug->StepInActive() && setter->IsJSFunction()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002959 debug->HandleStepIn(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002960 Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002961 }
2962#endif
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002963
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002964 bool has_pending_exception;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002965 Handle<Object> argv[] = { value };
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002966 Execution::Call(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002967 isolate, setter, object, ARRAY_SIZE(argv), argv, &has_pending_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002968 // Check for pending exception and return the result.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002969 if (has_pending_exception) return Handle<Object>();
2970 return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002971}
2972
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002973
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002974Handle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
2975 Handle<JSObject> object,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002976 uint32_t index,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002977 Handle<Object> value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002978 bool* found,
2979 StrictModeFlag strict_mode) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002980 Isolate *isolate = object->GetIsolate();
2981 for (Handle<Object> proto = handle(object->GetPrototype(), isolate);
2982 !proto->IsNull();
2983 proto = handle(proto->GetPrototype(isolate), isolate)) {
2984 if (proto->IsJSProxy()) {
2985 return JSProxy::SetPropertyViaPrototypesWithHandler(
2986 Handle<JSProxy>::cast(proto),
2987 object,
2988 isolate->factory()->Uint32ToString(index), // name
2989 value,
2990 NONE,
2991 strict_mode,
2992 found);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002993 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002994 Handle<JSObject> js_proto = Handle<JSObject>::cast(proto);
2995 if (!js_proto->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002996 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002997 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00002998 Handle<SeededNumberDictionary> dictionary(js_proto->element_dictionary());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002999 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003000 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003001 PropertyDetails details = dictionary->DetailsAt(entry);
3002 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003003 *found = true;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003004 Handle<Object> structure(dictionary->ValueAt(entry), isolate);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003005 return SetElementWithCallback(object, structure, index, value, js_proto,
3006 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003007 }
3008 }
3009 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003010 *found = false;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00003011 return isolate->factory()->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003012}
3013
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003014
3015Handle<Object> JSObject::SetPropertyViaPrototypes(Handle<JSObject> object,
3016 Handle<Name> name,
3017 Handle<Object> value,
3018 PropertyAttributes attributes,
3019 StrictModeFlag strict_mode,
3020 bool* done) {
3021 Isolate* isolate = object->GetIsolate();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003022
3023 *done = false;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003024 // We could not find a local property so let's check whether there is an
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003025 // accessor that wants to handle the property, or whether the property is
3026 // read-only on the prototype chain.
3027 LookupResult result(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003028 object->LookupRealNamedPropertyInPrototypes(*name, &result);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003029 if (result.IsFound()) {
3030 switch (result.type()) {
3031 case NORMAL:
3032 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00003033 case CONSTANT:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003034 *done = result.IsReadOnly();
3035 break;
3036 case INTERCEPTOR: {
3037 PropertyAttributes attr =
3038 result.holder()->GetPropertyAttributeWithInterceptor(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003039 *object, *name, true);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003040 *done = !!(attr & READ_ONLY);
3041 break;
3042 }
3043 case CALLBACKS: {
3044 if (!FLAG_es5_readonly && result.IsReadOnly()) break;
3045 *done = true;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003046 Handle<Object> callback_object(result.GetCallbackObject(), isolate);
3047 return SetPropertyWithCallback(object, callback_object, name, value,
3048 handle(result.holder()), strict_mode);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003049 }
3050 case HANDLER: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003051 Handle<JSProxy> proxy(result.proxy());
3052 return JSProxy::SetPropertyViaPrototypesWithHandler(
3053 proxy, object, name, value, attributes, strict_mode, done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003054 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003055 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003056 case NONEXISTENT:
3057 UNREACHABLE();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003058 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003059 }
3060 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003061
3062 // If we get here with *done true, we have encountered a read-only property.
3063 if (!FLAG_es5_readonly) *done = false;
3064 if (*done) {
3065 if (strict_mode == kNonStrictMode) return value;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003066 Handle<Object> args[] = { name, object };
3067 Handle<Object> error = isolate->factory()->NewTypeError(
3068 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
3069 isolate->Throw(*error);
3070 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003071 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003072 return isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003073}
3074
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003075
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003076void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
3077 Handle<DescriptorArray> descriptors(map->instance_descriptors());
3078 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
3079 int number_of_descriptors = descriptors->number_of_descriptors();
3080 Isolate* isolate = map->GetIsolate();
3081 Handle<DescriptorArray> new_descriptors =
3082 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack);
3083 DescriptorArray::WhitenessWitness witness(*new_descriptors);
3084
3085 for (int i = 0; i < number_of_descriptors; ++i) {
3086 new_descriptors->CopyFrom(i, *descriptors, i, witness);
3087 }
3088
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003089 map->set_instance_descriptors(*new_descriptors);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003090}
3091
3092
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003093template<class T>
3094static int AppendUniqueCallbacks(NeanderArray* callbacks,
3095 Handle<typename T::Array> array,
3096 int valid_descriptors) {
3097 int nof_callbacks = callbacks->length();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003098
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003099 Isolate* isolate = array->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00003100 // Ensure the keys are unique names before writing them into the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003101 // instance descriptor. Since it may cause a GC, it has to be done before we
danno@chromium.org129d3982012-07-25 15:01:47 +00003102 // temporarily put the heap in an invalid state while appending descriptors.
3103 for (int i = 0; i < nof_callbacks; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003104 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3105 if (entry->name()->IsUniqueName()) continue;
3106 Handle<String> key =
3107 isolate->factory()->InternalizedStringFromString(
3108 Handle<String>(String::cast(entry->name())));
3109 entry->set_name(*key);
danno@chromium.org129d3982012-07-25 15:01:47 +00003110 }
3111
danno@chromium.org129d3982012-07-25 15:01:47 +00003112 // Fill in new callback descriptors. Process the callbacks from
3113 // back to front so that the last callback with a given name takes
3114 // precedence over previously added callbacks with that name.
3115 for (int i = nof_callbacks - 1; i >= 0; i--) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003116 AccessorInfo* entry = AccessorInfo::cast(callbacks->get(i));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003117 Name* key = Name::cast(entry->name());
danno@chromium.org129d3982012-07-25 15:01:47 +00003118 // Check if a descriptor with this name already exists before writing.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003119 if (!T::Contains(key, entry, valid_descriptors, array)) {
3120 T::Insert(key, entry, valid_descriptors, array);
3121 valid_descriptors++;
danno@chromium.org129d3982012-07-25 15:01:47 +00003122 }
3123 }
3124
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003125 return valid_descriptors;
3126}
3127
3128struct DescriptorArrayAppender {
3129 typedef DescriptorArray Array;
3130 static bool Contains(Name* key,
3131 AccessorInfo* entry,
3132 int valid_descriptors,
3133 Handle<DescriptorArray> array) {
3134 return array->Search(key, valid_descriptors) != DescriptorArray::kNotFound;
3135 }
3136 static void Insert(Name* key,
3137 AccessorInfo* entry,
3138 int valid_descriptors,
3139 Handle<DescriptorArray> array) {
3140 CallbacksDescriptor desc(key, entry, entry->property_attributes());
3141 array->Append(&desc);
3142 }
3143};
3144
3145
3146struct FixedArrayAppender {
3147 typedef FixedArray Array;
3148 static bool Contains(Name* key,
3149 AccessorInfo* entry,
3150 int valid_descriptors,
3151 Handle<FixedArray> array) {
3152 for (int i = 0; i < valid_descriptors; i++) {
3153 if (key == AccessorInfo::cast(array->get(i))->name()) return true;
3154 }
3155 return false;
3156 }
3157 static void Insert(Name* key,
3158 AccessorInfo* entry,
3159 int valid_descriptors,
3160 Handle<FixedArray> array) {
3161 array->set(valid_descriptors, entry);
3162 }
3163};
3164
3165
3166void Map::AppendCallbackDescriptors(Handle<Map> map,
3167 Handle<Object> descriptors) {
3168 int nof = map->NumberOfOwnDescriptors();
3169 Handle<DescriptorArray> array(map->instance_descriptors());
3170 NeanderArray callbacks(descriptors);
3171 ASSERT(array->NumberOfSlackDescriptors() >= callbacks.length());
3172 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003173 map->SetNumberOfOwnDescriptors(nof);
danno@chromium.org129d3982012-07-25 15:01:47 +00003174}
3175
3176
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003177int AccessorInfo::AppendUnique(Handle<Object> descriptors,
3178 Handle<FixedArray> array,
3179 int valid_descriptors) {
3180 NeanderArray callbacks(descriptors);
3181 ASSERT(array->length() >= callbacks.length() + valid_descriptors);
3182 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
3183 array,
3184 valid_descriptors);
3185}
3186
3187
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003188static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
3189 ASSERT(!map.is_null());
3190 for (int i = 0; i < maps->length(); ++i) {
3191 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
3192 }
3193 return false;
3194}
3195
3196
3197template <class T>
3198static Handle<T> MaybeNull(T* p) {
3199 if (p == NULL) return Handle<T>::null();
3200 return Handle<T>(p);
3201}
3202
3203
3204Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003205 ElementsKind kind = elements_kind();
3206 Handle<Map> transitioned_map = Handle<Map>::null();
3207 Handle<Map> current_map(this);
3208 bool packed = IsFastPackedElementsKind(kind);
3209 if (IsTransitionableFastElementsKind(kind)) {
3210 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
3211 kind = GetNextMoreGeneralFastElementsKind(kind, false);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003212 Handle<Map> maybe_transitioned_map =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003213 MaybeNull(current_map->LookupElementsTransitionMap(kind));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003214 if (maybe_transitioned_map.is_null()) break;
3215 if (ContainsMap(candidates, maybe_transitioned_map) &&
3216 (packed || !IsFastPackedElementsKind(kind))) {
3217 transitioned_map = maybe_transitioned_map;
3218 if (!IsFastPackedElementsKind(kind)) packed = false;
3219 }
3220 current_map = maybe_transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003221 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003222 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003223 return transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003224}
3225
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003226
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003227static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
3228 Map* current_map = map;
3229 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
verwaest@chromium.org50915592012-06-18 12:15:44 +00003230 int to_index = IsFastElementsKind(to_kind)
3231 ? GetSequenceIndexFromFastElementsKind(to_kind)
3232 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
3233
3234 ASSERT(index <= to_index);
3235
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003236 for (; index < to_index; ++index) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003237 if (!current_map->HasElementsTransition()) return current_map;
3238 current_map = current_map->elements_transition_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003239 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003240 if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003241 Map* next_map = current_map->elements_transition_map();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003242 if (next_map->elements_kind() == to_kind) return next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00003243 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003244 ASSERT(IsFastElementsKind(to_kind)
3245 ? current_map->elements_kind() == to_kind
3246 : current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003247 return current_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003248}
3249
3250
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003251Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003252 Map* to_map = FindClosestElementsTransition(this, to_kind);
3253 if (to_map->elements_kind() == to_kind) return to_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003254 return NULL;
3255}
3256
3257
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003258bool Map::IsMapInArrayPrototypeChain() {
3259 Isolate* isolate = GetIsolate();
3260 if (isolate->initial_array_prototype()->map() == this) {
3261 return true;
3262 }
3263
3264 if (isolate->initial_object_prototype()->map() == this) {
3265 return true;
3266 }
3267
3268 return false;
3269}
3270
3271
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003272static MaybeObject* AddMissingElementsTransitions(Map* map,
3273 ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003274 ASSERT(IsFastElementsKind(map->elements_kind()));
3275 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
3276 int to_index = IsFastElementsKind(to_kind)
3277 ? GetSequenceIndexFromFastElementsKind(to_kind)
3278 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
3279
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003280 ASSERT(index <= to_index);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003281
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003282 Map* current_map = map;
3283
verwaest@chromium.org50915592012-06-18 12:15:44 +00003284 for (; index < to_index; ++index) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003285 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
3286 MaybeObject* maybe_next_map =
3287 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
3288 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003289 }
3290
verwaest@chromium.org50915592012-06-18 12:15:44 +00003291 // In case we are exiting the fast elements kind system, just add the map in
3292 // the end.
3293 if (!IsFastElementsKind(to_kind)) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003294 MaybeObject* maybe_next_map =
3295 current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
3296 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00003297 }
3298
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003299 ASSERT(current_map->elements_kind() == to_kind);
3300 return current_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003301}
3302
3303
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003304Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3305 ElementsKind to_kind) {
3306 Isolate* isolate = object->GetIsolate();
3307 CALL_HEAP_FUNCTION(isolate,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003308 object->GetElementsTransitionMap(isolate, to_kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003309 Map);
3310}
3311
3312
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003313MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003314 Map* start_map = map();
3315 ElementsKind from_kind = start_map->elements_kind();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003316
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003317 if (from_kind == to_kind) {
3318 return start_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003319 }
3320
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003321 bool allow_store_transition =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003322 // Only remember the map transition if there is not an already existing
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003323 // non-matching element transition.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003324 !start_map->IsUndefined() && !start_map->is_shared() &&
verwaest@chromium.org50915592012-06-18 12:15:44 +00003325 IsFastElementsKind(from_kind);
3326
3327 // Only store fast element maps in ascending generality.
3328 if (IsFastElementsKind(to_kind)) {
3329 allow_store_transition &=
3330 IsTransitionableFastElementsKind(from_kind) &&
3331 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
3332 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003333
3334 if (!allow_store_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003335 return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003336 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003337
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003338 return start_map->AsElementsKind(to_kind);
3339}
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003340
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003341
3342MaybeObject* Map::AsElementsKind(ElementsKind kind) {
3343 Map* closest_map = FindClosestElementsTransition(this, kind);
3344
3345 if (closest_map->elements_kind() == kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003346 return closest_map;
3347 }
3348
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003349 return AddMissingElementsTransitions(closest_map, kind);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003350}
3351
3352
ulan@chromium.org750145a2013-03-07 15:14:13 +00003353void JSObject::LocalLookupRealNamedProperty(Name* name, LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003354 if (IsJSGlobalProxy()) {
3355 Object* proto = GetPrototype();
3356 if (proto->IsNull()) return result->NotFound();
3357 ASSERT(proto->IsJSGlobalObject());
3358 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
3359 }
3360
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361 if (HasFastProperties()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003362 map()->LookupDescriptor(this, name, result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003363 // A property or a map transition was found. We return all of these result
3364 // types because LocalLookupRealNamedProperty is used when setting
3365 // properties where map transitions are handled.
3366 ASSERT(!result->IsFound() ||
3367 (result->holder() == this && result->IsFastPropertyType()));
3368 // Disallow caching for uninitialized constants. These can only
3369 // occur as fields.
3370 if (result->IsField() &&
3371 result->IsReadOnly() &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003372 RawFastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003373 result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003374 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003375 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003376 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003377
3378 int entry = property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003379 if (entry != NameDictionary::kNotFound) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003380 Object* value = property_dictionary()->ValueAt(entry);
3381 if (IsGlobalObject()) {
3382 PropertyDetails d = property_dictionary()->DetailsAt(entry);
3383 if (d.IsDeleted()) {
3384 result->NotFound();
3385 return;
3386 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003387 value = PropertyCell::cast(value)->value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003388 }
3389 // Make sure to disallow caching for uninitialized constants
3390 // found in the dictionary-mode objects.
3391 if (value->IsTheHole()) result->DisallowCaching();
3392 result->DictionaryResult(this, entry);
3393 return;
3394 }
3395
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003396 result->NotFound();
3397}
3398
3399
ulan@chromium.org750145a2013-03-07 15:14:13 +00003400void JSObject::LookupRealNamedProperty(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003402 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003403
3404 LookupRealNamedPropertyInPrototypes(name, result);
3405}
3406
3407
ulan@chromium.org750145a2013-03-07 15:14:13 +00003408void JSObject::LookupRealNamedPropertyInPrototypes(Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409 LookupResult* result) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003410 Isolate* isolate = GetIsolate();
3411 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003412 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003413 pt != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003414 pt = pt->GetPrototype(isolate)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003415 if (pt->IsJSProxy()) {
3416 return result->HandlerResult(JSProxy::cast(pt));
3417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003418 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003419 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR));
3420 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 }
3422 result->NotFound();
3423}
3424
3425
3426// We only need to deal with CALLBACKS and INTERCEPTORS
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003427Handle<Object> JSObject::SetPropertyWithFailedAccessCheck(
3428 Handle<JSObject> object,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003429 LookupResult* result,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003430 Handle<Name> name,
3431 Handle<Object> value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003432 bool check_prototype,
3433 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003434 if (check_prototype && !result->IsProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003435 object->LookupRealNamedPropertyInPrototypes(*name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 }
3437
3438 if (result->IsProperty()) {
3439 if (!result->IsReadOnly()) {
3440 switch (result->type()) {
3441 case CALLBACKS: {
3442 Object* obj = result->GetCallbackObject();
3443 if (obj->IsAccessorInfo()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003444 Handle<AccessorInfo> info(AccessorInfo::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445 if (info->all_can_write()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003446 return SetPropertyWithCallback(object,
3447 info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 name,
3449 value,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003450 handle(result->holder()),
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003451 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003452 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003453 } else if (obj->IsAccessorPair()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003454 Handle<AccessorPair> pair(AccessorPair::cast(obj));
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003455 if (pair->all_can_read()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003456 return SetPropertyWithCallback(object,
3457 pair,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003458 name,
3459 value,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003460 handle(result->holder()),
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003461 strict_mode);
3462 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003463 }
3464 break;
3465 }
3466 case INTERCEPTOR: {
3467 // Try lookup real named properties. Note that only property can be
3468 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003469 LookupResult r(object->GetIsolate());
3470 object->LookupRealNamedProperty(*name, &r);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 if (r.IsProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003472 return SetPropertyWithFailedAccessCheck(object,
3473 &r,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003474 name,
3475 value,
3476 check_prototype,
3477 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003478 }
3479 break;
3480 }
3481 default: {
3482 break;
3483 }
3484 }
3485 }
3486 }
3487
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003488 Isolate* isolate = object->GetIsolate();
3489 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
3490 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
3491 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003492}
3493
3494
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003495Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
3496 LookupResult* result,
3497 Handle<Name> key,
3498 Handle<Object> value,
3499 PropertyAttributes attributes,
3500 StrictModeFlag strict_mode,
3501 StoreFromKeyed store_mode) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003502 if (result->IsHandler()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003503 return JSProxy::SetPropertyWithHandler(handle(result->proxy()),
3504 object, key, value, attributes, strict_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003505 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003506 return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003507 result, key, value, attributes, strict_mode, store_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003508 }
3509}
3510
3511
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003512bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) {
3513 Isolate* isolate = proxy->GetIsolate();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003514
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003515 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3516 if (name->IsSymbol()) return false;
3517
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003518 Handle<Object> args[] = { name };
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003519 Handle<Object> result = proxy->CallTrap(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003520 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003521 if (isolate->has_pending_exception()) return false;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003522
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003523 return result->BooleanValue();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003524}
3525
3526
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003527Handle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
3528 Handle<JSReceiver> receiver,
3529 Handle<Name> name,
3530 Handle<Object> value,
3531 PropertyAttributes attributes,
3532 StrictModeFlag strict_mode) {
3533 Isolate* isolate = proxy->GetIsolate();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003534
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003535 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003536 if (name->IsSymbol()) return value;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003537
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003538 Handle<Object> args[] = { receiver, name, value };
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003539 proxy->CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
3540 if (isolate->has_pending_exception()) return Handle<Object>();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003541
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003542 return value;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003543}
3544
3545
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003546Handle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
3547 Handle<JSProxy> proxy,
3548 Handle<JSReceiver> receiver,
3549 Handle<Name> name,
3550 Handle<Object> value,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003551 PropertyAttributes attributes,
3552 StrictModeFlag strict_mode,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003553 bool* done) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003554 Isolate* isolate = proxy->GetIsolate();
3555 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003556
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003557 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3558 if (name->IsSymbol()) {
3559 *done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003560 return isolate->factory()->the_hole_value();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003561 }
3562
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003563 *done = true; // except where redefined...
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003564 Handle<Object> args[] = { name };
3565 Handle<Object> result = proxy->CallTrap(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003566 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003567 if (isolate->has_pending_exception()) return Handle<Object>();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003568
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003569 if (result->IsUndefined()) {
3570 *done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003571 return isolate->factory()->the_hole_value();
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003572 }
3573
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003574 // Emulate [[GetProperty]] semantics for proxies.
3575 bool has_pending_exception;
3576 Handle<Object> argv[] = { result };
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003577 Handle<Object> desc = Execution::Call(
3578 isolate, isolate->to_complete_property_descriptor(), result,
3579 ARRAY_SIZE(argv), argv, &has_pending_exception);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003580 if (has_pending_exception) return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003581
3582 // [[GetProperty]] requires to check that all properties are configurable.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003583 Handle<String> configurable_name =
3584 isolate->factory()->InternalizeOneByteString(
3585 STATIC_ASCII_VECTOR("configurable_"));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003586 Handle<Object> configurable(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003587 v8::internal::GetProperty(isolate, desc, configurable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003588 ASSERT(!isolate->has_pending_exception());
3589 ASSERT(configurable->IsTrue() || configurable->IsFalse());
3590 if (configurable->IsFalse()) {
3591 Handle<String> trap =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003592 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003593 STATIC_ASCII_VECTOR("getPropertyDescriptor"));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003594 Handle<Object> args[] = { handler, trap, name };
3595 Handle<Object> error = isolate->factory()->NewTypeError(
3596 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003597 isolate->Throw(*error);
3598 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003599 }
3600 ASSERT(configurable->IsTrue());
3601
3602 // Check for DataDescriptor.
3603 Handle<String> hasWritable_name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003604 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003605 STATIC_ASCII_VECTOR("hasWritable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003606 Handle<Object> hasWritable(
3607 v8::internal::GetProperty(isolate, desc, hasWritable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003608 ASSERT(!isolate->has_pending_exception());
3609 ASSERT(hasWritable->IsTrue() || hasWritable->IsFalse());
3610 if (hasWritable->IsTrue()) {
3611 Handle<String> writable_name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003612 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003613 STATIC_ASCII_VECTOR("writable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003614 Handle<Object> writable(
3615 v8::internal::GetProperty(isolate, desc, writable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003616 ASSERT(!isolate->has_pending_exception());
3617 ASSERT(writable->IsTrue() || writable->IsFalse());
3618 *done = writable->IsFalse();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003619 if (!*done) return isolate->factory()->the_hole_value();
3620 if (strict_mode == kNonStrictMode) return value;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003621 Handle<Object> args[] = { name, receiver };
3622 Handle<Object> error = isolate->factory()->NewTypeError(
3623 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003624 isolate->Throw(*error);
3625 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003626 }
3627
3628 // We have an AccessorDescriptor.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003629 Handle<String> set_name = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003630 STATIC_ASCII_VECTOR("set_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003631 Handle<Object> setter(v8::internal::GetProperty(isolate, desc, set_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003632 ASSERT(!isolate->has_pending_exception());
3633 if (!setter->IsUndefined()) {
3634 // TODO(rossberg): nicer would be to cast to some JSCallable here...
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003635 return SetPropertyWithDefinedSetter(
3636 receiver, Handle<JSReceiver>::cast(setter), value);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003637 }
3638
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003639 if (strict_mode == kNonStrictMode) return value;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003640 Handle<Object> args2[] = { name, proxy };
3641 Handle<Object> error = isolate->factory()->NewTypeError(
3642 "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003643 isolate->Throw(*error);
3644 return Handle<Object>();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003645}
3646
3647
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003648Handle<Object> JSProxy::DeletePropertyWithHandler(
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003649 Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
3650 Isolate* isolate = proxy->GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003651
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003652 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003653 if (name->IsSymbol()) return isolate->factory()->false_value();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003654
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003655 Handle<Object> args[] = { name };
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003656 Handle<Object> result = proxy->CallTrap(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003657 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
3658 if (isolate->has_pending_exception()) return Handle<Object>();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003659
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003660 bool result_bool = result->BooleanValue();
3661 if (mode == STRICT_DELETION && !result_bool) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003662 Handle<Object> handler(proxy->handler(), isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003663 Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003664 STATIC_ASCII_VECTOR("delete"));
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003665 Handle<Object> args[] = { handler, trap_name };
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003666 Handle<Object> error = isolate->factory()->NewTypeError(
3667 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
3668 isolate->Throw(*error);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003669 return Handle<Object>();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003670 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003671 return isolate->factory()->ToBoolean(result_bool);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003672}
3673
3674
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003675Handle<Object> JSProxy::DeleteElementWithHandler(
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003676 Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
3677 Isolate* isolate = proxy->GetIsolate();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003678 Handle<String> name = isolate->factory()->Uint32ToString(index);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003679 return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003680}
3681
3682
3683MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
3684 JSReceiver* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003685 Name* name_raw) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003686 Isolate* isolate = GetIsolate();
3687 HandleScope scope(isolate);
3688 Handle<JSProxy> proxy(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003689 Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003690 Handle<JSReceiver> receiver(receiver_raw);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003691 Handle<Object> name(name_raw, isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003692
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003693 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3694 if (name->IsSymbol()) return ABSENT;
3695
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003696 Handle<Object> args[] = { name };
3697 Handle<Object> result = CallTrap(
3698 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003699 if (isolate->has_pending_exception()) return NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003700
3701 if (result->IsUndefined()) return ABSENT;
3702
3703 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003704 Handle<Object> argv[] = { result };
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003705 Handle<Object> desc = Execution::Call(
3706 isolate, isolate->to_complete_property_descriptor(), result,
3707 ARRAY_SIZE(argv), argv, &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003708 if (has_pending_exception) return NONE;
3709
3710 // Convert result to PropertyAttributes.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003711 Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003712 STATIC_ASCII_VECTOR("enumerable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003713 Handle<Object> enumerable(v8::internal::GetProperty(isolate, desc, enum_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003714 if (isolate->has_pending_exception()) return NONE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003715 Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003716 STATIC_ASCII_VECTOR("configurable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003717 Handle<Object> configurable(v8::internal::GetProperty(isolate, desc, conf_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003718 if (isolate->has_pending_exception()) return NONE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003719 Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003720 STATIC_ASCII_VECTOR("writable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003721 Handle<Object> writable(v8::internal::GetProperty(isolate, desc, writ_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003722 if (isolate->has_pending_exception()) return NONE;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003723 if (!writable->BooleanValue()) {
3724 Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
3725 STATIC_ASCII_VECTOR("set_"));
3726 Handle<Object> setter(v8::internal::GetProperty(isolate, desc, set_n));
3727 if (isolate->has_pending_exception()) return NONE;
3728 writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
3729 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003730
3731 if (configurable->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003732 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003733 STATIC_ASCII_VECTOR("getPropertyDescriptor"));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003734 Handle<Object> args[] = { handler, trap, name };
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003735 Handle<Object> error = isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003736 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003737 isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003738 return NONE;
3739 }
3740
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003741 int attributes = NONE;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003742 if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3743 if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3744 if (!writable->BooleanValue()) attributes |= READ_ONLY;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003745 return static_cast<PropertyAttributes>(attributes);
3746}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003747
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003748
3749MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003750 JSReceiver* receiver_raw,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003751 uint32_t index) {
3752 Isolate* isolate = GetIsolate();
3753 HandleScope scope(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003754 Handle<JSProxy> proxy(this);
3755 Handle<JSReceiver> receiver(receiver_raw);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003756 Handle<String> name = isolate->factory()->Uint32ToString(index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003757 return proxy->GetPropertyAttributeWithHandler(*receiver, *name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003758}
3759
3760
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003761void JSProxy::Fix(Handle<JSProxy> proxy) {
3762 Isolate* isolate = proxy->GetIsolate();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003763
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003764 // Save identity hash.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003765 Handle<Object> hash(proxy->GetIdentityHash(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003766
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003767 if (proxy->IsJSFunctionProxy()) {
3768 isolate->factory()->BecomeJSFunction(proxy);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003769 // Code will be set on the JavaScript side.
3770 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003771 isolate->factory()->BecomeJSObject(proxy);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003772 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003773 ASSERT(proxy->IsJSObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003774
3775 // Inherit identity, if it was present.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003776 if (hash->IsSmi()) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00003777 JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy),
3778 Handle<Smi>::cast(hash));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003779 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003780}
3781
3782
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003783MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
3784 Handle<Object> derived,
3785 int argc,
3786 Handle<Object> argv[]) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003787 Isolate* isolate = GetIsolate();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003788 Handle<Object> handler(this->handler(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003789
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003790 Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003791 Handle<Object> trap(v8::internal::GetProperty(isolate, handler, trap_name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003792 if (isolate->has_pending_exception()) return trap;
3793
3794 if (trap->IsUndefined()) {
3795 if (derived.is_null()) {
3796 Handle<Object> args[] = { handler, trap_name };
3797 Handle<Object> error = isolate->factory()->NewTypeError(
3798 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
3799 isolate->Throw(*error);
3800 return Handle<Object>();
3801 }
3802 trap = Handle<Object>(derived);
3803 }
3804
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003805 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003806 return Execution::Call(isolate, trap, handler, argc, argv, &threw);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003807}
3808
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003809
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003810// TODO(mstarzinger): Temporary wrapper until handlified.
3811static Handle<Map> MapAsElementsKind(Handle<Map> map, ElementsKind kind) {
3812 CALL_HEAP_FUNCTION(map->GetIsolate(), map->AsElementsKind(kind), Map);
3813}
3814
3815
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003816void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003817 ASSERT(object->map()->inobject_properties() == map->inobject_properties());
3818 ElementsKind obj_kind = object->map()->elements_kind();
3819 ElementsKind map_kind = map->elements_kind();
3820 if (map_kind != obj_kind) {
3821 ElementsKind to_kind = map_kind;
3822 if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
3823 IsDictionaryElementsKind(obj_kind)) {
3824 to_kind = obj_kind;
3825 }
3826 if (IsDictionaryElementsKind(to_kind)) {
3827 NormalizeElements(object);
3828 } else {
3829 TransitionElementsKind(object, to_kind);
3830 }
3831 map = MapAsElementsKind(map, to_kind);
3832 }
3833 int total_size =
3834 map->NumberOfOwnDescriptors() + map->unused_property_fields();
3835 int out_of_object = total_size - map->inobject_properties();
3836 if (out_of_object != object->properties()->length()) {
3837 Isolate* isolate = object->GetIsolate();
3838 Handle<FixedArray> new_properties = isolate->factory()->CopySizeFixedArray(
3839 handle(object->properties()), out_of_object);
3840 object->set_properties(*new_properties);
3841 }
3842 object->set_map(*map);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003843}
3844
3845
danno@chromium.orgf005df62013-04-30 16:36:45 +00003846void JSObject::MigrateInstance(Handle<JSObject> object) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003847 // Converting any field to the most specific type will cause the
3848 // GeneralizeFieldRepresentation algorithm to create the most general existing
3849 // transition that matches the object. This achieves what is needed.
3850 Handle<Map> original_map(object->map());
3851 GeneralizeFieldRepresentation(
3852 object, 0, Representation::None(), ALLOW_AS_CONSTANT);
3853 if (FLAG_trace_migration) {
3854 object->PrintInstanceMigration(stdout, *original_map, object->map());
3855 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003856}
3857
3858
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003859Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003860 Map* new_map = object->map()->CurrentMapForDeprecated();
3861 if (new_map == NULL) return Handle<Object>();
3862 Handle<Map> original_map(object->map());
3863 JSObject::MigrateToMap(object, handle(new_map));
3864 if (FLAG_trace_migration) {
3865 object->PrintInstanceMigration(stdout, *original_map, object->map());
3866 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003867 return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003868}
3869
3870
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003871Handle<Object> JSObject::SetPropertyUsingTransition(
3872 Handle<JSObject> object,
3873 LookupResult* lookup,
3874 Handle<Name> name,
3875 Handle<Object> value,
3876 PropertyAttributes attributes) {
3877 Handle<Map> transition_map(lookup->GetTransitionTarget());
rossberg@chromium.org92597162013-08-23 13:28:00 +00003878 int descriptor = transition_map->LastAdded();
3879
3880 DescriptorArray* descriptors = transition_map->instance_descriptors();
3881 PropertyDetails details = descriptors->GetDetails(descriptor);
3882
3883 if (details.type() == CALLBACKS || attributes != details.attributes()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003884 // AddProperty will either normalize the object, or create a new fast copy
3885 // of the map. If we get a fast copy of the map, all field representations
3886 // will be tagged since the transition is omitted.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003887 return JSObject::AddProperty(
3888 object, name, value, attributes, kNonStrictMode,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003889 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
3890 JSReceiver::OMIT_EXTENSIBILITY_CHECK,
3891 JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION);
rossberg@chromium.org92597162013-08-23 13:28:00 +00003892 }
3893
3894 // Keep the target CONSTANT if the same value is stored.
3895 // TODO(verwaest): Also support keeping the placeholder
3896 // (value->IsUninitialized) as constant.
3897 if (details.type() == CONSTANT &&
3898 descriptors->GetValue(descriptor) == *value) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003899 object->set_map(*transition_map);
3900 return value;
rossberg@chromium.org92597162013-08-23 13:28:00 +00003901 }
3902
3903 Representation representation = details.representation();
3904
3905 if (!value->FitsRepresentation(representation) ||
3906 details.type() == CONSTANT) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003907 transition_map = Map::GeneralizeRepresentation(transition_map,
rossberg@chromium.org92597162013-08-23 13:28:00 +00003908 descriptor, value->OptimalRepresentation(), FORCE_FIELD);
rossberg@chromium.org92597162013-08-23 13:28:00 +00003909 Object* back = transition_map->GetBackPointer();
3910 if (back->IsMap()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003911 MigrateToMap(object, handle(Map::cast(back)));
rossberg@chromium.org92597162013-08-23 13:28:00 +00003912 }
3913 descriptors = transition_map->instance_descriptors();
3914 representation = descriptors->GetDetails(descriptor).representation();
3915 }
3916
3917 int field_index = descriptors->GetFieldIndex(descriptor);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003918 AddFastPropertyUsingMap(
3919 object, transition_map, name, value, field_index, representation);
3920 return value;
rossberg@chromium.org92597162013-08-23 13:28:00 +00003921}
3922
3923
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003924static void SetPropertyToField(LookupResult* lookup,
3925 Handle<Name> name,
3926 Handle<Object> value) {
rossberg@chromium.org92597162013-08-23 13:28:00 +00003927 Representation representation = lookup->representation();
3928 if (!value->FitsRepresentation(representation) ||
3929 lookup->type() == CONSTANT) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003930 JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
3931 lookup->GetDescriptorIndex(),
3932 value->OptimalRepresentation(),
3933 FORCE_FIELD);
rossberg@chromium.org92597162013-08-23 13:28:00 +00003934 DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
3935 int descriptor = lookup->GetDescriptorIndex();
3936 representation = desc->GetDetails(descriptor).representation();
3937 }
3938
3939 if (FLAG_track_double_fields && representation.IsDouble()) {
3940 HeapNumber* storage = HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
3941 lookup->GetFieldIndex().field_index()));
3942 storage->set_value(value->Number());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003943 return;
rossberg@chromium.org92597162013-08-23 13:28:00 +00003944 }
3945
3946 lookup->holder()->FastPropertyAtPut(
3947 lookup->GetFieldIndex().field_index(), *value);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003948}
3949
3950
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003951static void ConvertAndSetLocalProperty(LookupResult* lookup,
3952 Handle<Name> name,
3953 Handle<Object> value,
3954 PropertyAttributes attributes) {
3955 Handle<JSObject> object(lookup->holder());
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003956 if (object->TooManyFastProperties()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003957 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003958 }
3959
3960 if (!object->HasFastProperties()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003961 ReplaceSlowProperty(object, name, value, attributes);
3962 return;
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003963 }
3964
3965 int descriptor_index = lookup->GetDescriptorIndex();
3966 if (lookup->GetAttributes() == attributes) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003967 JSObject::GeneralizeFieldRepresentation(
3968 object, descriptor_index, Representation::Tagged(), FORCE_FIELD);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003969 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003970 Handle<Map> old_map(object->map());
3971 Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003972 descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003973 JSObject::MigrateToMap(object, new_map);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003974 }
3975
3976 DescriptorArray* descriptors = object->map()->instance_descriptors();
3977 int index = descriptors->GetDetails(descriptor_index).field_index();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003978 object->FastPropertyAtPut(index, *value);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003979}
3980
3981
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003982static void SetPropertyToFieldWithAttributes(LookupResult* lookup,
3983 Handle<Name> name,
3984 Handle<Object> value,
3985 PropertyAttributes attributes) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003986 if (lookup->GetAttributes() == attributes) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003987 if (value->IsUninitialized()) return;
3988 SetPropertyToField(lookup, name, value);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003989 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003990 ConvertAndSetLocalProperty(lookup, name, value, attributes);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003991 }
3992}
3993
3994
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003995Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
3996 LookupResult* lookup,
3997 Handle<Name> name,
3998 Handle<Object> value,
3999 PropertyAttributes attributes,
4000 StrictModeFlag strict_mode,
4001 StoreFromKeyed store_mode) {
4002 Isolate* isolate = object->GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004003
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 // Make sure that the top context does not change when doing callbacks or
4005 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004006 AssertNoContextChange ncc(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004007
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004008 // Optimization for 2-byte strings often used as keys in a decompression
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004009 // dictionary. We internalize these short keys to avoid constantly
ager@chromium.org6141cbe2009-11-20 12:14:52 +00004010 // reallocating them.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004011 if (name->IsString() && !name->IsInternalizedString() &&
4012 Handle<String>::cast(name)->length() <= 2) {
4013 name = isolate->factory()->InternalizeString(Handle<String>::cast(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004015
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004016 // Check access rights if needed.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004017 if (object->IsAccessCheckNeeded()) {
4018 if (!isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
4019 return SetPropertyWithFailedAccessCheck(object, lookup, name, value,
4020 true, strict_mode);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004021 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004022 }
4023
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004024 if (object->IsJSGlobalProxy()) {
4025 Handle<Object> proto(object->GetPrototype(), isolate);
4026 if (proto->IsNull()) return value;
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004027 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004028 return SetPropertyForResult(Handle<JSObject>::cast(proto),
4029 lookup, name, value, attributes, strict_mode, store_mode);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00004030 }
4031
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004032 ASSERT(!lookup->IsFound() || lookup->holder() == *object ||
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004033 lookup->holder()->map()->is_hidden_prototype());
4034
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004035 if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004036 bool done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004037 Handle<Object> result_object = SetPropertyViaPrototypes(
4038 object, name, value, attributes, strict_mode, &done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004039 if (done) return result_object;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004040 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004041
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004042 if (!lookup->IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004043 // Neither properties nor transitions found.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004044 return AddProperty(
4045 object, name, value, attributes, strict_mode, store_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004046 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004047
4048 if (lookup->IsProperty() && lookup->IsReadOnly()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004049 if (strict_mode == kStrictMode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004050 Handle<Object> args[] = { name, object };
4051 Handle<Object> error = isolate->factory()->NewTypeError(
4052 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
4053 isolate->Throw(*error);
4054 return Handle<Object>();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004055 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004056 return value;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004057 }
4058 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004059
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004060 Handle<Object> old_value = isolate->factory()->the_hole_value();
mstarzinger@chromium.org69008382013-10-18 10:34:25 +00004061 bool is_observed = FLAG_harmony_observation &&
4062 object->map()->is_observed() &&
4063 *name != isolate->heap()->hidden_string();
4064 if (is_observed && lookup->IsDataProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004065 old_value = Object::GetProperty(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004066 }
4067
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004068 // This is a real property that is not read-only, or it is a
4069 // transition or null descriptor and there are no setters in the prototypes.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004070 Handle<Object> result = value;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004071 switch (lookup->type()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004072 case NORMAL:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004073 SetNormalizedProperty(handle(lookup->holder()), lookup, value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004074 break;
rossberg@chromium.org92597162013-08-23 13:28:00 +00004075 case FIELD:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004076 SetPropertyToField(lookup, name, value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004077 break;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004078 case CONSTANT:
4079 // Only replace the constant if necessary.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004080 if (*value == lookup->GetConstant()) return value;
4081 SetPropertyToField(lookup, name, value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004082 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004083 case CALLBACKS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004084 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate);
4085 return SetPropertyWithCallback(object, callback_object, name, value,
4086 handle(lookup->holder()), strict_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004087 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004088 case INTERCEPTOR:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004089 result = SetPropertyWithInterceptor(handle(lookup->holder()), name, value,
4090 attributes, strict_mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004091 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004092 case TRANSITION:
4093 result = SetPropertyUsingTransition(handle(lookup->holder()), lookup,
4094 name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004095 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004096 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004097 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004098 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004100
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004101 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004102
mstarzinger@chromium.org69008382013-10-18 10:34:25 +00004103 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004104 if (lookup->IsTransition()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004105 EnqueueChangeRecord(object, "add", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004106 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004107 LookupResult new_lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004108 object->LocalLookup(*name, &new_lookup, true);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004109 if (new_lookup.IsDataProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004110 Handle<Object> new_value = Object::GetProperty(object, name);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004111 if (!new_value->SameValue(*old_value)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004112 EnqueueChangeRecord(object, "update", name, old_value);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004113 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004114 }
4115 }
4116 }
4117
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004118 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119}
4120
4121
4122// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004123// present, add it with attributes NONE. This code is an exact clone of
4124// SetProperty, with the check for IsReadOnly and the check for a
4125// callback setter removed. The two lines looking up the LookupResult
4126// result are also added. If one of the functions is changed, the other
4127// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004128// Note that this method cannot be used to set the prototype of a function
4129// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
4130// doesn't handle function prototypes correctly.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004131Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
4132 Handle<JSObject> object,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004133 Handle<Name> name,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004134 Handle<Object> value,
danno@chromium.org1fd77d52013-06-07 16:01:45 +00004135 PropertyAttributes attributes,
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004136 ValueType value_type,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004137 StoreMode mode,
4138 ExtensibilityCheck extensibility_check) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004139 Isolate* isolate = object->GetIsolate();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004140
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004141 // Make sure that the top context does not change when doing callbacks or
4142 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004143 AssertNoContextChange ncc(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004144
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004145 LookupResult lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004146 object->LocalLookup(*name, &lookup, true);
4147 if (!lookup.IsFound()) {
4148 object->map()->LookupTransition(*object, *name, &lookup);
4149 }
4150
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004151 // Check access rights if needed.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004152 if (object->IsAccessCheckNeeded()) {
4153 if (!isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
4154 return SetPropertyWithFailedAccessCheck(object, &lookup, name, value,
4155 false, kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004156 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004158
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004159 if (object->IsJSGlobalProxy()) {
4160 Handle<Object> proto(object->GetPrototype(), isolate);
4161 if (proto->IsNull()) return value;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004162 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004163 return SetLocalPropertyIgnoreAttributes(Handle<JSObject>::cast(proto),
4164 name, value, attributes, value_type, mode, extensibility_check);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004165 }
4166
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004167 if (lookup.IsFound() &&
4168 (lookup.type() == INTERCEPTOR || lookup.type() == CALLBACKS)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004169 object->LocalLookupRealNamedProperty(*name, &lookup);
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004170 }
4171
ager@chromium.org7c537e22008-10-16 08:43:32 +00004172 // Check for accessor in prototype chain removed here in clone.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004173 if (!lookup.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004174 // Neither properties nor transitions found.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004175 return AddProperty(object, name, value, attributes, kNonStrictMode,
rossberg@chromium.org92597162013-08-23 13:28:00 +00004176 MAY_BE_STORE_FROM_KEYED, extensibility_check, value_type, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004177 }
4178
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004179 Handle<Object> old_value = isolate->factory()->the_hole_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004180 PropertyAttributes old_attributes = ABSENT;
mstarzinger@chromium.org69008382013-10-18 10:34:25 +00004181 bool is_observed = FLAG_harmony_observation &&
4182 object->map()->is_observed() &&
4183 *name != isolate->heap()->hidden_string();
danno@chromium.org169691d2013-07-15 08:01:13 +00004184 if (is_observed && lookup.IsProperty()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004185 if (lookup.IsDataProperty()) old_value =
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004186 Object::GetProperty(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004187 old_attributes = lookup.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004189
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004190 // Check of IsReadOnly removed from here in clone.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004191 switch (lookup.type()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004192 case NORMAL:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004193 ReplaceSlowProperty(object, name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004194 break;
rossberg@chromium.org92597162013-08-23 13:28:00 +00004195 case FIELD:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004196 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004197 break;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004198 case CONSTANT:
rossberg@chromium.org92597162013-08-23 13:28:00 +00004199 // Only replace the constant if necessary.
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004200 if (lookup.GetAttributes() != attributes ||
4201 *value != lookup.GetConstant()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004202 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004203 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004204 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004205 case CALLBACKS:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004206 ConvertAndSetLocalProperty(&lookup, name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004207 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004208 case TRANSITION: {
4209 Handle<Object> result = SetPropertyUsingTransition(
4210 handle(lookup.holder()), &lookup, name, value, attributes);
4211 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004212 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004213 }
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004214 case NONEXISTENT:
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004215 case HANDLER:
4216 case INTERCEPTOR:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004217 UNREACHABLE();
4218 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004219
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00004220 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004221 if (lookup.IsTransition()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004222 EnqueueChangeRecord(object, "add", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00004223 } else if (old_value->IsTheHole()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004224 EnqueueChangeRecord(object, "reconfigure", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004225 } else {
4226 LookupResult new_lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004227 object->LocalLookup(*name, &new_lookup, true);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004228 bool value_changed = false;
4229 if (new_lookup.IsDataProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004230 Handle<Object> new_value = Object::GetProperty(object, name);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004231 value_changed = !old_value->SameValue(*new_value);
4232 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00004233 if (new_lookup.GetAttributes() != old_attributes) {
4234 if (!value_changed) old_value = isolate->factory()->the_hole_value();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004235 EnqueueChangeRecord(object, "reconfigure", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00004236 } else if (value_changed) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004237 EnqueueChangeRecord(object, "update", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004238 }
4239 }
4240 }
4241
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004242 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243}
4244
4245
4246PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
4247 JSObject* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004248 Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004249 bool continue_search) {
4250 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004251 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004252 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004253 if (result.IsFound()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004254
4255 if (continue_search) {
4256 // Continue searching via the prototype chain.
4257 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004258 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004259 return JSObject::cast(pt)->
4260 GetPropertyAttributeWithReceiver(receiver, name);
4261 }
4262 }
4263 return ABSENT;
4264}
4265
4266
4267PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
4268 JSObject* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004269 Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004270 bool continue_search) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004271 // TODO(rossberg): Support symbols in the API.
4272 if (name->IsSymbol()) return ABSENT;
4273
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004274 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004275 HandleScope scope(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004277 // Make sure that the top context does not change when doing
4278 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004279 AssertNoContextChange ncc(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004281 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
4282 Handle<JSObject> receiver_handle(receiver);
4283 Handle<JSObject> holder_handle(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004284 Handle<String> name_handle(String::cast(name));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004285 PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004286 if (!interceptor->query()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004287 v8::NamedPropertyQueryCallback query =
4288 v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004289 LOG(isolate,
4290 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004291 v8::Handle<v8::Integer> result =
4292 args.Call(query, v8::Utils::ToLocal(name_handle));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004293 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004294 ASSERT(result->IsInt32());
4295 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 }
4297 } else if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004298 v8::NamedPropertyGetterCallback getter =
4299 v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004300 LOG(isolate,
4301 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004302 v8::Handle<v8::Value> result =
4303 args.Call(getter, v8::Utils::ToLocal(name_handle));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004304 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004305 }
4306 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
4307 *name_handle,
4308 continue_search);
4309}
4310
4311
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004312PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
4313 JSReceiver* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004314 Name* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004315 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004316 if (IsJSObject() && key->AsArrayIndex(&index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004317 return JSObject::cast(this)->GetElementAttributeWithReceiver(
4318 receiver, index, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 }
4320 // Named property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004321 LookupResult lookup(GetIsolate());
4322 Lookup(key, &lookup);
4323 return GetPropertyAttributeForResult(receiver, &lookup, key, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004324}
4325
4326
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004327PropertyAttributes JSReceiver::GetPropertyAttributeForResult(
4328 JSReceiver* receiver,
4329 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004330 Name* name,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004331 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004332 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004333 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004334 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004336 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
4337 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004338 receiver, lookup, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004340 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004341 if (lookup->IsFound()) {
4342 switch (lookup->type()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004343 case NORMAL: // fall through
4344 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004345 case CONSTANT:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 case CALLBACKS:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004347 return lookup->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004348 case HANDLER: {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004349 return JSProxy::cast(lookup->proxy())->GetPropertyAttributeWithHandler(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004350 receiver, name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004351 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004352 case INTERCEPTOR:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004353 return lookup->holder()->GetPropertyAttributeWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004354 JSObject::cast(receiver), name, continue_search);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004355 case TRANSITION:
4356 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004357 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004358 }
4359 }
4360 return ABSENT;
4361}
4362
4363
ulan@chromium.org750145a2013-03-07 15:14:13 +00004364PropertyAttributes JSReceiver::GetLocalPropertyAttribute(Name* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004366 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004367 if (IsJSObject() && name->AsArrayIndex(&index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004368 return GetLocalElementAttribute(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004369 }
4370 // Named property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004371 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004372 LocalLookup(name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004373 return GetPropertyAttributeForResult(this, &lookup, name, false);
4374}
4375
4376
4377PropertyAttributes JSObject::GetElementAttributeWithReceiver(
4378 JSReceiver* receiver, uint32_t index, bool continue_search) {
4379 Isolate* isolate = GetIsolate();
4380
4381 // Check access rights if needed.
4382 if (IsAccessCheckNeeded()) {
4383 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
4384 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4385 return ABSENT;
4386 }
4387 }
4388
4389 if (IsJSGlobalProxy()) {
4390 Object* proto = GetPrototype();
4391 if (proto->IsNull()) return ABSENT;
4392 ASSERT(proto->IsJSGlobalObject());
4393 return JSObject::cast(proto)->GetElementAttributeWithReceiver(
4394 receiver, index, continue_search);
4395 }
4396
4397 // Check for lookup interceptor except when bootstrapping.
4398 if (HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4399 return GetElementAttributeWithInterceptor(receiver, index, continue_search);
4400 }
4401
4402 return GetElementAttributeWithoutInterceptor(
4403 receiver, index, continue_search);
4404}
4405
4406
4407PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
4408 JSReceiver* receiver, uint32_t index, bool continue_search) {
4409 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004410 HandleScope scope(isolate);
4411
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004412 // Make sure that the top context does not change when doing
4413 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004414 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004415
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004416 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
4417 Handle<JSReceiver> hreceiver(receiver);
4418 Handle<JSObject> holder(this);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004419 PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004420 if (!interceptor->query()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004421 v8::IndexedPropertyQueryCallback query =
4422 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004423 LOG(isolate,
4424 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004425 v8::Handle<v8::Integer> result = args.Call(query, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004426 if (!result.IsEmpty())
4427 return static_cast<PropertyAttributes>(result->Int32Value());
4428 } else if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004429 v8::IndexedPropertyGetterCallback getter =
4430 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004431 LOG(isolate,
4432 ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004433 v8::Handle<v8::Value> result = args.Call(getter, index);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004434 if (!result.IsEmpty()) return NONE;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004435 }
4436
4437 return holder->GetElementAttributeWithoutInterceptor(
4438 *hreceiver, index, continue_search);
4439}
4440
4441
4442PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor(
4443 JSReceiver* receiver, uint32_t index, bool continue_search) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004444 PropertyAttributes attr = GetElementsAccessor()->GetAttributes(
4445 receiver, this, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004446 if (attr != ABSENT) return attr;
4447
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004448 // Handle [] on String objects.
4449 if (IsStringObjectWithCharacterAt(index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004450 return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
4451 }
4452
4453 if (!continue_search) return ABSENT;
4454
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004455 Object* pt = GetPrototype();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004456 if (pt->IsJSProxy()) {
4457 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004458 return JSProxy::cast(pt)->GetElementAttributeWithHandler(receiver, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004459 }
4460 if (pt->IsNull()) return ABSENT;
4461 return JSObject::cast(pt)->GetElementAttributeWithReceiver(
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004462 receiver, index, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463}
4464
4465
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004466Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache,
4467 Handle<JSObject> obj,
4468 PropertyNormalizationMode mode) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004469 int index = obj->map()->Hash() % kEntries;
4470 Handle<Object> result = handle(cache->get(index), cache->GetIsolate());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004471 if (result->IsMap() &&
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004472 Handle<Map>::cast(result)->EquivalentToForNormalization(obj->map(),
4473 mode)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004474#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004475 if (FLAG_verify_heap) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004476 Handle<Map>::cast(result)->SharedMapVerify();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004477 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004478#endif
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00004479#ifdef ENABLE_SLOW_ASSERTS
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004480 if (FLAG_enable_slow_asserts) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004481 // The cached map should match newly created normalized map bit-by-bit,
4482 // except for the code cache, which can contain some ics which can be
4483 // applied to the shared map.
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004484 Handle<Map> fresh = Map::CopyNormalized(handle(obj->map()), mode,
4485 SHARED_NORMALIZED_MAP);
4486
4487 ASSERT(memcmp(fresh->address(),
4488 Handle<Map>::cast(result)->address(),
4489 Map::kCodeCacheOffset) == 0);
4490 STATIC_ASSERT(Map::kDependentCodeOffset ==
4491 Map::kCodeCacheOffset + kPointerSize);
4492 int offset = Map::kDependentCodeOffset + kPointerSize;
4493 ASSERT(memcmp(fresh->address() + offset,
4494 Handle<Map>::cast(result)->address() + offset,
4495 Map::kSize - offset) == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004496 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004497#endif
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004498 return Handle<Map>::cast(result);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004499 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004500
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004501 Isolate* isolate = cache->GetIsolate();
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00004502 Handle<Map> map = Map::CopyNormalized(handle(obj->map()), mode,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004503 SHARED_NORMALIZED_MAP);
4504 ASSERT(map->is_dictionary_map());
4505 cache->set(index, *map);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004506 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004507
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004508 return map;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004509}
4510
4511
ricow@chromium.org65fae842010-08-25 15:26:24 +00004512void NormalizedMapCache::Clear() {
4513 int entries = length();
4514 for (int i = 0; i != entries; i++) {
4515 set_undefined(i);
4516 }
4517}
4518
4519
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004520void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
4521 Handle<Name> name,
4522 Handle<Code> code) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004523 Handle<Map> map(object->map());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004524 Map::UpdateCodeCache(map, name, code);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004525}
4526
4527
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004528void JSObject::NormalizeProperties(Handle<JSObject> object,
4529 PropertyNormalizationMode mode,
4530 int expected_additional_properties) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004531 if (!object->HasFastProperties()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004532
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004533 // The global object is always normalized.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004534 ASSERT(!object->IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004535 // JSGlobalProxy must never be normalized
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004536 ASSERT(!object->IsJSGlobalProxy());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004537
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004538 Isolate* isolate = object->GetIsolate();
4539 HandleScope scope(isolate);
4540 Handle<Map> map(object->map());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004541
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004542 // Allocate new content.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004543 int real_size = map->NumberOfOwnDescriptors();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004544 int property_count = real_size;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004545 if (expected_additional_properties > 0) {
4546 property_count += expected_additional_properties;
4547 } else {
4548 property_count += 2; // Make space for two more properties.
4549 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004550 Handle<NameDictionary> dictionary =
4551 isolate->factory()->NewNameDictionary(property_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004553 Handle<DescriptorArray> descs(map->instance_descriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004554 for (int i = 0; i < real_size; i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004555 PropertyDetails details = descs->GetDetails(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004556 switch (details.type()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004557 case CONSTANT: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004558 Handle<Name> key(descs->GetKey(i));
4559 Handle<Object> value(descs->GetConstant(i), isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004560 PropertyDetails d = PropertyDetails(
4561 details.attributes(), NORMAL, i + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004562 dictionary = NameDictionaryAdd(dictionary, key, value, d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 break;
4564 }
4565 case FIELD: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004566 Handle<Name> key(descs->GetKey(i));
4567 Handle<Object> value(
4568 object->RawFastPropertyAt(descs->GetFieldIndex(i)), isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004569 PropertyDetails d =
4570 PropertyDetails(details.attributes(), NORMAL, i + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004571 dictionary = NameDictionaryAdd(dictionary, key, value, d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004572 break;
4573 }
4574 case CALLBACKS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004575 Handle<Name> key(descs->GetKey(i));
4576 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004577 PropertyDetails d = PropertyDetails(
4578 details.attributes(), CALLBACKS, i + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004579 dictionary = NameDictionaryAdd(dictionary, key, value, d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004580 break;
4581 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004582 case INTERCEPTOR:
4583 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004584 case HANDLER:
4585 case NORMAL:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004586 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004587 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004588 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00004589 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004590 }
4591 }
4592
4593 // Copy the next enumeration index from instance descriptor.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004594 dictionary->SetNextEnumerationIndex(real_size + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004596 Handle<NormalizedMapCache> cache(
4597 isolate->context()->native_context()->normalized_map_cache());
4598 Handle<Map> new_map = NormalizedMapCache::Get(cache, object, mode);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004599 ASSERT(new_map->is_dictionary_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004601 // From here on we cannot fail and we shouldn't GC anymore.
4602 DisallowHeapAllocation no_allocation;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004603
4604 // Resize the object in the heap if necessary.
4605 int new_instance_size = new_map->instance_size();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004606 int instance_size_delta = map->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004607 ASSERT(instance_size_delta >= 0);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004608 isolate->heap()->CreateFillerObjectAt(object->address() + new_instance_size,
4609 instance_size_delta);
4610 if (Marking::IsBlack(Marking::MarkBitFrom(*object))) {
4611 MemoryChunk::IncrementLiveBytesFromMutator(object->address(),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004612 -instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004613 }
4614
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004615 object->set_map(*new_map);
4616 map->NotifyLeafMapLayoutChange();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004618 object->set_properties(*dictionary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004619
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004620 isolate->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621
4622#ifdef DEBUG
4623 if (FLAG_trace_normalization) {
4624 PrintF("Object properties have been normalized:\n");
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004625 object->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004626 }
4627#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004628}
4629
4630
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004631void JSObject::TransformToFastProperties(Handle<JSObject> object,
4632 int unused_property_fields) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004633 if (object->HasFastProperties()) return;
4634 ASSERT(!object->IsGlobalObject());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004635 CALL_HEAP_FUNCTION_VOID(
4636 object->GetIsolate(),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004637 object->property_dictionary()->TransformPropertiesToFastFor(
4638 *object, unused_property_fields));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004639}
4640
4641
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004642static MUST_USE_RESULT MaybeObject* CopyFastElementsToDictionary(
4643 Isolate* isolate,
4644 FixedArrayBase* array,
4645 int length,
4646 SeededNumberDictionary* dictionary) {
4647 Heap* heap = isolate->heap();
4648 bool has_double_elements = array->IsFixedDoubleArray();
4649 for (int i = 0; i < length; i++) {
4650 Object* value = NULL;
4651 if (has_double_elements) {
4652 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
4653 if (double_array->is_the_hole(i)) {
4654 value = isolate->heap()->the_hole_value();
4655 } else {
4656 // Objects must be allocated in the old object space, since the
4657 // overall number of HeapNumbers needed for the conversion might
4658 // exceed the capacity of new space, and we would fail repeatedly
4659 // trying to convert the FixedDoubleArray.
4660 MaybeObject* maybe_value_object =
4661 heap->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
4662 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
4663 }
4664 } else {
4665 value = FixedArray::cast(array)->get(i);
4666 }
4667 if (!value->IsTheHole()) {
4668 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
4669 MaybeObject* maybe_result =
4670 dictionary->AddNumberEntry(i, value, details);
4671 if (!maybe_result->To(&dictionary)) return maybe_result;
4672 }
4673 }
4674 return dictionary;
4675}
4676
4677
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004678static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
4679 Handle<FixedArrayBase> array,
4680 int length,
4681 Handle<SeededNumberDictionary> dict) {
4682 Isolate* isolate = array->GetIsolate();
4683 CALL_HEAP_FUNCTION(isolate,
4684 CopyFastElementsToDictionary(
4685 isolate, *array, length, *dict),
4686 SeededNumberDictionary);
4687}
4688
4689
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004690Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4691 Handle<JSObject> object) {
4692 CALL_HEAP_FUNCTION(object->GetIsolate(),
4693 object->NormalizeElements(),
4694 SeededNumberDictionary);
4695}
4696
4697
lrn@chromium.org303ada72010-10-27 09:33:13 +00004698MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004699 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004700
whesse@chromium.org7b260152011-06-20 15:33:18 +00004701 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004702 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004703 Map* old_map = array->map();
4704 bool is_arguments =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004705 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004706 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004707 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004708 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004709 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004711 ASSERT(HasFastSmiOrObjectElements() ||
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004712 HasFastDoubleElements() ||
4713 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004714 // Compute the effective length and allocate a new backing store.
4715 int length = IsJSArray()
4716 ? Smi::cast(JSArray::cast(this)->length())->value()
4717 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004718 int old_capacity = 0;
4719 int used_elements = 0;
4720 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004721 SeededNumberDictionary* dictionary;
4722 MaybeObject* maybe_dictionary =
4723 SeededNumberDictionary::Allocate(GetHeap(), used_elements);
4724 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004725
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004726 maybe_dictionary = CopyFastElementsToDictionary(
4727 GetIsolate(), array, length, dictionary);
4728 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729
whesse@chromium.org7b260152011-06-20 15:33:18 +00004730 // Switch to using the dictionary as the backing storage for elements.
4731 if (is_arguments) {
4732 FixedArray::cast(elements())->set(1, dictionary);
4733 } else {
4734 // Set the new map first to satify the elements type assert in
4735 // set_elements().
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004736 Map* new_map;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004737 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
4738 DICTIONARY_ELEMENTS);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004739 if (!maybe->To(&new_map)) return maybe;
4740 set_map(new_map);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004741 set_elements(dictionary);
4742 }
4743
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004744 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
4745 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746
4747#ifdef DEBUG
4748 if (FLAG_trace_normalization) {
4749 PrintF("Object elements have been normalized:\n");
4750 Print();
4751 }
4752#endif
4753
whesse@chromium.org7b260152011-06-20 15:33:18 +00004754 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4755 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756}
4757
4758
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004759Smi* JSReceiver::GenerateIdentityHash() {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004760 Isolate* isolate = GetIsolate();
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004761
4762 int hash_value;
4763 int attempts = 0;
4764 do {
4765 // Generate a random 32-bit hash value but limit range to fit
4766 // within a smi.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004767 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004768 attempts++;
4769 } while (hash_value == 0 && attempts < 30);
4770 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
4771
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004772 return Smi::FromInt(hash_value);
4773}
4774
4775
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004776void JSObject::SetIdentityHash(Handle<JSObject> object, Handle<Smi> hash) {
4777 Isolate* isolate = object->GetIsolate();
4778 SetHiddenProperty(object, isolate->factory()->identity_hash_string(), hash);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004779}
4780
4781
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004782Object* JSObject::GetIdentityHash() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004783 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004784 return stored_value->IsSmi() ? stored_value : GetHeap()->undefined_value();
4785}
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004786
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004787
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004788Handle<Object> JSObject::GetOrCreateIdentityHash(Handle<JSObject> object) {
4789 Handle<Object> hash(object->GetIdentityHash(), object->GetIsolate());
4790 if (hash->IsSmi())
4791 return hash;
4792
4793 Isolate* isolate = object->GetIsolate();
4794
4795 hash = handle(object->GenerateIdentityHash(), isolate);
4796 Handle<Object> result = SetHiddenProperty(object,
4797 isolate->factory()->identity_hash_string(), hash);
4798
4799 if (result->IsUndefined()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004800 // Trying to get hash of detached proxy.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004801 return handle(Smi::FromInt(0), isolate);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004802 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004803
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004804 return hash;
4805}
4806
4807
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004808Object* JSProxy::GetIdentityHash() {
4809 return this->hash();
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004810}
4811
4812
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004813Handle<Object> JSProxy::GetOrCreateIdentityHash(Handle<JSProxy> proxy) {
4814 Isolate* isolate = proxy->GetIsolate();
4815
4816 Handle<Object> hash(proxy->GetIdentityHash(), isolate);
4817 if (hash->IsSmi())
4818 return hash;
4819
4820 hash = handle(proxy->GenerateIdentityHash(), isolate);
4821 proxy->set_hash(*hash);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004822 return hash;
4823}
4824
4825
ulan@chromium.org750145a2013-03-07 15:14:13 +00004826Object* JSObject::GetHiddenProperty(Name* key) {
4827 ASSERT(key->IsUniqueName());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 if (IsJSGlobalProxy()) {
4829 // For a proxy, use the prototype as target object.
4830 Object* proxy_parent = GetPrototype();
4831 // If the proxy is detached, return undefined.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004832 if (proxy_parent->IsNull()) return GetHeap()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004833 ASSERT(proxy_parent->IsJSGlobalObject());
4834 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
4835 }
4836 ASSERT(!IsJSGlobalProxy());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004837 Object* inline_value = GetHiddenPropertiesHashTable();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004838
4839 if (inline_value->IsSmi()) {
4840 // Handle inline-stored identity hash.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004841 if (key == GetHeap()->identity_hash_string()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004842 return inline_value;
4843 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004844 return GetHeap()->the_hole_value();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004845 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004846 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004847
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004848 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004849
4850 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4851 Object* entry = hashtable->Lookup(key);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004852 return entry;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004853}
4854
4855
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004856Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004857 Handle<Name> key,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004858 Handle<Object> value) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004859 Isolate* isolate = object->GetIsolate();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004860
ulan@chromium.org750145a2013-03-07 15:14:13 +00004861 ASSERT(key->IsUniqueName());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004862 if (object->IsJSGlobalProxy()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004863 // For a proxy, use the prototype as target object.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004864 Handle<Object> proxy_parent(object->GetPrototype(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004865 // If the proxy is detached, return undefined.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004866 if (proxy_parent->IsNull()) return isolate->factory()->undefined_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004867 ASSERT(proxy_parent->IsJSGlobalObject());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004868 return SetHiddenProperty(Handle<JSObject>::cast(proxy_parent), key, value);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004869 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004870 ASSERT(!object->IsJSGlobalProxy());
4871
4872 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004873
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004874 // If there is no backing store yet, store the identity hash inline.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004875 if (value->IsSmi() &&
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004876 *key == *isolate->factory()->identity_hash_string() &&
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004877 (inline_value->IsUndefined() || inline_value->IsSmi())) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004878 return JSObject::SetHiddenPropertiesHashTable(object, value);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004879 }
4880
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004881 Handle<ObjectHashTable> hashtable =
4882 GetOrCreateHiddenPropertiesHashtable(object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004883
4884 // If it was found, check if the key is already in the dictionary.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004885 Handle<ObjectHashTable> new_table = ObjectHashTable::Put(hashtable, key,
4886 value);
4887 if (*new_table != *hashtable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004888 // If adding the key expanded the dictionary (i.e., Add returned a new
4889 // dictionary), store it back to the object.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004890 SetHiddenPropertiesHashTable(object, new_table);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004891 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004892
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004893 // Return this to mark success.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004894 return object;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004895}
4896
4897
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004898void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
4899 Isolate* isolate = object->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00004900 ASSERT(key->IsUniqueName());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004901
4902 if (object->IsJSGlobalProxy()) {
4903 Handle<Object> proto(object->GetPrototype(), isolate);
4904 if (proto->IsNull()) return;
4905 ASSERT(proto->IsJSGlobalObject());
4906 return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004907 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004908
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004909 Object* inline_value = object->GetHiddenPropertiesHashTable();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004910
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004911 // We never delete (inline-stored) identity hashes.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004912 ASSERT(*key != *isolate->factory()->identity_hash_string());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004913 if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
4914
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004915 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004916 ObjectHashTable::Put(hashtable, key, isolate->factory()->the_hole_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004917}
4918
4919
4920bool JSObject::HasHiddenProperties() {
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00004921 return GetPropertyAttributePostInterceptor(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004922 GetHeap()->hidden_string(),
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00004923 false) != ABSENT;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004924}
4925
4926
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004927Object* JSObject::GetHiddenPropertiesHashTable() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004928 ASSERT(!IsJSGlobalProxy());
4929 if (HasFastProperties()) {
4930 // If the object has fast properties, check whether the first slot
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004931 // in the descriptor array matches the hidden string. Since the
ulan@chromium.org750145a2013-03-07 15:14:13 +00004932 // hidden strings hash code is zero (and no other name has hash
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004933 // code zero) it will always occupy the first entry if present.
4934 DescriptorArray* descriptors = this->map()->instance_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004935 if (descriptors->number_of_descriptors() > 0) {
4936 int sorted_index = descriptors->GetSortedKeyIndex(0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004937 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004938 sorted_index < map()->NumberOfOwnDescriptors()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004939 ASSERT(descriptors->GetType(sorted_index) == FIELD);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004940 ASSERT(descriptors->GetDetails(sorted_index).representation().
4941 IsCompatibleForLoad(Representation::Tagged()));
4942 return this->RawFastPropertyAt(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004943 descriptors->GetFieldIndex(sorted_index));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004944 } else {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004945 return GetHeap()->undefined_value();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004946 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004947 } else {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004948 return GetHeap()->undefined_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004949 }
4950 } else {
4951 PropertyAttributes attributes;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004952 // You can't install a getter on a property indexed by the hidden string,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004953 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
4954 // object.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004955 return GetLocalPropertyPostInterceptor(this,
4956 GetHeap()->hidden_string(),
4957 &attributes)->ToObjectUnchecked();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004958 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004959}
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004960
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004961Handle<ObjectHashTable> JSObject::GetOrCreateHiddenPropertiesHashtable(
4962 Handle<JSObject> object) {
4963 Isolate* isolate = object->GetIsolate();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004964
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004965 static const int kInitialCapacity = 4;
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004966 Handle<Object> inline_value(object->GetHiddenPropertiesHashTable(), isolate);
4967 if (inline_value->IsHashTable()) {
4968 return Handle<ObjectHashTable>::cast(inline_value);
4969 }
4970
4971 Handle<ObjectHashTable> hashtable = isolate->factory()->NewObjectHashTable(
4972 kInitialCapacity,
4973 USE_CUSTOM_MINIMUM_CAPACITY);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004974
4975 if (inline_value->IsSmi()) {
4976 // We were storing the identity hash inline and now allocated an actual
4977 // dictionary. Put the identity hash into the new dictionary.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004978 hashtable = ObjectHashTable::Put(hashtable,
4979 isolate->factory()->identity_hash_string(),
4980 inline_value);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004981 }
4982
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004983 JSObject::SetLocalPropertyIgnoreAttributes(
4984 object,
4985 isolate->factory()->hidden_string(),
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004986 hashtable,
4987 DONT_ENUM,
4988 OPTIMAL_REPRESENTATION,
4989 ALLOW_AS_CONSTANT,
4990 OMIT_EXTENSIBILITY_CHECK);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004991
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004992 return hashtable;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004993}
4994
4995
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004996Handle<Object> JSObject::SetHiddenPropertiesHashTable(Handle<JSObject> object,
4997 Handle<Object> value) {
4998 ASSERT(!object->IsJSGlobalProxy());
4999
5000 Isolate* isolate = object->GetIsolate();
5001
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00005002 // We can store the identity hash inline iff there is no backing store
5003 // for hidden properties yet.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005004 ASSERT(object->HasHiddenProperties() != value->IsSmi());
5005 if (object->HasFastProperties()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005006 // If the object has fast properties, check whether the first slot
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005007 // in the descriptor array matches the hidden string. Since the
ulan@chromium.org750145a2013-03-07 15:14:13 +00005008 // hidden strings hash code is zero (and no other name has hash
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005009 // code zero) it will always occupy the first entry if present.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005010 DescriptorArray* descriptors = object->map()->instance_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005011 if (descriptors->number_of_descriptors() > 0) {
5012 int sorted_index = descriptors->GetSortedKeyIndex(0);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005013 if (descriptors->GetKey(sorted_index) == isolate->heap()->hidden_string()
5014 && sorted_index < object->map()->NumberOfOwnDescriptors()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005015 ASSERT(descriptors->GetType(sorted_index) == FIELD);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005016 object->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index),
5017 *value);
5018 return object;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005019 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005020 }
5021 }
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005022
5023 SetLocalPropertyIgnoreAttributes(object,
5024 isolate->factory()->hidden_string(),
5025 value,
5026 DONT_ENUM,
5027 OPTIMAL_REPRESENTATION,
5028 ALLOW_AS_CONSTANT,
5029 OMIT_EXTENSIBILITY_CHECK);
5030 return object;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005031}
5032
5033
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005034Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object,
5035 Handle<Name> name,
5036 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005037 // Check local property, ignore interceptor.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005038 Isolate* isolate = object->GetIsolate();
5039 LookupResult result(isolate);
5040 object->LocalLookupRealNamedProperty(*name, &result);
5041 if (!result.IsFound()) return isolate->factory()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005042
5043 // Normalize object if needed.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005044 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005045
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005046 return DeleteNormalizedProperty(object, name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005047}
5048
5049
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005050Handle<Object> JSObject::DeletePropertyWithInterceptor(Handle<JSObject> object,
5051 Handle<Name> name) {
5052 Isolate* isolate = object->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005053
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005054 // TODO(rossberg): Support symbols in the API.
5055 if (name->IsSymbol()) return isolate->factory()->false_value();
5056
5057 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005058 if (!interceptor->deleter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005059 v8::NamedPropertyDeleterCallback deleter =
5060 v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005061 LOG(isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005062 ApiNamedPropertyAccess("interceptor-named-delete", *object, *name));
5063 PropertyCallbackArguments args(
5064 isolate, interceptor->data(), *object, *object);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005065 v8::Handle<v8::Boolean> result =
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005066 args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name)));
5067 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005068 if (!result.IsEmpty()) {
5069 ASSERT(result->IsBoolean());
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00005070 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5071 result_internal->VerifyApiCallResultType();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005072 // Rebox CustomArguments::kReturnValueOffset before returning.
5073 return handle(*result_internal, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005074 }
5075 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005076 Handle<Object> result =
5077 DeletePropertyPostInterceptor(object, name, NORMAL_DELETION);
5078 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5079 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005080}
5081
5082
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005083// TODO(mstarzinger): Temporary wrapper until handlified.
5084static Handle<Object> AccessorDelete(Handle<JSObject> object,
5085 uint32_t index,
5086 JSObject::DeleteMode mode) {
5087 CALL_HEAP_FUNCTION(object->GetIsolate(),
5088 object->GetElementsAccessor()->Delete(*object,
5089 index,
5090 mode),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005091 Object);
5092}
5093
5094
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005095Handle<Object> JSObject::DeleteElementWithInterceptor(Handle<JSObject> object,
5096 uint32_t index) {
5097 Isolate* isolate = object->GetIsolate();
5098 Factory* factory = isolate->factory();
5099
5100 // Make sure that the top context does not change when doing
5101 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005102 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005103
5104 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
5105 if (interceptor->deleter()->IsUndefined()) return factory->false_value();
5106 v8::IndexedPropertyDeleterCallback deleter =
5107 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5108 LOG(isolate,
5109 ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
5110 PropertyCallbackArguments args(
5111 isolate, interceptor->data(), *object, *object);
5112 v8::Handle<v8::Boolean> result = args.Call(deleter, index);
5113 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5114 if (!result.IsEmpty()) {
5115 ASSERT(result->IsBoolean());
5116 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5117 result_internal->VerifyApiCallResultType();
5118 // Rebox CustomArguments::kReturnValueOffset before returning.
5119 return handle(*result_internal, isolate);
5120 }
5121 Handle<Object> delete_result = AccessorDelete(object, index, NORMAL_DELETION);
5122 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5123 return delete_result;
5124}
5125
5126
5127Handle<Object> JSObject::DeleteElement(Handle<JSObject> object,
5128 uint32_t index,
5129 DeleteMode mode) {
5130 Isolate* isolate = object->GetIsolate();
5131 Factory* factory = isolate->factory();
5132
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005133 // Check access rights if needed.
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005134 if (object->IsAccessCheckNeeded() &&
5135 !isolate->MayIndexedAccess(*object, index, v8::ACCESS_DELETE)) {
5136 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_DELETE);
5137 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5138 return factory->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005139 }
5140
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005141 if (object->IsStringObjectWithCharacterAt(index)) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005142 if (mode == STRICT_DELETION) {
5143 // Deleting a non-configurable property in strict mode.
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005144 Handle<Object> name = factory->NewNumberFromUint(index);
5145 Handle<Object> args[2] = { name, object };
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005146 Handle<Object> error =
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005147 factory->NewTypeError("strict_delete_property",
5148 HandleVector(args, 2));
5149 isolate->Throw(*error);
5150 return Handle<Object>();
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005151 }
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005152 return factory->false_value();
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005153 }
5154
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005155 if (object->IsJSGlobalProxy()) {
5156 Handle<Object> proto(object->GetPrototype(), isolate);
5157 if (proto->IsNull()) return factory->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005158 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005159 return DeleteElement(Handle<JSObject>::cast(proto), index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005160 }
5161
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005162 Handle<Object> old_value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005163 bool should_enqueue_change_record = false;
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005164 if (FLAG_harmony_observation && object->map()->is_observed()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005165 should_enqueue_change_record = HasLocalElement(object, index);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005166 if (should_enqueue_change_record) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005167 old_value = object->GetLocalElementAccessorPair(index) != NULL
5168 ? Handle<Object>::cast(factory->the_hole_value())
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00005169 : Object::GetElement(isolate, object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005171 }
5172
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005173 // Skip interceptor if forcing deletion.
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005174 Handle<Object> result;
5175 if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
5176 result = DeleteElementWithInterceptor(object, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005177 } else {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005178 result = AccessorDelete(object, index, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005179 }
5180
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005181 if (should_enqueue_change_record && !HasLocalElement(object, index)) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005182 Handle<String> name = factory->Uint32ToString(index);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005183 EnqueueChangeRecord(object, "delete", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005184 }
5185
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005186 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187}
5188
5189
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005190Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
5191 Handle<Name> name,
5192 DeleteMode mode) {
5193 Isolate* isolate = object->GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005194 // ECMA-262, 3rd, 8.6.2.5
ulan@chromium.org750145a2013-03-07 15:14:13 +00005195 ASSERT(name->IsName());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197 // Check access rights if needed.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005198 if (object->IsAccessCheckNeeded() &&
5199 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_DELETE)) {
5200 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_DELETE);
5201 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5202 return isolate->factory()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005203 }
5204
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005205 if (object->IsJSGlobalProxy()) {
5206 Object* proto = object->GetPrototype();
5207 if (proto->IsNull()) return isolate->factory()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005208 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005209 return JSGlobalObject::DeleteProperty(
5210 handle(JSGlobalObject::cast(proto)), name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005212
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005213 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 if (name->AsArrayIndex(&index)) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005215 return DeleteElement(object, index, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005216 }
5217
5218 LookupResult lookup(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005219 object->LocalLookup(*name, &lookup, true);
5220 if (!lookup.IsFound()) return isolate->factory()->true_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005221 // Ignore attributes if forcing a deletion.
5222 if (lookup.IsDontDelete() && mode != FORCE_DELETION) {
5223 if (mode == STRICT_DELETION) {
5224 // Deleting a non-configurable property in strict mode.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005225 Handle<Object> args[2] = { name, object };
5226 Handle<Object> error = isolate->factory()->NewTypeError(
5227 "strict_delete_property", HandleVector(args, ARRAY_SIZE(args)));
5228 isolate->Throw(*error);
5229 return Handle<Object>();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005230 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005231 return isolate->factory()->false_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005232 }
5233
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005234 Handle<Object> old_value = isolate->factory()->the_hole_value();
mstarzinger@chromium.org69008382013-10-18 10:34:25 +00005235 bool is_observed = FLAG_harmony_observation &&
5236 object->map()->is_observed() &&
5237 *name != isolate->heap()->hidden_string();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005238 if (is_observed && lookup.IsDataProperty()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005239 old_value = Object::GetProperty(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005240 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005241 Handle<Object> result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005242
5243 // Check for interceptor.
5244 if (lookup.IsInterceptor()) {
5245 // Skip interceptor if forcing a deletion.
5246 if (mode == FORCE_DELETION) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005247 result = DeletePropertyPostInterceptor(object, name, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005248 } else {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005249 result = DeletePropertyWithInterceptor(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005250 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005251 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005252 // Normalize object if needed.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005253 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005254 // Make sure the properties are normalized before removing the entry.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005255 result = DeleteNormalizedProperty(object, name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005256 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005257
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005258 if (is_observed && !HasLocalProperty(object, name)) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00005259 EnqueueChangeRecord(object, "delete", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005260 }
5261
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005262 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263}
5264
5265
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005266Handle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
5267 uint32_t index,
5268 DeleteMode mode) {
5269 if (object->IsJSProxy()) {
5270 return JSProxy::DeleteElementWithHandler(
5271 Handle<JSProxy>::cast(object), index, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005272 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005273 return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005274}
5275
5276
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005277Handle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
5278 Handle<Name> name,
5279 DeleteMode mode) {
5280 if (object->IsJSProxy()) {
5281 return JSProxy::DeletePropertyWithHandler(
5282 Handle<JSProxy>::cast(object), name, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005283 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005284 return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005285}
5286
5287
whesse@chromium.org7b260152011-06-20 15:33:18 +00005288bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5289 ElementsKind kind,
5290 Object* object) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005291 ASSERT(IsFastObjectElementsKind(kind) ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005292 kind == DICTIONARY_ELEMENTS);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005293 if (IsFastObjectElementsKind(kind)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005294 int length = IsJSArray()
5295 ? Smi::cast(JSArray::cast(this)->length())->value()
5296 : elements->length();
5297 for (int i = 0; i < length; ++i) {
5298 Object* element = elements->get(i);
5299 if (!element->IsTheHole() && element == object) return true;
5300 }
5301 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005302 Object* key =
5303 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00005304 if (!key->IsUndefined()) return true;
5305 }
5306 return false;
5307}
5308
5309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005310// Check whether this object references another object.
5311bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005312 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005313 Heap* heap = GetHeap();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005314 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315
5316 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005317 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005318 return true;
5319 }
5320
5321 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005322 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005323 return true;
5324 }
5325
5326 // Check if the object is among the named properties.
5327 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005328 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005329 return true;
5330 }
5331
5332 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00005333 ElementsKind kind = GetElementsKind();
5334 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005335 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00005336 case EXTERNAL_BYTE_ELEMENTS:
5337 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5338 case EXTERNAL_SHORT_ELEMENTS:
5339 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5340 case EXTERNAL_INT_ELEMENTS:
5341 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5342 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005343 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00005344 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005345 case FAST_HOLEY_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00005346 // Raw pixels and external arrays do not reference other
5347 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005348 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005349 case FAST_SMI_ELEMENTS:
5350 case FAST_HOLEY_SMI_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005351 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005352 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005353 case FAST_HOLEY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005354 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005355 FixedArray* elements = FixedArray::cast(this->elements());
5356 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005357 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005358 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00005359 case NON_STRICT_ARGUMENTS_ELEMENTS: {
5360 FixedArray* parameter_map = FixedArray::cast(elements());
5361 // Check the mapped parameters.
5362 int length = parameter_map->length();
5363 for (int i = 2; i < length; ++i) {
5364 Object* value = parameter_map->get(i);
5365 if (!value->IsTheHole() && value == obj) return true;
5366 }
5367 // Check the arguments.
5368 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005369 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5370 FAST_HOLEY_ELEMENTS;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005371 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005372 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005374 }
5375
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005376 // For functions check the context.
5377 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005378 // Get the constructor function for arguments array.
5379 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005380 heap->isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005381 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382 JSFunction* arguments_function =
5383 JSFunction::cast(arguments_boilerplate->map()->constructor());
5384
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005385 // Get the context and don't check if it is the native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386 JSFunction* f = JSFunction::cast(this);
5387 Context* context = f->context();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005388 if (context->IsNativeContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389 return false;
5390 }
5391
5392 // Check the non-special context slots.
5393 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5394 // Only check JS objects.
5395 if (context->get(i)->IsJSObject()) {
5396 JSObject* ctxobj = JSObject::cast(context->get(i));
5397 // If it is an arguments array check the content.
5398 if (ctxobj->map()->constructor() == arguments_function) {
5399 if (ctxobj->ReferencesObject(obj)) {
5400 return true;
5401 }
5402 } else if (ctxobj == obj) {
5403 return true;
5404 }
5405 }
5406 }
5407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005408 // Check the context extension (if any) if it can have references.
5409 if (context->has_extension() && !context->IsCatchContext()) {
5410 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 }
5412 }
5413
5414 // No references to object.
5415 return false;
5416}
5417
5418
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005419Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005420 Isolate* isolate = object->GetIsolate();
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005421
5422 if (!object->map()->is_extensible()) return object;
5423
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005424 if (object->IsAccessCheckNeeded() &&
5425 !isolate->MayNamedAccess(*object,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005426 isolate->heap()->undefined_value(),
5427 v8::ACCESS_KEYS)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005428 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5429 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5430 return isolate->factory()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005431 }
5432
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005433 if (object->IsJSGlobalProxy()) {
5434 Handle<Object> proto(object->GetPrototype(), isolate);
5435 if (proto->IsNull()) return object;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005436 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005437 return PreventExtensions(Handle<JSObject>::cast(proto));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005438 }
5439
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005440 // It's not possible to seal objects with external array elements
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005441 if (object->HasExternalArrayElements()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005442 Handle<Object> error =
5443 isolate->factory()->NewTypeError(
5444 "cant_prevent_ext_external_array_elements",
5445 HandleVector(&object, 1));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005446 isolate->Throw(*error);
5447 return Handle<Object>();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005448 }
5449
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005450 // If there are fast elements we normalize.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005451 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
5452 ASSERT(object->HasDictionaryElements() ||
5453 object->HasDictionaryArgumentsElements());
5454
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005455 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005456 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005457
5458 // Do a map transition, other objects with this map may still
5459 // be extensible.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005460 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005461 Handle<Map> new_map = Map::Copy(handle(object->map()));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005462
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005463 new_map->set_is_extensible(false);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005464 object->set_map(*new_map);
5465 ASSERT(!object->map()->is_extensible());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005466
5467 if (FLAG_harmony_observation && object->map()->is_observed()) {
5468 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
5469 isolate->factory()->the_hole_value());
5470 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005471 return object;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005472}
5473
5474
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005475template<typename Dictionary>
5476static void FreezeDictionary(Dictionary* dictionary) {
5477 int capacity = dictionary->Capacity();
5478 for (int i = 0; i < capacity; i++) {
5479 Object* k = dictionary->KeyAt(i);
5480 if (dictionary->IsKey(k)) {
5481 PropertyDetails details = dictionary->DetailsAt(i);
5482 int attrs = DONT_DELETE;
5483 // READ_ONLY is an invalid attribute for JS setters/getters.
5484 if (details.type() != CALLBACKS ||
5485 !dictionary->ValueAt(i)->IsAccessorPair()) {
5486 attrs |= READ_ONLY;
5487 }
5488 details = details.CopyAddAttributes(
5489 static_cast<PropertyAttributes>(attrs));
5490 dictionary->DetailsAtPut(i, details);
5491 }
5492 }
5493}
5494
5495
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005496Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005497 // Freezing non-strict arguments should be handled elsewhere.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005498 ASSERT(!object->HasNonStrictArgumentsElements());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005499 ASSERT(!object->map()->is_observed());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005500
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005501 if (object->map()->is_frozen()) return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005502
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005503 Isolate* isolate = object->GetIsolate();
5504 if (object->IsAccessCheckNeeded() &&
5505 !isolate->MayNamedAccess(*object,
5506 isolate->heap()->undefined_value(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005507 v8::ACCESS_KEYS)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005508 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5509 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5510 return isolate->factory()->false_value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005511 }
5512
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005513 if (object->IsJSGlobalProxy()) {
5514 Handle<Object> proto(object->GetPrototype(), isolate);
5515 if (proto->IsNull()) return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005516 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005517 return Freeze(Handle<JSObject>::cast(proto));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005518 }
5519
5520 // It's not possible to freeze objects with external array elements
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005521 if (object->HasExternalArrayElements()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005522 Handle<Object> error =
5523 isolate->factory()->NewTypeError(
5524 "cant_prevent_ext_external_array_elements",
5525 HandleVector(&object, 1));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005526 isolate->Throw(*error);
5527 return Handle<Object>();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005528 }
5529
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005530 Handle<SeededNumberDictionary> new_element_dictionary;
5531 if (!object->elements()->IsDictionary()) {
5532 int length = object->IsJSArray()
5533 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5534 : object->elements()->length();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005535 if (length > 0) {
5536 int capacity = 0;
5537 int used = 0;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005538 object->GetElementsCapacityAndUsage(&capacity, &used);
5539 new_element_dictionary =
5540 isolate->factory()->NewSeededNumberDictionary(used);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005541
5542 // Move elements to a dictionary; avoid calling NormalizeElements to avoid
5543 // unnecessary transitions.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005544 new_element_dictionary = CopyFastElementsToDictionary(
5545 handle(object->elements()), length, new_element_dictionary);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005546 } else {
5547 // No existing elements, use a pre-allocated empty backing store
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005548 new_element_dictionary =
5549 isolate->factory()->empty_slow_element_dictionary();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005550 }
5551 }
5552
5553 LookupResult result(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005554 Handle<Map> old_map(object->map());
5555 old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005556 if (result.IsTransition()) {
5557 Map* transition_map = result.GetTransitionTarget();
5558 ASSERT(transition_map->has_dictionary_elements());
5559 ASSERT(transition_map->is_frozen());
5560 ASSERT(!transition_map->is_extensible());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005561 object->set_map(transition_map);
5562 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005563 // Create a new descriptor array with fully-frozen properties
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005564 int num_descriptors = old_map->NumberOfOwnDescriptors();
5565 Handle<DescriptorArray> new_descriptors =
5566 DescriptorArray::CopyUpToAddAttributes(
5567 handle(old_map->instance_descriptors()), num_descriptors, FROZEN);
5568 Handle<Map> new_map = Map::CopyReplaceDescriptors(
5569 old_map, new_descriptors, INSERT_TRANSITION,
5570 isolate->factory()->frozen_symbol());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005571 new_map->freeze();
5572 new_map->set_is_extensible(false);
5573 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005574 object->set_map(*new_map);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005575 } else {
5576 // Slow path: need to normalize properties for safety
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005577 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005578
5579 // Create a new map, since other objects with this map may be extensible.
5580 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005581 Handle<Map> new_map = Map::Copy(handle(object->map()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005582 new_map->freeze();
5583 new_map->set_is_extensible(false);
5584 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005585 object->set_map(*new_map);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005586
5587 // Freeze dictionary-mode properties
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005588 FreezeDictionary(object->property_dictionary());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005589 }
5590
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005591 ASSERT(object->map()->has_dictionary_elements());
5592 if (!new_element_dictionary.is_null()) {
5593 object->set_elements(*new_element_dictionary);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005594 }
5595
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005596 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
5597 SeededNumberDictionary* dictionary = object->element_dictionary();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005598 // Make sure we never go back to the fast case
5599 dictionary->set_requires_slow_elements();
5600 // Freeze all elements in the dictionary
5601 FreezeDictionary(dictionary);
5602 }
5603
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005604 return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005605}
5606
5607
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005608void JSObject::SetObserved(Handle<JSObject> object) {
5609 Isolate* isolate = object->GetIsolate();
danno@chromium.org169691d2013-07-15 08:01:13 +00005610
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005611 if (object->map()->is_observed())
5612 return;
danno@chromium.org169691d2013-07-15 08:01:13 +00005613
danno@chromium.org169691d2013-07-15 08:01:13 +00005614 LookupResult result(isolate);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005615 object->map()->LookupTransition(*object,
5616 isolate->heap()->observed_symbol(),
5617 &result);
danno@chromium.org169691d2013-07-15 08:01:13 +00005618
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005619 Handle<Map> new_map;
danno@chromium.org169691d2013-07-15 08:01:13 +00005620 if (result.IsTransition()) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005621 new_map = handle(result.GetTransitionTarget());
danno@chromium.org169691d2013-07-15 08:01:13 +00005622 ASSERT(new_map->is_observed());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005623 } else if (object->map()->CanHaveMoreTransitions()) {
5624 new_map = Map::CopyForObserved(handle(object->map()));
danno@chromium.org169691d2013-07-15 08:01:13 +00005625 } else {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005626 new_map = Map::Copy(handle(object->map()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00005627 new_map->set_is_observed();
danno@chromium.org169691d2013-07-15 08:01:13 +00005628 }
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005629 object->set_map(*new_map);
5630}
danno@chromium.org169691d2013-07-15 08:01:13 +00005631
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005632
5633Handle<JSObject> JSObject::Copy(Handle<JSObject> object,
5634 Handle<AllocationSite> site) {
5635 Isolate* isolate = object->GetIsolate();
5636 CALL_HEAP_FUNCTION(isolate,
5637 isolate->heap()->CopyJSObject(*object, *site), JSObject);
danno@chromium.org169691d2013-07-15 08:01:13 +00005638}
5639
5640
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005641Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
5642 Isolate* isolate = object->GetIsolate();
5643 CALL_HEAP_FUNCTION(isolate,
5644 isolate->heap()->CopyJSObject(*object), JSObject);
5645}
5646
5647
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005648class JSObjectWalkVisitor {
5649 public:
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005650 explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
5651 site_context_(site_context) {}
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005652 virtual ~JSObjectWalkVisitor() {}
5653
5654 Handle<JSObject> Visit(Handle<JSObject> object) {
5655 return StructureWalk(object);
5656 }
5657
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005658 virtual bool is_copying() = 0;
5659
5660 protected:
5661 Handle<JSObject> StructureWalk(Handle<JSObject> object);
5662
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005663 // The returned handle will be used for the object in all subsequent usages.
5664 // This allows VisitObject to make a copy of the object if desired.
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005665 virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005666 virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
5667 Handle<JSObject> value) = 0;
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005668
5669 AllocationSiteContext* site_context() { return site_context_; }
5670
5671 private:
5672 AllocationSiteContext* site_context_;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005673};
5674
5675
5676class JSObjectCopyVisitor: public JSObjectWalkVisitor {
5677 public:
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005678 explicit JSObjectCopyVisitor(AllocationSiteContext* site_context)
5679 : JSObjectWalkVisitor(site_context) {}
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005680
5681 virtual bool is_copying() V8_OVERRIDE { return true; }
5682
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005683 // The returned handle will be used for the object in all
5684 // subsequent usages. This allows VisitObject to make a copy
5685 // of the object if desired.
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005686 virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005687 // Only create a memento if
5688 // 1) we have a JSArray, and
5689 // 2) the elements kind is palatable
5690 // 3) allow_mementos is true
5691 Handle<JSObject> copy;
5692 if (site_context()->activated() &&
5693 AllocationSite::CanTrack(object->map()->instance_type()) &&
5694 AllocationSite::GetMode(object->GetElementsKind()) ==
5695 TRACK_ALLOCATION_SITE) {
5696 copy = JSObject::Copy(object, site_context()->current());
5697 } else {
5698 copy = JSObject::Copy(object);
5699 }
5700
5701 return copy;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005702 }
5703
5704 virtual Handle<JSObject> VisitElementOrProperty(
5705 Handle<JSObject> object,
5706 Handle<JSObject> value) V8_OVERRIDE {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005707 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5708 Handle<JSObject> copy_of_value = StructureWalk(value);
5709 site_context()->ExitScope(current_site, value);
5710 return copy_of_value;
5711 }
5712};
5713
5714
5715class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor {
5716 public:
5717 explicit JSObjectCreateAllocationSitesVisitor(
5718 AllocationSiteContext* site_context)
5719 : JSObjectWalkVisitor(site_context) {}
5720
5721 virtual bool is_copying() V8_OVERRIDE { return false; }
5722
5723 // The returned handle will be used for the object in all
5724 // subsequent usages. This allows VisitObject to make a copy
5725 // of the object if desired.
5726 virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
5727 return object;
5728 }
5729
5730 virtual Handle<JSObject> VisitElementOrProperty(
5731 Handle<JSObject> object,
5732 Handle<JSObject> value) V8_OVERRIDE {
5733 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5734 value = StructureWalk(value);
5735 site_context()->ExitScope(current_site, value);
5736 return value;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005737 }
5738};
5739
5740
5741Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
5742 bool copying = is_copying();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005743 Isolate* isolate = object->GetIsolate();
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00005744 StackLimitCheck check(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005745 if (check.HasOverflowed()) {
5746 isolate->StackOverflow();
5747 return Handle<JSObject>::null();
mvstanton@chromium.org5a4733b2013-09-16 07:33:24 +00005748 }
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00005749
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005750 if (object->map()->is_deprecated()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005751 JSObject::MigrateInstance(object);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00005752 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005753
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005754 Handle<JSObject> copy = VisitObject(object);
5755 ASSERT(copying || copy.is_identical_to(object));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005756
5757 HandleScope scope(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005758
5759 // Deep copy local properties.
5760 if (copy->HasFastProperties()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005761 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005762 int limit = copy->map()->NumberOfOwnDescriptors();
5763 for (int i = 0; i < limit; i++) {
5764 PropertyDetails details = descriptors->GetDetails(i);
5765 if (details.type() != FIELD) continue;
5766 int index = descriptors->GetFieldIndex(i);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005767 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005768 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005769 value = VisitElementOrProperty(copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005770 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005771 } else {
5772 Representation representation = details.representation();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005773 value = NewStorageFor(isolate, value, representation);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005774 }
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005775 if (copying) {
5776 copy->FastPropertyAtPut(index, *value);
5777 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005778 }
5779 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005780 Handle<FixedArray> names =
5781 isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties());
5782 copy->GetLocalPropertyNames(*names, 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005783 for (int i = 0; i < names->length(); i++) {
5784 ASSERT(names->get(i)->IsString());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005785 Handle<String> key_string(String::cast(names->get(i)));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005786 PropertyAttributes attributes =
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005787 copy->GetLocalPropertyAttribute(*key_string);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005788 // Only deep copy fields from the object literal expression.
5789 // In particular, don't try to copy the length attribute of
5790 // an array.
5791 if (attributes != NONE) continue;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005792 Handle<Object> value(
5793 copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
5794 isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005795 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005796 Handle<JSObject> result = VisitElementOrProperty(
5797 copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005798 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005799 if (copying) {
5800 // Creating object copy for literals. No strict mode needed.
5801 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
5802 copy, key_string, result, NONE, kNonStrictMode));
5803 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005804 }
5805 }
5806 }
5807
5808 // Deep copy local elements.
5809 // Pixel elements cannot be created using an object literal.
5810 ASSERT(!copy->HasExternalArrayElements());
5811 switch (copy->GetElementsKind()) {
5812 case FAST_SMI_ELEMENTS:
5813 case FAST_ELEMENTS:
5814 case FAST_HOLEY_SMI_ELEMENTS:
5815 case FAST_HOLEY_ELEMENTS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005816 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
5817 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00005818 if (copying) {
5819 isolate->counters()->cow_arrays_created_runtime()->Increment();
5820 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005821#ifdef DEBUG
5822 for (int i = 0; i < elements->length(); i++) {
5823 ASSERT(!elements->get(i)->IsJSObject());
5824 }
5825#endif
5826 } else {
5827 for (int i = 0; i < elements->length(); i++) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005828 Handle<Object> value(elements->get(i), isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005829 ASSERT(value->IsSmi() ||
5830 value->IsTheHole() ||
5831 (IsFastObjectElementsKind(copy->GetElementsKind())));
5832 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005833 Handle<JSObject> result = VisitElementOrProperty(
5834 copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005835 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005836 if (copying) {
5837 elements->set(i, *result);
5838 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005839 }
5840 }
5841 }
5842 break;
5843 }
5844 case DICTIONARY_ELEMENTS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005845 Handle<SeededNumberDictionary> element_dictionary(
5846 copy->element_dictionary());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005847 int capacity = element_dictionary->Capacity();
5848 for (int i = 0; i < capacity; i++) {
5849 Object* k = element_dictionary->KeyAt(i);
5850 if (element_dictionary->IsKey(k)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005851 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005852 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005853 Handle<JSObject> result = VisitElementOrProperty(
5854 copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005855 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005856 if (copying) {
5857 element_dictionary->ValueAtPut(i, *result);
5858 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005859 }
5860 }
5861 }
5862 break;
5863 }
5864 case NON_STRICT_ARGUMENTS_ELEMENTS:
5865 UNIMPLEMENTED();
5866 break;
5867 case EXTERNAL_PIXEL_ELEMENTS:
5868 case EXTERNAL_BYTE_ELEMENTS:
5869 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5870 case EXTERNAL_SHORT_ELEMENTS:
5871 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5872 case EXTERNAL_INT_ELEMENTS:
5873 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5874 case EXTERNAL_FLOAT_ELEMENTS:
5875 case EXTERNAL_DOUBLE_ELEMENTS:
5876 case FAST_DOUBLE_ELEMENTS:
5877 case FAST_HOLEY_DOUBLE_ELEMENTS:
5878 // No contained objects, nothing to do.
5879 break;
5880 }
5881 return copy;
5882}
5883
5884
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005885Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object,
5886 AllocationSiteContext* site_context) {
5887 JSObjectCreateAllocationSitesVisitor v(site_context);
5888 Handle<JSObject> result = v.Visit(object);
5889 ASSERT(!v.is_copying() &&
5890 (result.is_null() || result.is_identical_to(object)));
5891 return result;
5892}
5893
5894
5895Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object,
5896 AllocationSiteContext* site_context) {
5897 JSObjectCopyVisitor v(site_context);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005898 Handle<JSObject> copy = v.Visit(object);
5899 ASSERT(v.is_copying() && !copy.is_identical_to(object));
5900 return copy;
5901}
5902
5903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904// Tests for the fast common case for property enumeration:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005905// - This object and all prototypes has an enum cache (which means that
5906// it is no proxy, has no interceptors and needs no access checks).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005907// - This object has no elements.
5908// - No prototype has enumerable properties/elements.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005909bool JSReceiver::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005912 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913 o = JSObject::cast(o)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005914 if (!o->IsJSObject()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915 JSObject* curr = JSObject::cast(o);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005916 int enum_length = curr->map()->EnumLength();
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00005917 if (enum_length == kInvalidEnumCacheSentinel) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005918 ASSERT(!curr->HasNamedInterceptor());
5919 ASSERT(!curr->HasIndexedInterceptor());
5920 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 if (curr->NumberOfEnumElements() > 0) return false;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005922 if (curr != this && enum_length != 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005923 }
5924 return true;
5925}
5926
5927
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005928int Map::NumberOfDescribedProperties(DescriptorFlag which,
5929 PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005931 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005932 int limit = which == ALL_DESCRIPTORS
5933 ? descs->number_of_descriptors()
5934 : NumberOfOwnDescriptors();
5935 for (int i = 0; i < limit; i++) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005936 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
5937 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
5938 result++;
5939 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 }
5941 return result;
5942}
5943
5944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005945int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005946 int max_index = -1;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005947 int number_of_own_descriptors = NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005948 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005949 for (int i = 0; i < number_of_own_descriptors; i++) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005950 if (descs->GetType(i) == FIELD) {
5951 int current_index = descs->GetFieldIndex(i);
5952 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 }
5954 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005955 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005956}
5957
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005958
ulan@chromium.org750145a2013-03-07 15:14:13 +00005959AccessorDescriptor* Map::FindAccessor(Name* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005960 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005961 int number_of_own_descriptors = NumberOfOwnDescriptors();
5962 for (int i = 0; i < number_of_own_descriptors; i++) {
5963 if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005964 return descs->GetCallbacks(i);
5965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005966 }
5967 return NULL;
5968}
5969
5970
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005971void JSReceiver::LocalLookup(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005972 Name* name, LookupResult* result, bool search_hidden_prototypes) {
5973 ASSERT(name->IsName());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005975 Heap* heap = GetHeap();
5976
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005977 if (IsJSGlobalProxy()) {
5978 Object* proto = GetPrototype();
5979 if (proto->IsNull()) return result->NotFound();
5980 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005981 return JSReceiver::cast(proto)->LocalLookup(
5982 name, result, search_hidden_prototypes);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005983 }
5984
5985 if (IsJSProxy()) {
5986 result->HandlerResult(JSProxy::cast(this));
5987 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005988 }
5989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005990 // Do not use inline caching if the object is a non-global object
5991 // that requires access checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005992 if (IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993 result->DisallowCaching();
5994 }
5995
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005996 JSObject* js_object = JSObject::cast(this);
5997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 // Check for lookup interceptor except when bootstrapping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005999 if (js_object->HasNamedInterceptor() &&
6000 !heap->isolate()->bootstrapper()->IsActive()) {
6001 result->InterceptorResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006002 return;
6003 }
6004
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006005 js_object->LocalLookupRealNamedProperty(name, result);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006006 if (result->IsFound() || !search_hidden_prototypes) return;
6007
6008 Object* proto = js_object->GetPrototype();
6009 if (!proto->IsJSReceiver()) return;
6010 JSReceiver* receiver = JSReceiver::cast(proto);
6011 if (receiver->map()->is_hidden_prototype()) {
6012 receiver->LocalLookup(name, result, search_hidden_prototypes);
6013 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006014}
6015
6016
ulan@chromium.org750145a2013-03-07 15:14:13 +00006017void JSReceiver::Lookup(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006018 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006019 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 current = JSObject::cast(current)->GetPrototype()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006023 JSReceiver::cast(current)->LocalLookup(name, result, false);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006024 if (result->IsFound()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006025 }
6026 result->NotFound();
6027}
6028
6029
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006030// Search object and its prototype chain for callback properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006031void JSObject::LookupCallbackProperty(Name* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006032 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006033 for (Object* current = this;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006034 current != heap->null_value() && current->IsJSObject();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006035 current = JSObject::cast(current)->GetPrototype()) {
6036 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006037 if (result->IsPropertyCallbacks()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006038 }
6039 result->NotFound();
6040}
6041
6042
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006043// Try to update an accessor in an elements dictionary. Return true if the
6044// update succeeded, and false otherwise.
6045static bool UpdateGetterSetterInDictionary(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006046 SeededNumberDictionary* dictionary,
6047 uint32_t index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00006048 Object* getter,
6049 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006050 PropertyAttributes attributes) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00006051 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006052 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00006053 Object* result = dictionary->ValueAt(entry);
6054 PropertyDetails details = dictionary->DetailsAt(entry);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006055 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00006056 ASSERT(!details.IsDontDelete());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006057 if (details.attributes() != attributes) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00006058 dictionary->DetailsAtPut(
6059 entry,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006060 PropertyDetails(attributes, CALLBACKS, index));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006061 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00006062 AccessorPair::cast(result)->SetComponents(getter, setter);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006063 return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006064 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00006065 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006066 return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006067}
6068
6069
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006070void JSObject::DefineElementAccessor(Handle<JSObject> object,
6071 uint32_t index,
6072 Handle<Object> getter,
6073 Handle<Object> setter,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006074 PropertyAttributes attributes,
6075 v8::AccessControl access_control) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006076 switch (object->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006077 case FAST_SMI_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006078 case FAST_ELEMENTS:
6079 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006080 case FAST_HOLEY_SMI_ELEMENTS:
6081 case FAST_HOLEY_ELEMENTS:
6082 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006083 break;
6084 case EXTERNAL_PIXEL_ELEMENTS:
6085 case EXTERNAL_BYTE_ELEMENTS:
6086 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6087 case EXTERNAL_SHORT_ELEMENTS:
6088 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6089 case EXTERNAL_INT_ELEMENTS:
6090 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6091 case EXTERNAL_FLOAT_ELEMENTS:
6092 case EXTERNAL_DOUBLE_ELEMENTS:
6093 // Ignore getters and setters on pixel and external array elements.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006094 return;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006095 case DICTIONARY_ELEMENTS:
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006096 if (UpdateGetterSetterInDictionary(object->element_dictionary(),
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006097 index,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006098 *getter,
6099 *setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006100 attributes)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006101 return;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006102 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006103 break;
6104 case NON_STRICT_ARGUMENTS_ELEMENTS: {
6105 // Ascertain whether we have read-only properties or an existing
6106 // getter/setter pair in an arguments elements dictionary backing
6107 // store.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006108 FixedArray* parameter_map = FixedArray::cast(object->elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006109 uint32_t length = parameter_map->length();
6110 Object* probe =
6111 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
6112 if (probe == NULL || probe->IsTheHole()) {
6113 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
6114 if (arguments->IsDictionary()) {
6115 SeededNumberDictionary* dictionary =
6116 SeededNumberDictionary::cast(arguments);
6117 if (UpdateGetterSetterInDictionary(dictionary,
6118 index,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006119 *getter,
6120 *setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006121 attributes)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006122 return;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006123 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006124 }
6125 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006126 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006127 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006128 }
6129
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006130 Isolate* isolate = object->GetIsolate();
6131 Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
6132 accessors->SetComponents(*getter, *setter);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006133 accessors->set_access_flags(access_control);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006134
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006135 SetElementCallback(object, index, accessors, attributes);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006136}
6137
6138
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006139Handle<AccessorPair> JSObject::CreateAccessorPairFor(Handle<JSObject> object,
6140 Handle<Name> name) {
6141 Isolate* isolate = object->GetIsolate();
6142 LookupResult result(isolate);
6143 object->LocalLookupRealNamedProperty(*name, &result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006144 if (result.IsPropertyCallbacks()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006145 // Note that the result can actually have IsDontDelete() == true when we
6146 // e.g. have to fall back to the slow case while adding a setter after
6147 // successfully reusing a map transition for a getter. Nevertheless, this is
6148 // OK, because the assertion only holds for the whole addition of both
6149 // accessors, not for the addition of each part. See first comment in
6150 // DefinePropertyAccessor below.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006151 Object* obj = result.GetCallbackObject();
6152 if (obj->IsAccessorPair()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006153 return AccessorPair::Copy(handle(AccessorPair::cast(obj), isolate));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006154 }
6155 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006156 return isolate->factory()->NewAccessorPair();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006157}
6158
6159
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006160void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
6161 Handle<Name> name,
6162 Handle<Object> getter,
6163 Handle<Object> setter,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006164 PropertyAttributes attributes,
6165 v8::AccessControl access_control) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006166 // We could assert that the property is configurable here, but we would need
6167 // to do a lookup, which seems to be a bit of overkill.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006168 bool only_attribute_changes = getter->IsNull() && setter->IsNull();
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006169 if (object->HasFastProperties() && !only_attribute_changes &&
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006170 access_control == v8::DEFAULT &&
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006171 (object->map()->NumberOfOwnDescriptors() <= kMaxNumberOfDescriptors)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006172 bool getterOk = getter->IsNull() ||
6173 DefineFastAccessor(object, name, ACCESSOR_GETTER, getter, attributes);
6174 bool setterOk = !getterOk || setter->IsNull() ||
6175 DefineFastAccessor(object, name, ACCESSOR_SETTER, setter, attributes);
6176 if (getterOk && setterOk) return;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006177 }
6178
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006179 Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
6180 accessors->SetComponents(*getter, *setter);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006181 accessors->set_access_flags(access_control);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006182
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006183 SetPropertyCallback(object, name, accessors, attributes);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006184}
6185
6186
ulan@chromium.org750145a2013-03-07 15:14:13 +00006187bool JSObject::CanSetCallback(Name* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006188 ASSERT(!IsAccessCheckNeeded() ||
6189 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006190
6191 // Check if there is an API defined callback object which prohibits
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006192 // callback overwriting in this object or its prototype chain.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006193 // This mechanism is needed for instance in a browser setting, where
6194 // certain accessors such as window.location should not be allowed
6195 // to be overwritten because allowing overwriting could potentially
6196 // cause security problems.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006197 LookupResult callback_result(GetIsolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006198 LookupCallbackProperty(name, &callback_result);
6199 if (callback_result.IsFound()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006200 Object* obj = callback_result.GetCallbackObject();
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006201 if (obj->IsAccessorInfo()) {
6202 return !AccessorInfo::cast(obj)->prohibits_overwriting();
6203 }
6204 if (obj->IsAccessorPair()) {
6205 return !AccessorPair::cast(obj)->prohibits_overwriting();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006206 }
6207 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006208 return true;
6209}
6210
6211
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006212bool Map::DictionaryElementsInPrototypeChainOnly() {
6213 Heap* heap = GetHeap();
6214
6215 if (IsDictionaryElementsKind(elements_kind())) {
6216 return false;
6217 }
6218
6219 for (Object* prototype = this->prototype();
6220 prototype != heap->null_value();
6221 prototype = prototype->GetPrototype(GetIsolate())) {
6222 if (prototype->IsJSProxy()) {
6223 // Be conservative, don't walk into proxies.
6224 return true;
6225 }
6226
6227 if (IsDictionaryElementsKind(
6228 JSObject::cast(prototype)->map()->elements_kind())) {
6229 return true;
6230 }
6231 }
6232
6233 return false;
6234}
6235
6236
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006237void JSObject::SetElementCallback(Handle<JSObject> object,
6238 uint32_t index,
6239 Handle<Object> structure,
6240 PropertyAttributes attributes) {
6241 Heap* heap = object->GetHeap();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006242 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006243
6244 // Normalize elements to make this operation simple.
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006245 bool had_dictionary_elements = object->HasDictionaryElements();
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006246 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6247 ASSERT(object->HasDictionaryElements() ||
6248 object->HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006249 // Update the dictionary with the new CALLBACKS property.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006250 dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6251 details);
whesse@chromium.org7b260152011-06-20 15:33:18 +00006252 dictionary->set_requires_slow_elements();
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006253
whesse@chromium.org7b260152011-06-20 15:33:18 +00006254 // Update the dictionary backing store on the object.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006255 if (object->elements()->map() == heap->non_strict_arguments_elements_map()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00006256 // Also delete any parameter alias.
6257 //
6258 // TODO(kmillikin): when deleting the last parameter alias we could
6259 // switch to a direct backing store without the parameter map. This
6260 // would allow GC of the context.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006261 FixedArray* parameter_map = FixedArray::cast(object->elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006262 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006263 parameter_map->set(index + 2, heap->the_hole_value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00006264 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006265 parameter_map->set(1, *dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00006266 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006267 object->set_elements(*dictionary);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006268
6269 if (!had_dictionary_elements) {
6270 // KeyedStoreICs (at least the non-generic ones) need a reset.
6271 heap->ClearAllICsByKind(Code::KEYED_STORE_IC);
6272 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00006273 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274}
6275
6276
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006277void JSObject::SetPropertyCallback(Handle<JSObject> object,
6278 Handle<Name> name,
6279 Handle<Object> structure,
6280 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006281 // Normalize object to make this operation simple.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006282 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006283
6284 // For the global object allocate a new map to invalidate the global inline
6285 // caches which have a global property cell reference directly in the code.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006286 if (object->IsGlobalObject()) {
6287 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
erik.corry@gmail.com88767242012-08-08 14:43:45 +00006288 ASSERT(new_map->is_dictionary_map());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006289 object->set_map(*new_map);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006290
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006291 // When running crankshaft, changing the map is not enough. We
6292 // need to deoptimize all functions that rely on this global
6293 // object.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006294 Deoptimizer::DeoptimizeGlobalObject(*object);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006295 }
6296
6297 // Update the dictionary with the new CALLBACKS property.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006298 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006299 SetNormalizedProperty(object, name, structure, details);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006300}
6301
danno@chromium.org88aa0582012-03-23 15:11:57 +00006302
6303void JSObject::DefineAccessor(Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00006304 Handle<Name> name,
danno@chromium.org88aa0582012-03-23 15:11:57 +00006305 Handle<Object> getter,
6306 Handle<Object> setter,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006307 PropertyAttributes attributes,
6308 v8::AccessControl access_control) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006309 Isolate* isolate = object->GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006310 // Check access rights if needed.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006311 if (object->IsAccessCheckNeeded() &&
6312 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
6313 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
6314 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006315 }
6316
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006317 if (object->IsJSGlobalProxy()) {
6318 Handle<Object> proto(object->GetPrototype(), isolate);
6319 if (proto->IsNull()) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006320 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006321 DefineAccessor(Handle<JSObject>::cast(proto),
6322 name,
6323 getter,
6324 setter,
6325 attributes,
6326 access_control);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006327 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006328 }
6329
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006330 // Make sure that the top context does not change when doing callbacks or
6331 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006332 AssertNoContextChange ncc(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006333
6334 // Try to flatten before operating on the string.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006335 if (name->IsString()) String::cast(*name)->TryFlatten();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006336
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006337 if (!object->CanSetCallback(*name)) return;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006338
6339 uint32_t index = 0;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006340 bool is_element = name->AsArrayIndex(&index);
6341
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006342 Handle<Object> old_value = isolate->factory()->the_hole_value();
mstarzinger@chromium.org69008382013-10-18 10:34:25 +00006343 bool is_observed = FLAG_harmony_observation &&
6344 object->map()->is_observed() &&
6345 *name != isolate->heap()->hidden_string();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006346 bool preexists = false;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00006347 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006348 if (is_element) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006349 preexists = HasLocalElement(object, index);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006350 if (preexists && object->GetLocalElementAccessorPair(index) == NULL) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006351 old_value = Object::GetElement(isolate, object, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006352 }
6353 } else {
6354 LookupResult lookup(isolate);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006355 object->LocalLookup(*name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006356 preexists = lookup.IsProperty();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006357 if (preexists && lookup.IsDataProperty()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006358 old_value = Object::GetProperty(object, name);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006359 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006360 }
6361 }
6362
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006363 if (is_element) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006364 DefineElementAccessor(
6365 object, index, getter, setter, attributes, access_control);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006366 } else {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006367 DefinePropertyAccessor(
6368 object, name, getter, setter, attributes, access_control);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006369 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006370
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00006371 if (is_observed) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00006372 const char* type = preexists ? "reconfigure" : "add";
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006373 EnqueueChangeRecord(object, type, name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006374 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006378static bool TryAccessorTransition(JSObject* self,
6379 Map* transitioned_map,
6380 int target_descriptor,
6381 AccessorComponent component,
6382 Object* accessor,
6383 PropertyAttributes attributes) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006384 DescriptorArray* descs = transitioned_map->instance_descriptors();
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006385 PropertyDetails details = descs->GetDetails(target_descriptor);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006386
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006387 // If the transition target was not callbacks, fall back to the slow case.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006388 if (details.type() != CALLBACKS) return false;
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006389 Object* descriptor = descs->GetCallbacksObject(target_descriptor);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006390 if (!descriptor->IsAccessorPair()) return false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006391
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006392 Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006393 PropertyAttributes target_attributes = details.attributes();
6394
6395 // Reuse transition if adding same accessor with same attributes.
6396 if (target_accessor == accessor && target_attributes == attributes) {
6397 self->set_map(transitioned_map);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006398 return true;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006399 }
6400
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006401 // If either not the same accessor, or not the same attributes, fall back to
6402 // the slow case.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006403 return false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006404}
6405
6406
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006407static MaybeObject* CopyInsertDescriptor(Map* map,
6408 Name* name,
6409 AccessorPair* accessors,
6410 PropertyAttributes attributes) {
6411 CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
6412 return map->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
6413}
6414
6415
6416static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
6417 Handle<Name> name,
6418 Handle<AccessorPair> accessors,
6419 PropertyAttributes attributes) {
6420 CALL_HEAP_FUNCTION(map->GetIsolate(),
6421 CopyInsertDescriptor(*map, *name, *accessors, attributes),
6422 Map);
6423}
6424
6425
6426bool JSObject::DefineFastAccessor(Handle<JSObject> object,
6427 Handle<Name> name,
6428 AccessorComponent component,
6429 Handle<Object> accessor,
6430 PropertyAttributes attributes) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006431 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006432 Isolate* isolate = object->GetIsolate();
6433 LookupResult result(isolate);
6434 object->LocalLookup(*name, &result);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006435
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006436 if (result.IsFound() && !result.IsPropertyCallbacks()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006437 return false;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006438 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006439
6440 // Return success if the same accessor with the same attributes already exist.
6441 AccessorPair* source_accessors = NULL;
6442 if (result.IsPropertyCallbacks()) {
6443 Object* callback_value = result.GetCallbackObject();
6444 if (callback_value->IsAccessorPair()) {
6445 source_accessors = AccessorPair::cast(callback_value);
6446 Object* entry = source_accessors->get(component);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006447 if (entry == *accessor && result.GetAttributes() == attributes) {
6448 return true;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006449 }
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006450 } else {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006451 return false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006452 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006453
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006454 int descriptor_number = result.GetDescriptorIndex();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006455
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006456 object->map()->LookupTransition(*object, *name, &result);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006457
6458 if (result.IsFound()) {
6459 Map* target = result.GetTransitionTarget();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006460 ASSERT(target->NumberOfOwnDescriptors() ==
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006461 object->map()->NumberOfOwnDescriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006462 // This works since descriptors are sorted in order of addition.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006463 ASSERT(object->map()->instance_descriptors()->
6464 GetKey(descriptor_number) == *name);
6465 return TryAccessorTransition(*object, target, descriptor_number,
6466 component, *accessor, attributes);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006467 }
6468 } else {
6469 // If not, lookup a transition.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006470 object->map()->LookupTransition(*object, *name, &result);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006471
6472 // If there is a transition, try to follow it.
6473 if (result.IsFound()) {
6474 Map* target = result.GetTransitionTarget();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006475 int descriptor_number = target->LastAdded();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006476 ASSERT(target->instance_descriptors()->GetKey(descriptor_number)
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006477 ->Equals(*name));
6478 return TryAccessorTransition(*object, target, descriptor_number,
6479 component, *accessor, attributes);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006480 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006481 }
6482
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006483 // If there is no transition yet, add a transition to the a new accessor pair
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006484 // containing the accessor. Allocate a new pair if there were no source
6485 // accessors. Otherwise, copy the pair and modify the accessor.
6486 Handle<AccessorPair> accessors = source_accessors != NULL
6487 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
6488 : isolate->factory()->NewAccessorPair();
6489 accessors->set(component, *accessor);
6490 Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()),
6491 name, accessors, attributes);
6492 object->set_map(*new_map);
6493 return true;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006494}
6495
6496
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006497Handle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6498 Handle<AccessorInfo> info) {
6499 Isolate* isolate = object->GetIsolate();
6500 Factory* factory = isolate->factory();
6501 Handle<Name> name(Name::cast(info->name()));
6502
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006503 // Check access rights if needed.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006504 if (object->IsAccessCheckNeeded() &&
6505 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
6506 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
6507 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
6508 return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006509 }
6510
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006511 if (object->IsJSGlobalProxy()) {
6512 Handle<Object> proto(object->GetPrototype(), isolate);
6513 if (proto->IsNull()) return object;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006514 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006515 return SetAccessor(Handle<JSObject>::cast(proto), info);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006516 }
6517
6518 // Make sure that the top context does not change when doing callbacks or
6519 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006520 AssertNoContextChange ncc(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006521
6522 // Try to flatten before operating on the string.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006523 if (name->IsString()) FlattenString(Handle<String>::cast(name));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006524
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006525 if (!object->CanSetCallback(*name)) return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006526
6527 uint32_t index = 0;
6528 bool is_element = name->AsArrayIndex(&index);
6529
6530 if (is_element) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006531 if (object->IsJSArray()) return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006532
6533 // Accessors overwrite previous callbacks (cf. with getters/setters).
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006534 switch (object->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006535 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006536 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00006537 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006538 case FAST_HOLEY_SMI_ELEMENTS:
6539 case FAST_HOLEY_ELEMENTS:
6540 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006541 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006542 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006543 case EXTERNAL_BYTE_ELEMENTS:
6544 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6545 case EXTERNAL_SHORT_ELEMENTS:
6546 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6547 case EXTERNAL_INT_ELEMENTS:
6548 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6549 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006550 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006551 // Ignore getters and setters on pixel and external array
6552 // elements.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006553 return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006554 case DICTIONARY_ELEMENTS:
6555 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006556 case NON_STRICT_ARGUMENTS_ELEMENTS:
6557 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006558 break;
6559 }
6560
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006561 SetElementCallback(object, index, info, info->property_attributes());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006562 } else {
6563 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006564 LookupResult result(isolate);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006565 object->LocalLookup(*name, &result, true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006566 // ES5 forbids turning a property into an accessor if it's not
6567 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006568 if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006569 return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006570 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006571
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006572 SetPropertyCallback(object, name, info, info->property_attributes());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006573 }
6574
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006575 return object;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006576}
6577
6578
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006579Handle<Object> JSObject::GetAccessor(Handle<JSObject> object,
6580 Handle<Name> name,
6581 AccessorComponent component) {
6582 Isolate* isolate = object->GetIsolate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006583
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006584 // Make sure that the top context does not change when doing callbacks or
6585 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006586 AssertNoContextChange ncc(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587
6588 // Check access rights if needed.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006589 if (object->IsAccessCheckNeeded() &&
6590 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_HAS)) {
6591 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
6592 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
6593 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006594 }
6595
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596 // Make the lookup and include prototypes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006597 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006598 if (name->AsArrayIndex(&index)) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006599 for (Handle<Object> obj = object;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00006600 !obj->IsNull();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006601 obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
6602 if (obj->IsJSObject() && JSObject::cast(*obj)->HasDictionaryElements()) {
6603 JSObject* js_object = JSObject::cast(*obj);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006604 SeededNumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00006605 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006606 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006607 Object* element = dictionary->ValueAt(entry);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006608 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6609 element->IsAccessorPair()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006610 return handle(AccessorPair::cast(element)->GetComponent(component),
6611 isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006612 }
6613 }
6614 }
6615 }
6616 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006617 for (Handle<Object> obj = object;
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +00006618 !obj->IsNull();
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006619 obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
6620 LookupResult result(isolate);
6621 JSReceiver::cast(*obj)->LocalLookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006622 if (result.IsFound()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006623 if (result.IsReadOnly()) return isolate->factory()->undefined_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006624 if (result.IsPropertyCallbacks()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006625 Object* obj = result.GetCallbackObject();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006626 if (obj->IsAccessorPair()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006627 return handle(AccessorPair::cast(obj)->GetComponent(component),
6628 isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 }
6631 }
6632 }
6633 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006634 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006635}
6636
6637
6638Object* JSObject::SlowReverseLookup(Object* value) {
6639 if (HasFastProperties()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006640 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006641 DescriptorArray* descs = map()->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006642 for (int i = 0; i < number_of_own_descriptors; i++) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006643 if (descs->GetType(i) == FIELD) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006644 Object* property = RawFastPropertyAt(descs->GetFieldIndex(i));
6645 if (FLAG_track_double_fields &&
6646 descs->GetDetails(i).representation().IsDouble()) {
6647 ASSERT(property->IsHeapNumber());
6648 if (value->IsNumber() && property->Number() == value->Number()) {
6649 return descs->GetKey(i);
6650 }
6651 } else if (property == value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006652 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00006654 } else if (descs->GetType(i) == CONSTANT) {
6655 if (descs->GetConstant(i) == value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006656 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 }
6658 }
6659 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006660 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661 } else {
6662 return property_dictionary()->SlowReverseLookup(value);
6663 }
6664}
6665
6666
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006667Handle<Map> Map::RawCopy(Handle<Map> map,
6668 int instance_size) {
6669 CALL_HEAP_FUNCTION(map->GetIsolate(),
6670 map->RawCopy(instance_size),
6671 Map);
6672}
6673
6674
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006675MaybeObject* Map::RawCopy(int instance_size) {
6676 Map* result;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006677 MaybeObject* maybe_result =
6678 GetHeap()->AllocateMap(instance_type(), instance_size);
6679 if (!maybe_result->To(&result)) return maybe_result;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006680
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006681 result->set_prototype(prototype());
6682 result->set_constructor(constructor());
6683 result->set_bit_field(bit_field());
6684 result->set_bit_field2(bit_field2());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006685 int new_bit_field3 = bit_field3();
6686 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
6687 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00006688 new_bit_field3 = EnumLengthBits::update(new_bit_field3,
6689 kInvalidEnumCacheSentinel);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006690 new_bit_field3 = Deprecated::update(new_bit_field3, false);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00006691 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006692 result->set_bit_field3(new_bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006693 return result;
6694}
6695
6696
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006697Handle<Map> Map::CopyNormalized(Handle<Map> map,
6698 PropertyNormalizationMode mode,
6699 NormalizedMapSharingMode sharing) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006700 int new_instance_size = map->instance_size();
ricow@chromium.org65fae842010-08-25 15:26:24 +00006701 if (mode == CLEAR_INOBJECT_PROPERTIES) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006702 new_instance_size -= map->inobject_properties() * kPointerSize;
ricow@chromium.org65fae842010-08-25 15:26:24 +00006703 }
6704
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006705 Handle<Map> result = Map::RawCopy(map, new_instance_size);
ricow@chromium.org65fae842010-08-25 15:26:24 +00006706
6707 if (mode != CLEAR_INOBJECT_PROPERTIES) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006708 result->set_inobject_properties(map->inobject_properties());
ricow@chromium.org65fae842010-08-25 15:26:24 +00006709 }
6710
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006711 result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00006712 result->set_dictionary_map(true);
danno@chromium.org59400602013-08-13 17:09:37 +00006713 result->set_migration_target(false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006714
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006715#ifdef VERIFY_HEAP
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006716 if (FLAG_verify_heap && result->is_shared()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006717 result->SharedMapVerify();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006718 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00006719#endif
6720
6721 return result;
6722}
6723
6724
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006725Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
6726 CALL_HEAP_FUNCTION(map->GetIsolate(), map->CopyDropDescriptors(), Map);
6727}
6728
6729
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006730MaybeObject* Map::CopyDropDescriptors() {
6731 Map* result;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006732 MaybeObject* maybe_result = RawCopy(instance_size());
6733 if (!maybe_result->To(&result)) return maybe_result;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006734
6735 // Please note instance_type and instance_size are set when allocated.
6736 result->set_inobject_properties(inobject_properties());
6737 result->set_unused_property_fields(unused_property_fields());
6738
6739 result->set_pre_allocated_property_fields(pre_allocated_property_fields());
6740 result->set_is_shared(false);
6741 result->ClearCodeCache(GetHeap());
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006742 NotifyLeafMapLayoutChange();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006743 return result;
6744}
6745
6746
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006747MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors,
6748 Descriptor* descriptor) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006749 // Sanity check. This path is only to be taken if the map owns its descriptor
6750 // array, implying that its NumberOfOwnDescriptors equals the number of
6751 // descriptors in the descriptor array.
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006752 ASSERT(NumberOfOwnDescriptors() ==
6753 instance_descriptors()->number_of_descriptors());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006754 Map* result;
6755 MaybeObject* maybe_result = CopyDropDescriptors();
6756 if (!maybe_result->To(&result)) return maybe_result;
6757
ulan@chromium.org750145a2013-03-07 15:14:13 +00006758 Name* name = descriptor->GetKey();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006759
6760 TransitionArray* transitions;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006761 MaybeObject* maybe_transitions =
6762 AddTransition(name, result, SIMPLE_TRANSITION);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006763 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
6764
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006765 int old_size = descriptors->number_of_descriptors();
6766
6767 DescriptorArray* new_descriptors;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006768
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006769 if (descriptors->NumberOfSlackDescriptors() > 0) {
6770 new_descriptors = descriptors;
6771 new_descriptors->Append(descriptor);
6772 } else {
6773 // Descriptor arrays grow by 50%.
6774 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006775 GetIsolate(), old_size, old_size < 4 ? 1 : old_size / 2);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006776 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006777
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006778 DescriptorArray::WhitenessWitness witness(new_descriptors);
6779
6780 // Copy the descriptors, inserting a descriptor.
6781 for (int i = 0; i < old_size; ++i) {
6782 new_descriptors->CopyFrom(i, descriptors, i, witness);
6783 }
6784
6785 new_descriptors->Append(descriptor, witness);
6786
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006787 if (old_size > 0) {
6788 // If the source descriptors had an enum cache we copy it. This ensures
6789 // that the maps to which we push the new descriptor array back can rely
6790 // on a cache always being available once it is set. If the map has more
6791 // enumerated descriptors than available in the original cache, the cache
6792 // will be lazily replaced by the extended cache when needed.
6793 if (descriptors->HasEnumCache()) {
6794 new_descriptors->CopyEnumCacheFrom(descriptors);
6795 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006796
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006797 Map* map;
6798 // Replace descriptors by new_descriptors in all maps that share it.
6799 for (Object* current = GetBackPointer();
6800 !current->IsUndefined();
6801 current = map->GetBackPointer()) {
6802 map = Map::cast(current);
6803 if (map->instance_descriptors() != descriptors) break;
6804 map->set_instance_descriptors(new_descriptors);
6805 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006806
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006807 set_instance_descriptors(new_descriptors);
6808 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006809 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006810
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006811 result->SetBackPointer(this);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006812 result->InitializeDescriptors(new_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006813 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1);
6814
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006815 set_transitions(transitions);
6816 set_owns_descriptors(false);
6817
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006818 return result;
6819}
6820
6821
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006822Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
6823 Handle<DescriptorArray> descriptors,
6824 TransitionFlag flag,
6825 Handle<Name> name) {
6826 CALL_HEAP_FUNCTION(map->GetIsolate(),
6827 map->CopyReplaceDescriptors(*descriptors, flag, *name),
6828 Map);
6829}
6830
6831
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006832MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006833 TransitionFlag flag,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006834 Name* name,
6835 SimpleTransitionFlag simple_flag) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006836 ASSERT(descriptors->IsSortedNoDuplicates());
6837
6838 Map* result;
6839 MaybeObject* maybe_result = CopyDropDescriptors();
6840 if (!maybe_result->To(&result)) return maybe_result;
6841
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006842 result->InitializeDescriptors(descriptors);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006843
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006844 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006845 TransitionArray* transitions;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006846 MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006847 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006848 set_transitions(transitions);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006849 result->SetBackPointer(this);
rossberg@chromium.org92597162013-08-23 13:28:00 +00006850 } else {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006851 descriptors->InitializeRepresentations(Representation::Tagged());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006852 }
6853
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006854 return result;
6855}
6856
6857
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006858// Since this method is used to rewrite an existing transition tree, it can
6859// always insert transitions without checking.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006860Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
6861 int new_descriptor,
6862 Handle<DescriptorArray> descriptors) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00006863 ASSERT(descriptors->IsSortedNoDuplicates());
6864
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006865 Handle<Map> result = Map::CopyDropDescriptors(map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00006866
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006867 result->InitializeDescriptors(*descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00006868 result->SetNumberOfOwnDescriptors(new_descriptor + 1);
6869
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006870 int unused_property_fields = map->unused_property_fields();
danno@chromium.orgf005df62013-04-30 16:36:45 +00006871 if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006872 unused_property_fields = map->unused_property_fields() - 1;
danno@chromium.orgf005df62013-04-30 16:36:45 +00006873 if (unused_property_fields < 0) {
6874 unused_property_fields += JSObject::kFieldsAdded;
6875 }
6876 }
6877
6878 result->set_unused_property_fields(unused_property_fields);
6879 result->set_owns_descriptors(false);
6880
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006881 Handle<Name> name = handle(descriptors->GetKey(new_descriptor));
6882 Handle<TransitionArray> transitions = Map::AddTransition(map, name, result,
6883 SIMPLE_TRANSITION);
danno@chromium.orgf005df62013-04-30 16:36:45 +00006884
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00006885 map->set_transitions(*transitions);
6886 result->SetBackPointer(*map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00006887
6888 return result;
6889}
6890
6891
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006892MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006893 if (flag == INSERT_TRANSITION) {
6894 ASSERT(!HasElementsTransition() ||
6895 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
6896 IsExternalArrayElementsKind(
6897 elements_transition_map()->elements_kind())) &&
6898 (kind == DICTIONARY_ELEMENTS ||
6899 IsExternalArrayElementsKind(kind))));
6900 ASSERT(!IsFastElementsKind(kind) ||
6901 IsMoreGeneralElementsKindTransition(elements_kind(), kind));
6902 ASSERT(kind != elements_kind());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006903 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006904
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006905 bool insert_transition =
6906 flag == INSERT_TRANSITION && !HasElementsTransition();
6907
6908 if (insert_transition && owns_descriptors()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006909 // In case the map owned its own descriptors, share the descriptors and
6910 // transfer ownership to the new map.
6911 Map* new_map;
6912 MaybeObject* maybe_new_map = CopyDropDescriptors();
6913 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
6914
6915 MaybeObject* added_elements = set_elements_transition_map(new_map);
6916 if (added_elements->IsFailure()) return added_elements;
6917
6918 new_map->set_elements_kind(kind);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006919 new_map->InitializeDescriptors(instance_descriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006920 new_map->SetBackPointer(this);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006921 set_owns_descriptors(false);
6922 return new_map;
6923 }
6924
6925 // In case the map did not own its own descriptors, a split is forced by
6926 // copying the map; creating a new descriptor array cell.
6927 // Create a new free-floating map only if we are not allowed to store it.
6928 Map* new_map;
6929 MaybeObject* maybe_new_map = Copy();
6930 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006931
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006932 new_map->set_elements_kind(kind);
6933
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006934 if (insert_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006935 MaybeObject* added_elements = set_elements_transition_map(new_map);
6936 if (added_elements->IsFailure()) return added_elements;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006937 new_map->SetBackPointer(this);
6938 }
6939
6940 return new_map;
6941}
6942
6943
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00006944Handle<Map> Map::CopyForObserved(Handle<Map> map) {
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006945 ASSERT(!map->is_observed());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00006946
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006947 Isolate* isolate = map->GetIsolate();
danno@chromium.org169691d2013-07-15 08:01:13 +00006948
6949 // In case the map owned its own descriptors, share the descriptors and
6950 // transfer ownership to the new map.
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006951 Handle<Map> new_map;
6952 if (map->owns_descriptors()) {
6953 new_map = Map::CopyDropDescriptors(map);
danno@chromium.org169691d2013-07-15 08:01:13 +00006954 } else {
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006955 new_map = Map::Copy(map);
danno@chromium.org169691d2013-07-15 08:01:13 +00006956 }
danno@chromium.org169691d2013-07-15 08:01:13 +00006957
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006958 Handle<TransitionArray> transitions =
6959 Map::AddTransition(map, isolate->factory()->observed_symbol(), new_map,
6960 FULL_TRANSITION);
6961
6962 map->set_transitions(*transitions);
danno@chromium.org169691d2013-07-15 08:01:13 +00006963
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00006964 new_map->set_is_observed();
danno@chromium.org169691d2013-07-15 08:01:13 +00006965
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006966 if (map->owns_descriptors()) {
6967 new_map->InitializeDescriptors(map->instance_descriptors());
6968 map->set_owns_descriptors(false);
danno@chromium.org169691d2013-07-15 08:01:13 +00006969 }
6970
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +00006971 new_map->SetBackPointer(*map);
danno@chromium.org169691d2013-07-15 08:01:13 +00006972 return new_map;
6973}
6974
6975
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006976MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
6977 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
6978
6979 // If the map has pre-allocated properties always start out with a descriptor
6980 // array describing these properties.
6981 ASSERT(constructor()->IsJSFunction());
6982 JSFunction* ctor = JSFunction::cast(constructor());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006983 Map* map = ctor->initial_map();
6984 DescriptorArray* descriptors = map->instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006985
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006986 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
6987 DescriptorArray* new_descriptors;
6988 MaybeObject* maybe_descriptors =
6989 descriptors->CopyUpTo(number_of_own_descriptors);
6990 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
6991
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006992 return CopyReplaceDescriptors(new_descriptors, OMIT_TRANSITION);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006993}
6994
6995
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006996Handle<Map> Map::Copy(Handle<Map> map) {
6997 CALL_HEAP_FUNCTION(map->GetIsolate(), map->Copy(), Map);
6998}
6999
7000
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007001MaybeObject* Map::Copy() {
7002 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007003 DescriptorArray* new_descriptors;
7004 int number_of_own_descriptors = NumberOfOwnDescriptors();
7005 MaybeObject* maybe_descriptors =
7006 descriptors->CopyUpTo(number_of_own_descriptors);
7007 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
7008
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007009 return CopyReplaceDescriptors(new_descriptors, OMIT_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007010}
7011
7012
7013MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
7014 TransitionFlag flag) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007015 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007016
ulan@chromium.org750145a2013-03-07 15:14:13 +00007017 // Ensure the key is unique.
7018 MaybeObject* maybe_failure = descriptor->KeyToUniqueName();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007019 if (maybe_failure->IsFailure()) return maybe_failure;
7020
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007021 int old_size = NumberOfOwnDescriptors();
verwaest@chromium.org652f4fa2012-10-08 08:48:51 +00007022 int new_size = old_size + 1;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007023
7024 if (flag == INSERT_TRANSITION &&
7025 owns_descriptors() &&
7026 CanHaveMoreTransitions()) {
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00007027 return ShareDescriptor(descriptors, descriptor);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007028 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007029
7030 DescriptorArray* new_descriptors;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007031 MaybeObject* maybe_descriptors =
7032 DescriptorArray::Allocate(GetIsolate(), old_size, 1);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007033 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
7034
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007035 DescriptorArray::WhitenessWitness witness(new_descriptors);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007036
7037 // Copy the descriptors, inserting a descriptor.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007038 for (int i = 0; i < old_size; ++i) {
7039 new_descriptors->CopyFrom(i, descriptors, i, witness);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007040 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007041
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007042 if (old_size != descriptors->number_of_descriptors()) {
7043 new_descriptors->SetNumberOfDescriptors(new_size);
7044 new_descriptors->Set(old_size, descriptor, witness);
7045 new_descriptors->Sort();
7046 } else {
7047 new_descriptors->Append(descriptor, witness);
7048 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007049
ulan@chromium.org750145a2013-03-07 15:14:13 +00007050 Name* key = descriptor->GetKey();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007051 return CopyReplaceDescriptors(new_descriptors, flag, key, SIMPLE_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007052}
7053
7054
7055MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor,
7056 TransitionFlag flag) {
7057 DescriptorArray* old_descriptors = instance_descriptors();
7058
ulan@chromium.org750145a2013-03-07 15:14:13 +00007059 // Ensure the key is unique.
7060 MaybeObject* maybe_result = descriptor->KeyToUniqueName();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007061 if (maybe_result->IsFailure()) return maybe_result;
7062
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007063 // We replace the key if it is already present.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007064 int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007065 if (index != DescriptorArray::kNotFound) {
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00007066 return CopyReplaceDescriptor(old_descriptors, descriptor, index, flag);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007067 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007068 return CopyAddDescriptor(descriptor, flag);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007069}
7070
7071
machenbach@chromium.org528ce022013-09-23 14:09:36 +00007072Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
7073 Handle<DescriptorArray> desc,
7074 int enumeration_index,
7075 PropertyAttributes attributes) {
7076 CALL_HEAP_FUNCTION(desc->GetIsolate(),
7077 desc->CopyUpToAddAttributes(enumeration_index, attributes),
7078 DescriptorArray);
7079}
7080
7081
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007082MaybeObject* DescriptorArray::CopyUpToAddAttributes(
7083 int enumeration_index, PropertyAttributes attributes) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007084 if (enumeration_index == 0) return GetHeap()->empty_descriptor_array();
7085
7086 int size = enumeration_index;
7087
7088 DescriptorArray* descriptors;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007089 MaybeObject* maybe_descriptors = Allocate(GetIsolate(), size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007090 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
7091 DescriptorArray::WhitenessWitness witness(descriptors);
7092
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007093 if (attributes != NONE) {
7094 for (int i = 0; i < size; ++i) {
7095 Object* value = GetValue(i);
7096 PropertyDetails details = GetDetails(i);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00007097 int mask = DONT_DELETE | DONT_ENUM;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007098 // READ_ONLY is an invalid attribute for JS setters/getters.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00007099 if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
7100 mask |= READ_ONLY;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007101 }
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00007102 details = details.CopyAddAttributes(
7103 static_cast<PropertyAttributes>(attributes & mask));
7104 Descriptor desc(GetKey(i), value, details);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007105 descriptors->Set(i, &desc, witness);
7106 }
7107 } else {
7108 for (int i = 0; i < size; ++i) {
7109 descriptors->CopyFrom(i, this, i, witness);
7110 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007111 }
7112
7113 if (number_of_descriptors() != enumeration_index) descriptors->Sort();
7114
7115 return descriptors;
7116}
7117
7118
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00007119MaybeObject* Map::CopyReplaceDescriptor(DescriptorArray* descriptors,
7120 Descriptor* descriptor,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007121 int insertion_index,
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007122 TransitionFlag flag) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00007123 // Ensure the key is unique.
7124 MaybeObject* maybe_failure = descriptor->KeyToUniqueName();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007125 if (maybe_failure->IsFailure()) return maybe_failure;
7126
ulan@chromium.org750145a2013-03-07 15:14:13 +00007127 Name* key = descriptor->GetKey();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007128 ASSERT(key == descriptors->GetKey(insertion_index));
7129
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007130 int new_size = NumberOfOwnDescriptors();
7131 ASSERT(0 <= insertion_index && insertion_index < new_size);
verwaest@chromium.org652f4fa2012-10-08 08:48:51 +00007132
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007133 ASSERT_LT(insertion_index, new_size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007134
7135 DescriptorArray* new_descriptors;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007136 MaybeObject* maybe_descriptors =
7137 DescriptorArray::Allocate(GetIsolate(), new_size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007138 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007139 DescriptorArray::WhitenessWitness witness(new_descriptors);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007140
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007141 for (int i = 0; i < new_size; ++i) {
7142 if (i == insertion_index) {
7143 new_descriptors->Set(i, descriptor, witness);
7144 } else {
7145 new_descriptors->CopyFrom(i, descriptors, i, witness);
7146 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007147 }
7148
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007149 // Re-sort if descriptors were removed.
7150 if (new_size != descriptors->length()) new_descriptors->Sort();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007151
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007152 SimpleTransitionFlag simple_flag =
7153 (insertion_index == descriptors->number_of_descriptors() - 1)
7154 ? SIMPLE_TRANSITION
7155 : FULL_TRANSITION;
7156 return CopyReplaceDescriptors(new_descriptors, flag, key, simple_flag);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007157}
7158
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007159
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007160void Map::UpdateCodeCache(Handle<Map> map,
ulan@chromium.org750145a2013-03-07 15:14:13 +00007161 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007162 Handle<Code> code) {
7163 Isolate* isolate = map->GetIsolate();
7164 CALL_HEAP_FUNCTION_VOID(isolate,
7165 map->UpdateCodeCache(*name, *code));
7166}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007167
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007168
ulan@chromium.org750145a2013-03-07 15:14:13 +00007169MaybeObject* Map::UpdateCodeCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007170 // Allocate the code cache if not present.
7171 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007172 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007173 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007174 if (!maybe_result->ToObject(&result)) return maybe_result;
7175 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007176 set_code_cache(result);
7177 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007178
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007179 // Update the code cache.
7180 return CodeCache::cast(code_cache())->Update(name, code);
7181}
7182
7183
ulan@chromium.org750145a2013-03-07 15:14:13 +00007184Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007185 // Do a lookup if a code cache exists.
7186 if (!code_cache()->IsFixedArray()) {
7187 return CodeCache::cast(code_cache())->Lookup(name, flags);
7188 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007189 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007190 }
7191}
7192
7193
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00007194int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007195 // Get the internal index if a code cache exists.
7196 if (!code_cache()->IsFixedArray()) {
7197 return CodeCache::cast(code_cache())->GetIndex(name, code);
7198 }
7199 return -1;
7200}
7201
7202
ulan@chromium.org750145a2013-03-07 15:14:13 +00007203void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007204 // No GC is supposed to happen between a call to IndexInCodeCache and
7205 // RemoveFromCodeCache so the code cache must be there.
7206 ASSERT(!code_cache()->IsFixedArray());
7207 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7208}
7209
7210
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007211// An iterator over all map transitions in an descriptor array, reusing the map
7212// field of the contens array while it is running.
7213class IntrusiveMapTransitionIterator {
7214 public:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007215 explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
7216 : transition_array_(transition_array) { }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007217
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007218 void Start() {
7219 ASSERT(!IsIterating());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007220 *TransitionArrayHeader() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007221 }
7222
7223 bool IsIterating() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007224 return (*TransitionArrayHeader())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007225 }
7226
7227 Map* Next() {
7228 ASSERT(IsIterating());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007229 int index = Smi::cast(*TransitionArrayHeader())->value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007230 int number_of_transitions = transition_array_->number_of_transitions();
7231 while (index < number_of_transitions) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007232 *TransitionArrayHeader() = Smi::FromInt(index + 1);
7233 return transition_array_->GetTarget(index);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007234 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007235
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007236 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007237 return NULL;
7238 }
7239
7240 private:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007241 Object** TransitionArrayHeader() {
7242 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007243 }
7244
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007245 TransitionArray* transition_array_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007246};
7247
7248
7249// An iterator over all prototype transitions, reusing the map field of the
7250// underlying array while it is running.
7251class IntrusivePrototypeTransitionIterator {
7252 public:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007253 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007254 : proto_trans_(proto_trans) { }
7255
7256 void Start() {
7257 ASSERT(!IsIterating());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007258 *Header() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007259 }
7260
7261 bool IsIterating() {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007262 return (*Header())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007263 }
7264
7265 Map* Next() {
7266 ASSERT(IsIterating());
7267 int transitionNumber = Smi::cast(*Header())->value();
7268 if (transitionNumber < NumberOfTransitions()) {
7269 *Header() = Smi::FromInt(transitionNumber + 1);
7270 return GetTransition(transitionNumber);
7271 }
7272 *Header() = proto_trans_->GetHeap()->fixed_array_map();
7273 return NULL;
7274 }
7275
7276 private:
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007277 Object** Header() {
7278 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
7279 }
7280
7281 int NumberOfTransitions() {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007282 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7283 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007284 return Smi::cast(num)->value();
7285 }
7286
7287 Map* GetTransition(int transitionNumber) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007288 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7289 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007290 }
7291
7292 int IndexFor(int transitionNumber) {
7293 return Map::kProtoTransitionHeaderSize +
7294 Map::kProtoTransitionMapOffset +
7295 transitionNumber * Map::kProtoTransitionElementsPerEntry;
7296 }
7297
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007298 HeapObject* proto_trans_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007299};
7300
7301
7302// To traverse the transition tree iteratively, we have to store two kinds of
7303// information in a map: The parent map in the traversal and which children of a
7304// node have already been visited. To do this without additional memory, we
7305// temporarily reuse two maps with known values:
7306//
7307// (1) The map of the map temporarily holds the parent, and is restored to the
7308// meta map afterwards.
7309//
7310// (2) The info which children have already been visited depends on which part
7311// of the map we currently iterate:
7312//
7313// (a) If we currently follow normal map transitions, we temporarily store
7314// the current index in the map of the FixedArray of the desciptor
7315// array's contents, and restore it to the fixed array map afterwards.
7316// Note that a single descriptor can have 0, 1, or 2 transitions.
7317//
7318// (b) If we currently follow prototype transitions, we temporarily store
7319// the current index in the map of the FixedArray holding the prototype
7320// transitions, and restore it to the fixed array map afterwards.
7321//
7322// Note that the child iterator is just a concatenation of two iterators: One
7323// iterating over map transitions and one iterating over prototype transisitons.
7324class TraversableMap : public Map {
7325 public:
7326 // Record the parent in the traversal within this map. Note that this destroys
7327 // this map's map!
7328 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7329
7330 // Reset the current map's map, returning the parent previously stored in it.
7331 TraversableMap* GetAndResetParent() {
7332 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7333 set_map_no_write_barrier(GetHeap()->meta_map());
7334 return old_parent;
7335 }
7336
7337 // Start iterating over this map's children, possibly destroying a FixedArray
7338 // map (see explanation above).
7339 void ChildIteratorStart() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007340 if (HasTransitionArray()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007341 if (HasPrototypeTransitions()) {
7342 IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start();
7343 }
7344
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007345 IntrusiveMapTransitionIterator(transitions()).Start();
7346 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007347 }
7348
7349 // If we have an unvisited child map, return that one and advance. If we have
7350 // none, return NULL and reset any destroyed FixedArray maps.
7351 TraversableMap* ChildIteratorNext() {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007352 TransitionArray* transition_array = unchecked_transition_array();
7353 if (!transition_array->map()->IsSmi() &&
7354 !transition_array->IsTransitionArray()) {
7355 return NULL;
7356 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007357
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007358 if (transition_array->HasPrototypeTransitions()) {
7359 HeapObject* proto_transitions =
7360 transition_array->UncheckedPrototypeTransitions();
7361 IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
7362 if (proto_iterator.IsIterating()) {
7363 Map* next = proto_iterator.Next();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007364 if (next != NULL) return static_cast<TraversableMap*>(next);
7365 }
verwaest@chromium.org37141392012-05-31 13:27:02 +00007366 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007367
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007368 IntrusiveMapTransitionIterator transition_iterator(transition_array);
7369 if (transition_iterator.IsIterating()) {
7370 Map* next = transition_iterator.Next();
7371 if (next != NULL) return static_cast<TraversableMap*>(next);
7372 }
7373
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007374 return NULL;
7375 }
7376};
7377
7378
7379// Traverse the transition tree in postorder without using the C++ stack by
7380// doing pointer reversal.
7381void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
7382 TraversableMap* current = static_cast<TraversableMap*>(this);
7383 current->ChildIteratorStart();
7384 while (true) {
7385 TraversableMap* child = current->ChildIteratorNext();
7386 if (child != NULL) {
7387 child->ChildIteratorStart();
7388 child->SetParent(current);
7389 current = child;
7390 } else {
7391 TraversableMap* parent = current->GetAndResetParent();
7392 callback(current, data);
7393 if (current == this) break;
7394 current = parent;
7395 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007396 }
7397}
7398
7399
ulan@chromium.org750145a2013-03-07 15:14:13 +00007400MaybeObject* CodeCache::Update(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007401 // The number of monomorphic stubs for normal load/store/call IC's can grow to
7402 // a large number and therefore they need to go into a hash table. They are
7403 // used to load global properties from cells.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007404 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007405 // Make sure that a hash table is allocated for the normal load code cache.
7406 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007407 Object* result;
7408 { MaybeObject* maybe_result =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007409 CodeCacheHashTable::Allocate(GetHeap(),
7410 CodeCacheHashTable::kInitialSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007411 if (!maybe_result->ToObject(&result)) return maybe_result;
7412 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007413 set_normal_type_cache(result);
7414 }
7415 return UpdateNormalTypeCache(name, code);
7416 } else {
7417 ASSERT(default_cache()->IsFixedArray());
7418 return UpdateDefaultCache(name, code);
7419 }
7420}
7421
7422
ulan@chromium.org750145a2013-03-07 15:14:13 +00007423MaybeObject* CodeCache::UpdateDefaultCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007424 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007425 // flags. This allows call constant stubs to overwrite call field
7426 // stubs, etc.
7427 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
7428
7429 // First check whether we can update existing code cache without
7430 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007431 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007432 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00007433 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007434 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007435 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00007436 if (key->IsNull()) {
7437 if (deleted_index < 0) deleted_index = i;
7438 continue;
7439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00007441 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007442 cache->set(i + kCodeCacheEntryNameOffset, name);
7443 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444 return this;
7445 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00007446 if (name->Equals(Name::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007447 Code::Flags found =
7448 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007449 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007450 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451 return this;
7452 }
7453 }
7454 }
7455
ager@chromium.org236ad962008-09-25 09:45:57 +00007456 // Reached the end of the code cache. If there were deleted
7457 // elements, reuse the space for the first of them.
7458 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007459 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
7460 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00007461 return this;
7462 }
7463
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007464 // Extend the code cache with some new entries (at least one). Must be a
7465 // multiple of the entry size.
7466 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
7467 new_length = new_length - new_length % kCodeCacheEntrySize;
7468 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007469 Object* result;
7470 { MaybeObject* maybe_result = cache->CopySize(new_length);
7471 if (!maybe_result->ToObject(&result)) return maybe_result;
7472 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007473
7474 // Add the (name, code) pair to the new cache.
7475 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007476 cache->set(length + kCodeCacheEntryNameOffset, name);
7477 cache->set(length + kCodeCacheEntryCodeOffset, code);
7478 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007479 return this;
7480}
7481
7482
ulan@chromium.org750145a2013-03-07 15:14:13 +00007483MaybeObject* CodeCache::UpdateNormalTypeCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007484 // Adding a new entry can cause a new cache to be allocated.
7485 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007486 Object* new_cache;
7487 { MaybeObject* maybe_new_cache = cache->Put(name, code);
7488 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
7489 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007490 set_normal_type_cache(new_cache);
7491 return this;
7492}
7493
7494
ulan@chromium.org750145a2013-03-07 15:14:13 +00007495Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00007496 flags = Code::RemoveTypeFromFlags(flags);
7497 Object* result = LookupDefaultCache(name, flags);
7498 if (result->IsCode()) return result;
7499 return LookupNormalTypeCache(name, flags);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007500}
7501
7502
ulan@chromium.org750145a2013-03-07 15:14:13 +00007503Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007504 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007505 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007506 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7507 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00007508 // Skip deleted elements.
7509 if (key->IsNull()) continue;
7510 if (key->IsUndefined()) return key;
ulan@chromium.org750145a2013-03-07 15:14:13 +00007511 if (name->Equals(Name::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007512 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00007513 if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007514 return code;
7515 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516 }
7517 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007518 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007519}
7520
7521
ulan@chromium.org750145a2013-03-07 15:14:13 +00007522Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007523 if (!normal_type_cache()->IsUndefined()) {
7524 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7525 return cache->Lookup(name, flags);
7526 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007527 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007528 }
7529}
7530
7531
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00007532int CodeCache::GetIndex(Object* name, Code* code) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007533 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007534 if (normal_type_cache()->IsUndefined()) return -1;
7535 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
ulan@chromium.org750145a2013-03-07 15:14:13 +00007536 return cache->GetIndex(Name::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007537 }
7538
7539 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007540 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007541 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
7542 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007543 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007544 return -1;
7545}
7546
7547
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00007548void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007549 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007550 ASSERT(!normal_type_cache()->IsUndefined());
7551 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
ulan@chromium.org750145a2013-03-07 15:14:13 +00007552 ASSERT(cache->GetIndex(Name::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007553 cache->RemoveByIndex(index);
7554 } else {
7555 FixedArray* array = default_cache();
7556 ASSERT(array->length() >= index && array->get(index)->IsCode());
7557 // Use null instead of undefined for deleted elements to distinguish
7558 // deleted elements from unused elements. This distinction is used
7559 // when looking up in the cache and when updating the cache.
7560 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
7561 array->set_null(index - 1); // Name.
7562 array->set_null(index); // Code.
7563 }
7564}
7565
7566
7567// The key in the code cache hash table consists of the property name and the
7568// code object. The actual match is on the name and the code flags. If a key
7569// is created using the flags and not a code object it can only be used for
7570// lookup not to create a new entry.
7571class CodeCacheHashTableKey : public HashTableKey {
7572 public:
ulan@chromium.org750145a2013-03-07 15:14:13 +00007573 CodeCacheHashTableKey(Name* name, Code::Flags flags)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007574 : name_(name), flags_(flags), code_(NULL) { }
7575
ulan@chromium.org750145a2013-03-07 15:14:13 +00007576 CodeCacheHashTableKey(Name* name, Code* code)
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00007577 : name_(name), flags_(code->flags()), code_(code) { }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007578
7579
7580 bool IsMatch(Object* other) {
7581 if (!other->IsFixedArray()) return false;
7582 FixedArray* pair = FixedArray::cast(other);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007583 Name* name = Name::cast(pair->get(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007584 Code::Flags flags = Code::cast(pair->get(1))->flags();
7585 if (flags != flags_) {
7586 return false;
7587 }
7588 return name_->Equals(name);
7589 }
7590
ulan@chromium.org750145a2013-03-07 15:14:13 +00007591 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007592 return name->Hash() ^ flags;
7593 }
7594
7595 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
7596
7597 uint32_t HashForObject(Object* obj) {
7598 FixedArray* pair = FixedArray::cast(obj);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007599 Name* name = Name::cast(pair->get(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007600 Code* code = Code::cast(pair->get(1));
7601 return NameFlagsHashHelper(name, code->flags());
7602 }
7603
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007604 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007605 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007606 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007607 { MaybeObject* maybe_obj = heap->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007608 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7609 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007610 FixedArray* pair = FixedArray::cast(obj);
7611 pair->set(0, name_);
7612 pair->set(1, code_);
7613 return pair;
7614 }
7615
7616 private:
ulan@chromium.org750145a2013-03-07 15:14:13 +00007617 Name* name_;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007618 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007619 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007620 Code* code_;
7621};
7622
7623
ulan@chromium.org750145a2013-03-07 15:14:13 +00007624Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007625 CodeCacheHashTableKey key(name, flags);
7626 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007627 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007628 return get(EntryToIndex(entry) + 1);
7629}
7630
7631
ulan@chromium.org750145a2013-03-07 15:14:13 +00007632MaybeObject* CodeCacheHashTable::Put(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007633 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007634 Object* obj;
7635 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
7636 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7637 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007638
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007639 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007640 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
7641
7642 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007643 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007644 { MaybeObject* maybe_k = key.AsObject(GetHeap());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007645 if (!maybe_k->ToObject(&k)) return maybe_k;
7646 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007647
7648 cache->set(EntryToIndex(entry), k);
7649 cache->set(EntryToIndex(entry) + 1, code);
7650 cache->ElementAdded();
7651 return cache;
7652}
7653
7654
ulan@chromium.org750145a2013-03-07 15:14:13 +00007655int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007656 CodeCacheHashTableKey key(name, flags);
7657 int entry = FindEntry(&key);
7658 return (entry == kNotFound) ? -1 : entry;
7659}
7660
7661
7662void CodeCacheHashTable::RemoveByIndex(int index) {
7663 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007664 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007665 set(EntryToIndex(index), heap->the_hole_value());
7666 set(EntryToIndex(index) + 1, heap->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007667 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007668}
7669
7670
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007671void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
7672 MapHandleList* maps,
7673 Code::Flags flags,
7674 Handle<Code> code) {
7675 Isolate* isolate = cache->GetIsolate();
7676 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
7677}
7678
7679
7680MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007681 Code::Flags flags,
7682 Code* code) {
7683 // Initialize cache if necessary.
7684 if (cache()->IsUndefined()) {
7685 Object* result;
7686 { MaybeObject* maybe_result =
7687 PolymorphicCodeCacheHashTable::Allocate(
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007688 GetHeap(),
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007689 PolymorphicCodeCacheHashTable::kInitialSize);
7690 if (!maybe_result->ToObject(&result)) return maybe_result;
7691 }
7692 set_cache(result);
7693 } else {
7694 // This entry shouldn't be contained in the cache yet.
7695 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
7696 ->Lookup(maps, flags)->IsUndefined());
7697 }
7698 PolymorphicCodeCacheHashTable* hash_table =
7699 PolymorphicCodeCacheHashTable::cast(cache());
7700 Object* new_cache;
7701 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
7702 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
7703 }
7704 set_cache(new_cache);
7705 return this;
7706}
7707
7708
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007709Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
7710 Code::Flags flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007711 if (!cache()->IsUndefined()) {
7712 PolymorphicCodeCacheHashTable* hash_table =
7713 PolymorphicCodeCacheHashTable::cast(cache());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007714 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007715 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007716 return GetIsolate()->factory()->undefined_value();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007717 }
7718}
7719
7720
7721// Despite their name, object of this class are not stored in the actual
7722// hash table; instead they're temporarily used for lookups. It is therefore
7723// safe to have a weak (non-owning) pointer to a MapList as a member field.
7724class PolymorphicCodeCacheHashTableKey : public HashTableKey {
7725 public:
7726 // Callers must ensure that |maps| outlives the newly constructed object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007727 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007728 : maps_(maps),
7729 code_flags_(code_flags) {}
7730
7731 bool IsMatch(Object* other) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007732 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007733 int other_flags;
7734 FromObject(other, &other_flags, &other_maps);
7735 if (code_flags_ != other_flags) return false;
7736 if (maps_->length() != other_maps.length()) return false;
7737 // Compare just the hashes first because it's faster.
7738 int this_hash = MapsHashHelper(maps_, code_flags_);
7739 int other_hash = MapsHashHelper(&other_maps, other_flags);
7740 if (this_hash != other_hash) return false;
7741
7742 // Full comparison: for each map in maps_, look for an equivalent map in
7743 // other_maps. This implementation is slow, but probably good enough for
7744 // now because the lists are short (<= 4 elements currently).
7745 for (int i = 0; i < maps_->length(); ++i) {
7746 bool match_found = false;
7747 for (int j = 0; j < other_maps.length(); ++j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00007748 if (*(maps_->at(i)) == *(other_maps.at(j))) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007749 match_found = true;
7750 break;
7751 }
7752 }
7753 if (!match_found) return false;
7754 }
7755 return true;
7756 }
7757
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007758 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007759 uint32_t hash = code_flags;
7760 for (int i = 0; i < maps->length(); ++i) {
7761 hash ^= maps->at(i)->Hash();
7762 }
7763 return hash;
7764 }
7765
7766 uint32_t Hash() {
7767 return MapsHashHelper(maps_, code_flags_);
7768 }
7769
7770 uint32_t HashForObject(Object* obj) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007771 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007772 int other_flags;
7773 FromObject(obj, &other_flags, &other_maps);
7774 return MapsHashHelper(&other_maps, other_flags);
7775 }
7776
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007777 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007778 Object* obj;
7779 // The maps in |maps_| must be copied to a newly allocated FixedArray,
7780 // both because the referenced MapList is short-lived, and because C++
7781 // objects can't be stored in the heap anyway.
7782 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007783 heap->AllocateUninitializedFixedArray(maps_->length() + 1);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7785 }
7786 FixedArray* list = FixedArray::cast(obj);
7787 list->set(0, Smi::FromInt(code_flags_));
7788 for (int i = 0; i < maps_->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007789 list->set(i + 1, *maps_->at(i));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007790 }
7791 return list;
7792 }
7793
7794 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007795 static MapHandleList* FromObject(Object* obj,
7796 int* code_flags,
7797 MapHandleList* maps) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007798 FixedArray* list = FixedArray::cast(obj);
7799 maps->Rewind(0);
7800 *code_flags = Smi::cast(list->get(0))->value();
7801 for (int i = 1; i < list->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007802 maps->Add(Handle<Map>(Map::cast(list->get(i))));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007803 }
7804 return maps;
7805 }
7806
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007807 MapHandleList* maps_; // weak.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007808 int code_flags_;
whesse@chromium.org7b260152011-06-20 15:33:18 +00007809 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007810};
7811
7812
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007813Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
7814 int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007815 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
7816 int entry = FindEntry(&key);
7817 if (entry == kNotFound) return GetHeap()->undefined_value();
7818 return get(EntryToIndex(entry) + 1);
7819}
7820
7821
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007822MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007823 int code_flags,
7824 Code* code) {
7825 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
7826 Object* obj;
7827 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
7828 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7829 }
7830 PolymorphicCodeCacheHashTable* cache =
7831 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
7832 int entry = cache->FindInsertionEntry(key.Hash());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007833 { MaybeObject* maybe_obj = key.AsObject(GetHeap());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007834 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7835 }
7836 cache->set(EntryToIndex(entry), obj);
7837 cache->set(EntryToIndex(entry) + 1, code);
7838 cache->ElementAdded();
7839 return cache;
7840}
7841
7842
lrn@chromium.org303ada72010-10-27 09:33:13 +00007843MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007844 ElementsAccessor* accessor = array->GetElementsAccessor();
7845 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007846 accessor->AddElementsToFixedArray(array, array, this);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007847 FixedArray* result;
7848 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00007849#ifdef ENABLE_SLOW_ASSERTS
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007850 if (FLAG_enable_slow_asserts) {
7851 for (int i = 0; i < result->length(); i++) {
7852 Object* current = result->get(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007853 ASSERT(current->IsNumber() || current->IsName());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007854 }
7855 }
7856#endif
7857 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007858}
7859
7860
lrn@chromium.org303ada72010-10-27 09:33:13 +00007861MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007862 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
7863 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007864 accessor->AddElementsToFixedArray(NULL, NULL, this, other);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007865 FixedArray* result;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00007866 if (!maybe_result->To(&result)) return maybe_result;
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00007867#ifdef ENABLE_SLOW_ASSERTS
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007868 if (FLAG_enable_slow_asserts) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007869 for (int i = 0; i < result->length(); i++) {
7870 Object* current = result->get(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007871 ASSERT(current->IsNumber() || current->IsName());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007872 }
7873 }
7874#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007875 return result;
7876}
7877
7878
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00007879MaybeObject* FixedArray::CopySize(int new_length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 Heap* heap = GetHeap();
7881 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007882 Object* obj;
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00007883 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007884 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007886 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 // Copy the content
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007888 DisallowHeapAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007889 int len = length();
7890 if (new_length < len) len = new_length;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007891 // We are taking the map from the old fixed array so the map is sure to
7892 // be an immortal immutable object.
7893 result->set_map_no_write_barrier(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007894 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007895 for (int i = 0; i < len; i++) {
7896 result->set(i, get(i), mode);
7897 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007898 return result;
7899}
7900
7901
7902void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007903 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007904 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007905 for (int index = 0; index < len; index++) {
7906 dest->set(dest_pos+index, get(pos+index), mode);
7907 }
7908}
7909
7910
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007911#ifdef DEBUG
7912bool FixedArray::IsEqualTo(FixedArray* other) {
7913 if (length() != other->length()) return false;
7914 for (int i = 0 ; i < length(); ++i) {
7915 if (get(i) != other->get(i)) return false;
7916 }
7917 return true;
7918}
7919#endif
7920
7921
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007922MaybeObject* DescriptorArray::Allocate(Isolate* isolate,
7923 int number_of_descriptors,
7924 int slack) {
7925 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007926 // Do not use DescriptorArray::cast on incomplete object.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007927 int size = number_of_descriptors + slack;
7928 if (size == 0) return heap->empty_descriptor_array();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007929 FixedArray* result;
verwaest@chromium.org50915592012-06-18 12:15:44 +00007930 // Allocate the array of keys.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007931 MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size));
danno@chromium.org129d3982012-07-25 15:01:47 +00007932 if (!maybe_array->To(&result)) return maybe_array;
verwaest@chromium.org50915592012-06-18 12:15:44 +00007933
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007934 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007935 result->set(kEnumCacheIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007936 return result;
7937}
7938
7939
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007940void DescriptorArray::ClearEnumCache() {
7941 set(kEnumCacheIndex, Smi::FromInt(0));
7942}
7943
7944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007945void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007946 FixedArray* new_cache,
7947 Object* new_index_cache) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007948 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007949 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007950 ASSERT(!IsEmpty());
7951 ASSERT(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
7952 FixedArray::cast(bridge_storage)->
7953 set(kEnumCacheBridgeCacheIndex, new_cache);
7954 FixedArray::cast(bridge_storage)->
7955 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
7956 set(kEnumCacheIndex, bridge_storage);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007957}
7958
7959
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007960void DescriptorArray::CopyFrom(int dst_index,
7961 DescriptorArray* src,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007962 int src_index,
7963 const WhitenessWitness& witness) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007964 Object* value = src->GetValue(src_index);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00007965 PropertyDetails details = src->GetDetails(src_index);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007966 Descriptor desc(src->GetKey(src_index), value, details);
7967 Set(dst_index, &desc, witness);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007968}
7969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007970
machenbach@chromium.org528ce022013-09-23 14:09:36 +00007971Handle<DescriptorArray> DescriptorArray::Merge(Handle<DescriptorArray> desc,
7972 int verbatim,
7973 int valid,
7974 int new_size,
7975 int modify_index,
7976 StoreMode store_mode,
7977 Handle<DescriptorArray> other) {
7978 CALL_HEAP_FUNCTION(desc->GetIsolate(),
7979 desc->Merge(verbatim, valid, new_size, modify_index,
7980 store_mode, *other),
7981 DescriptorArray);
7982}
7983
7984
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007985// Generalize the |other| descriptor array by merging it into the (at least
danno@chromium.orgf005df62013-04-30 16:36:45 +00007986// partly) updated |this| descriptor array.
7987// The method merges two descriptor array in three parts. Both descriptor arrays
7988// are identical up to |verbatim|. They also overlap in keys up to |valid|.
7989// Between |verbatim| and |valid|, the resulting descriptor type as well as the
7990// representation are generalized from both |this| and |other|. Beyond |valid|,
7991// the descriptors are copied verbatim from |other| up to |new_size|.
7992// In case of incompatible types, the type and representation of |other| is
7993// used.
7994MaybeObject* DescriptorArray::Merge(int verbatim,
7995 int valid,
7996 int new_size,
rossberg@chromium.org92597162013-08-23 13:28:00 +00007997 int modify_index,
7998 StoreMode store_mode,
danno@chromium.orgf005df62013-04-30 16:36:45 +00007999 DescriptorArray* other) {
8000 ASSERT(verbatim <= valid);
8001 ASSERT(valid <= new_size);
8002
8003 DescriptorArray* result;
8004 // Allocate a new descriptor array large enough to hold the required
8005 // descriptors, with minimally the exact same size as this descriptor array.
8006 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008007 GetIsolate(), new_size,
8008 Max(new_size, other->number_of_descriptors()) - new_size);
danno@chromium.orgf005df62013-04-30 16:36:45 +00008009 if (!maybe_descriptors->To(&result)) return maybe_descriptors;
8010 ASSERT(result->length() > length() ||
8011 result->NumberOfSlackDescriptors() > 0 ||
8012 result->number_of_descriptors() == other->number_of_descriptors());
8013 ASSERT(result->number_of_descriptors() == new_size);
8014
8015 DescriptorArray::WhitenessWitness witness(result);
8016
8017 int descriptor;
8018
8019 // 0 -> |verbatim|
8020 int current_offset = 0;
8021 for (descriptor = 0; descriptor < verbatim; descriptor++) {
8022 if (GetDetails(descriptor).type() == FIELD) current_offset++;
hpayer@chromium.org2311a912013-08-28 13:39:38 +00008023 result->CopyFrom(descriptor, other, descriptor, witness);
danno@chromium.orgf005df62013-04-30 16:36:45 +00008024 }
8025
8026 // |verbatim| -> |valid|
8027 for (; descriptor < valid; descriptor++) {
8028 Name* key = GetKey(descriptor);
8029 PropertyDetails details = GetDetails(descriptor);
8030 PropertyDetails other_details = other->GetDetails(descriptor);
danno@chromium.orgf005df62013-04-30 16:36:45 +00008031
8032 if (details.type() == FIELD || other_details.type() == FIELD ||
rossberg@chromium.org92597162013-08-23 13:28:00 +00008033 (store_mode == FORCE_FIELD && descriptor == modify_index) ||
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00008034 (details.type() == CONSTANT &&
8035 other_details.type() == CONSTANT &&
danno@chromium.orgf005df62013-04-30 16:36:45 +00008036 GetValue(descriptor) != other->GetValue(descriptor))) {
8037 Representation representation =
8038 details.representation().generalize(other_details.representation());
8039 FieldDescriptor d(key,
8040 current_offset++,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008041 other_details.attributes(),
8042 representation);
danno@chromium.orgf005df62013-04-30 16:36:45 +00008043 result->Set(descriptor, &d, witness);
8044 } else {
8045 result->CopyFrom(descriptor, other, descriptor, witness);
8046 }
8047 }
8048
8049 // |valid| -> |new_size|
8050 for (; descriptor < new_size; descriptor++) {
8051 PropertyDetails details = other->GetDetails(descriptor);
rossberg@chromium.org92597162013-08-23 13:28:00 +00008052 if (details.type() == FIELD ||
8053 (store_mode == FORCE_FIELD && descriptor == modify_index)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00008054 Name* key = other->GetKey(descriptor);
8055 FieldDescriptor d(key,
8056 current_offset++,
8057 details.attributes(),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008058 details.representation());
danno@chromium.orgf005df62013-04-30 16:36:45 +00008059 result->Set(descriptor, &d, witness);
8060 } else {
8061 result->CopyFrom(descriptor, other, descriptor, witness);
8062 }
8063 }
8064
8065 result->Sort();
8066 return result;
8067}
8068
8069
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008070// Checks whether a merge of |other| into |this| would return a copy of |this|.
8071bool DescriptorArray::IsMoreGeneralThan(int verbatim,
8072 int valid,
8073 int new_size,
8074 DescriptorArray* other) {
8075 ASSERT(verbatim <= valid);
8076 ASSERT(valid <= new_size);
8077 if (valid != new_size) return false;
8078
8079 for (int descriptor = verbatim; descriptor < valid; descriptor++) {
8080 PropertyDetails details = GetDetails(descriptor);
8081 PropertyDetails other_details = other->GetDetails(descriptor);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00008082 if (!other_details.representation().fits_into(details.representation())) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008083 return false;
8084 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00008085 if (details.type() == CONSTANT) {
8086 if (other_details.type() != CONSTANT) return false;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00008087 if (GetValue(descriptor) != other->GetValue(descriptor)) return false;
8088 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008089 }
8090
8091 return true;
8092}
8093
8094
verwaest@chromium.org37141392012-05-31 13:27:02 +00008095// We need the whiteness witness since sort will reshuffle the entries in the
8096// descriptor array. If the descriptor array were to be black, the shuffling
8097// would move a slot that was already recorded as pointing into an evacuation
8098// candidate. This would result in missing updates upon evacuation.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008099void DescriptorArray::Sort() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008100 // In-place heap sort.
8101 int len = number_of_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008102 // Reset sorting since the descriptor array might contain invalid pointers.
8103 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008104 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008105 // Index of the last node with children
8106 const int max_parent_index = (len / 2) - 1;
8107 for (int i = max_parent_index; i >= 0; --i) {
8108 int parent_index = i;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008109 const uint32_t parent_hash = GetSortedKey(i)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008110 while (parent_index <= max_parent_index) {
8111 int child_index = 2 * parent_index + 1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008112 uint32_t child_hash = GetSortedKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008113 if (child_index + 1 < len) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008114 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008115 if (right_child_hash > child_hash) {
8116 child_index++;
8117 child_hash = right_child_hash;
8118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008119 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008120 if (child_hash <= parent_hash) break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008121 SwapSortedKeys(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008122 // Now element at child_index could be < its children.
8123 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124 }
8125 }
8126
8127 // Extract elements and create sorted array.
8128 for (int i = len - 1; i > 0; --i) {
8129 // Put max element at the back of the array.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008130 SwapSortedKeys(0, i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008131 // Shift down the new top element.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008132 int parent_index = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008133 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008134 const int max_parent_index = (i / 2) - 1;
8135 while (parent_index <= max_parent_index) {
8136 int child_index = parent_index * 2 + 1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008137 uint32_t child_hash = GetSortedKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008138 if (child_index + 1 < i) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008139 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008140 if (right_child_hash > child_hash) {
8141 child_index++;
8142 child_hash = right_child_hash;
8143 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008144 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008145 if (child_hash <= parent_hash) break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008146 SwapSortedKeys(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008147 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008148 }
8149 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008150 ASSERT(IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008151}
8152
8153
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00008154Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
8155 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
8156 copy->set_getter(pair->getter());
8157 copy->set_setter(pair->setter());
ulan@chromium.org65a89c22012-02-14 11:46:07 +00008158 return copy;
8159}
8160
8161
danno@chromium.org88aa0582012-03-23 15:11:57 +00008162Object* AccessorPair::GetComponent(AccessorComponent component) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008163 Object* accessor = get(component);
8164 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008165}
8166
8167
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008168MaybeObject* DeoptimizationInputData::Allocate(Isolate* isolate,
8169 int deopt_entry_count,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008170 PretenureFlag pretenure) {
8171 ASSERT(deopt_entry_count > 0);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008172 return isolate->heap()->AllocateFixedArray(LengthFor(deopt_entry_count),
8173 pretenure);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008174}
8175
8176
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008177MaybeObject* DeoptimizationOutputData::Allocate(Isolate* isolate,
8178 int number_of_deopt_points,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008179 PretenureFlag pretenure) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008180 if (number_of_deopt_points == 0) return isolate->heap()->empty_fixed_array();
8181 return isolate->heap()->AllocateFixedArray(
8182 LengthOfFixedArray(number_of_deopt_points), pretenure);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008183}
8184
8185
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008186#ifdef DEBUG
8187bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
8188 if (IsEmpty()) return other->IsEmpty();
8189 if (other->IsEmpty()) return false;
8190 if (length() != other->length()) return false;
8191 for (int i = 0; i < length(); ++i) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00008192 if (get(i) != other->get(i)) return false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008193 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00008194 return true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008195}
8196#endif
8197
8198
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008199static bool IsIdentifier(UnicodeCache* cache, Name* name) {
8200 // Checks whether the buffer contains an identifier (no escape).
8201 if (!name->IsString()) return false;
8202 String* string = String::cast(name);
8203 if (string->length() == 0) return false;
8204 ConsStringIteratorOp op;
8205 StringCharacterStream stream(string, &op);
8206 if (!cache->IsIdentifierStart(stream.GetNext())) {
8207 return false;
8208 }
8209 while (stream.HasMore()) {
8210 if (!cache->IsIdentifierPart(stream.GetNext())) {
8211 return false;
8212 }
8213 }
8214 return true;
8215}
8216
8217
8218bool Name::IsCacheable(Isolate* isolate) {
8219 return IsSymbol() ||
8220 IsIdentifier(isolate->unicode_cache(), this) ||
8221 this == isolate->heap()->hidden_string();
8222}
8223
8224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008225bool String::LooksValid() {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008226 if (!GetIsolate()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00008227 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008228}
8229
8230
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008231String::FlatContent String::GetFlatContent() {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008232 ASSERT(!AllowHeapAllocation::IsAllowed());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008233 int length = this->length();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008234 StringShape shape(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00008235 String* string = this;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008236 int offset = 0;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008237 if (shape.representation_tag() == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008238 ConsString* cons = ConsString::cast(string);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008239 if (cons->second()->length() != 0) {
8240 return FlatContent();
8241 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00008242 string = cons->first();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008243 shape = StringShape(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +00008244 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008245 if (shape.representation_tag() == kSlicedStringTag) {
8246 SlicedString* slice = SlicedString::cast(string);
8247 offset = slice->offset();
8248 string = slice->parent();
8249 shape = StringShape(string);
8250 ASSERT(shape.representation_tag() != kConsStringTag &&
8251 shape.representation_tag() != kSlicedStringTag);
8252 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008253 if (shape.encoding_tag() == kOneByteStringTag) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008254 const uint8_t* start;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008255 if (shape.representation_tag() == kSeqStringTag) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008256 start = SeqOneByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008257 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00008258 start = ExternalAsciiString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008259 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008260 return FlatContent(Vector<const uint8_t>(start + offset, length));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008261 } else {
8262 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
8263 const uc16* start;
8264 if (shape.representation_tag() == kSeqStringTag) {
8265 start = SeqTwoByteString::cast(string)->GetChars();
8266 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00008267 start = ExternalTwoByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008268 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008269 return FlatContent(Vector<const uc16>(start + offset, length));
ager@chromium.org7c537e22008-10-16 08:43:32 +00008270 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00008271}
8272
8273
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008274SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8275 RobustnessFlag robust_flag,
8276 int offset,
8277 int length,
8278 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008279 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008280 return SmartArrayPointer<char>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008282 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283
8284 // Negative length means the to the end of the string.
8285 if (length < 0) length = kMaxInt - offset;
8286
8287 // Compute the size of the UTF-8 string. Start at the specified offset.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008288 Access<ConsStringIteratorOp> op(
8289 heap->isolate()->objects_string_iterator());
8290 StringCharacterStream stream(this, op.value(), offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008291 int character_position = offset;
8292 int utf8_bytes = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008293 int last = unibrow::Utf16::kNoPreviousCharacter;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008294 while (stream.HasMore() && character_position++ < offset + length) {
8295 uint16_t character = stream.GetNext();
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008296 utf8_bytes += unibrow::Utf8::Length(character, last);
8297 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008298 }
8299
8300 if (length_return) {
8301 *length_return = utf8_bytes;
8302 }
8303
8304 char* result = NewArray<char>(utf8_bytes + 1);
8305
8306 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008307 stream.Reset(this, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008308 character_position = offset;
8309 int utf8_byte_position = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008310 last = unibrow::Utf16::kNoPreviousCharacter;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008311 while (stream.HasMore() && character_position++ < offset + length) {
8312 uint16_t character = stream.GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00008313 if (allow_nulls == DISALLOW_NULLS && character == 0) {
8314 character = ' ';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00008316 utf8_byte_position +=
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008317 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8318 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008319 }
8320 result[utf8_byte_position] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008321 return SmartArrayPointer<char>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322}
8323
8324
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008325SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8326 RobustnessFlag robust_flag,
8327 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8329}
8330
8331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332const uc16* String::GetTwoByteData(unsigned start) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008333 ASSERT(!IsOneByteRepresentationUnderneath());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008334 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00008336 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 case kExternalStringTag:
8338 return ExternalTwoByteString::cast(this)->
8339 ExternalTwoByteStringGetData(start);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008340 case kSlicedStringTag: {
8341 SlicedString* slice = SlicedString::cast(this);
8342 return slice->parent()->GetTwoByteData(start + slice->offset());
8343 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 case kConsStringTag:
8345 UNREACHABLE();
8346 return NULL;
8347 }
8348 UNREACHABLE();
8349 return NULL;
8350}
8351
8352
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008353SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008355 return SmartArrayPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008356 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008357 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008358
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008359 Access<ConsStringIteratorOp> op(
8360 heap->isolate()->objects_string_iterator());
8361 StringCharacterStream stream(this, op.value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008362
8363 uc16* result = NewArray<uc16>(length() + 1);
8364
8365 int i = 0;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008366 while (stream.HasMore()) {
8367 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008368 result[i++] = character;
8369 }
8370 result[i] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008371 return SmartArrayPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008372}
8373
8374
ager@chromium.org7c537e22008-10-16 08:43:32 +00008375const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376 return reinterpret_cast<uc16*>(
8377 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
8378}
8379
8380
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008381void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008382 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008383 while (current != NULL) {
8384 current->PostGarbageCollection();
8385 current = current->prev_;
8386 }
8387}
8388
8389
8390// Reserve space for statics needing saving and restoring.
8391int Relocatable::ArchiveSpacePerThread() {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008392 return sizeof(Relocatable*); // NOLINT
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008393}
8394
8395
8396// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008397char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008398 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
8399 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008400 return to + ArchiveSpacePerThread();
8401}
8402
8403
8404// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008405char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008406 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008407 return from + ArchiveSpacePerThread();
8408}
8409
8410
8411char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
8412 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
8413 Iterate(v, top);
8414 return thread_storage + ArchiveSpacePerThread();
8415}
8416
8417
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008418void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008420}
8421
8422
8423void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
8424 Relocatable* current = top;
8425 while (current != NULL) {
8426 current->IterateInstance(v);
8427 current = current->prev_;
8428 }
8429}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008430
8431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008432FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
8433 : Relocatable(isolate),
8434 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008435 length_(str->length()) {
8436 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008437}
8438
8439
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
8441 : Relocatable(isolate),
8442 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008443 is_ascii_(true),
8444 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008445 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008446
8447
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008448void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008449 if (str_ == NULL) return;
8450 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008451 ASSERT(str->IsFlat());
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008452 DisallowHeapAllocation no_gc;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00008453 // This does not actually prevent the vector from being relocated later.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008454 String::FlatContent content = str->GetFlatContent();
8455 ASSERT(content.IsFlat());
8456 is_ascii_ = content.IsAscii();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008457 if (is_ascii_) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008458 start_ = content.ToOneByteVector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008459 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008460 start_ = content.ToUC16Vector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008461 }
8462}
8463
8464
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008465String* ConsStringIteratorOp::Operate(String* string,
8466 unsigned* offset_out,
8467 int32_t* type_out,
8468 unsigned* length_out) {
8469 ASSERT(string->IsConsString());
8470 ConsString* cons_string = ConsString::cast(string);
8471 // Set up search data.
8472 root_ = cons_string;
8473 consumed_ = *offset_out;
8474 // Now search.
8475 return Search(offset_out, type_out, length_out);
8476}
8477
8478
8479String* ConsStringIteratorOp::Search(unsigned* offset_out,
8480 int32_t* type_out,
8481 unsigned* length_out) {
8482 ConsString* cons_string = root_;
8483 // Reset the stack, pushing the root string.
8484 depth_ = 1;
8485 maximum_depth_ = 1;
8486 frames_[0] = cons_string;
8487 const unsigned consumed = consumed_;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008488 unsigned offset = 0;
8489 while (true) {
8490 // Loop until the string is found which contains the target offset.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008491 String* string = cons_string->first();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008492 unsigned length = string->length();
8493 int32_t type;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008494 if (consumed < offset + length) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008495 // Target offset is in the left branch.
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008496 // Keep going if we're still in a ConString.
8497 type = string->map()->instance_type();
8498 if ((type & kStringRepresentationMask) == kConsStringTag) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008499 cons_string = ConsString::cast(string);
8500 PushLeft(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008501 continue;
8502 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008503 // Tell the stack we're done decending.
8504 AdjustMaximumDepth();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008505 } else {
8506 // Descend right.
8507 // Update progress through the string.
8508 offset += length;
8509 // Keep going if we're still in a ConString.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008510 string = cons_string->second();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008511 type = string->map()->instance_type();
8512 if ((type & kStringRepresentationMask) == kConsStringTag) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008513 cons_string = ConsString::cast(string);
8514 PushRight(cons_string);
8515 // TODO(dcarney) Add back root optimization.
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008516 continue;
8517 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008518 // Need this to be updated for the current string.
8519 length = string->length();
8520 // Account for the possibility of an empty right leaf.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008521 // This happens only if we have asked for an offset outside the string.
8522 if (length == 0) {
8523 // Reset depth so future operations will return null immediately.
8524 Reset();
8525 return NULL;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008526 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008527 // Tell the stack we're done decending.
8528 AdjustMaximumDepth();
8529 // Pop stack so next iteration is in correct place.
8530 Pop();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008531 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008532 ASSERT(length != 0);
8533 // Adjust return values and exit.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008534 consumed_ = offset + length;
8535 *offset_out = consumed - offset;
8536 *type_out = type;
8537 *length_out = length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008538 return string;
8539 }
8540 UNREACHABLE();
8541 return NULL;
8542}
8543
8544
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008545String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
8546 int32_t* type_out,
8547 unsigned* length_out) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008548 while (true) {
8549 // Tree traversal complete.
8550 if (depth_ == 0) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008551 *blew_stack = false;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008552 return NULL;
8553 }
8554 // We've lost track of higher nodes.
8555 if (maximum_depth_ - depth_ == kStackSize) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008556 *blew_stack = true;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008557 return NULL;
8558 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008559 // Go right.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008560 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
8561 String* string = cons_string->second();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008562 int32_t type = string->map()->instance_type();
8563 if ((type & kStringRepresentationMask) != kConsStringTag) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008564 // Pop stack so next iteration is in correct place.
8565 Pop();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008566 unsigned length = static_cast<unsigned>(string->length());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008567 // Could be a flattened ConsString.
8568 if (length == 0) continue;
8569 *length_out = length;
8570 *type_out = type;
8571 consumed_ += length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008572 return string;
8573 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008574 cons_string = ConsString::cast(string);
8575 // TODO(dcarney) Add back root optimization.
8576 PushRight(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008577 // Need to traverse all the way left.
8578 while (true) {
8579 // Continue left.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008580 string = cons_string->first();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008581 type = string->map()->instance_type();
8582 if ((type & kStringRepresentationMask) != kConsStringTag) {
8583 AdjustMaximumDepth();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008584 unsigned length = static_cast<unsigned>(string->length());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008585 ASSERT(length != 0);
8586 *length_out = length;
8587 *type_out = type;
8588 consumed_ += length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008589 return string;
8590 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008591 cons_string = ConsString::cast(string);
8592 PushLeft(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008593 }
8594 }
8595 UNREACHABLE();
8596 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008597}
8598
8599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600uint16_t ConsString::ConsStringGet(int index) {
8601 ASSERT(index >= 0 && index < this->length());
8602
8603 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00008604 if (second()->length() == 0) {
8605 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008606 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 }
8608
8609 String* string = String::cast(this);
8610
8611 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008612 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00008614 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008615 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008616 string = left;
8617 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008618 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00008619 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008620 }
8621 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008622 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008623 }
8624 }
8625
8626 UNREACHABLE();
8627 return 0;
8628}
8629
8630
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008631uint16_t SlicedString::SlicedStringGet(int index) {
8632 return parent()->Get(offset() + index);
8633}
8634
8635
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008636template <typename sinkchar>
8637void String::WriteToFlat(String* src,
8638 sinkchar* sink,
8639 int f,
8640 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641 String* source = src;
8642 int from = f;
8643 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008645 ASSERT(0 <= from && from <= to && to <= source->length());
8646 switch (StringShape(source).full_representation_tag()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008647 case kOneByteStringTag | kExternalStringTag: {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008648 CopyChars(sink,
erikcorry0ad885c2011-11-21 13:51:57 +00008649 ExternalAsciiString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008650 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651 return;
8652 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008653 case kTwoByteStringTag | kExternalStringTag: {
8654 const uc16* data =
erikcorry0ad885c2011-11-21 13:51:57 +00008655 ExternalTwoByteString::cast(source)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008656 CopyChars(sink,
8657 data + from,
8658 to - from);
8659 return;
8660 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008661 case kOneByteStringTag | kSeqStringTag: {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008662 CopyChars(sink,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008663 SeqOneByteString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008664 to - from);
8665 return;
8666 }
8667 case kTwoByteStringTag | kSeqStringTag: {
8668 CopyChars(sink,
8669 SeqTwoByteString::cast(source)->GetChars() + from,
8670 to - from);
8671 return;
8672 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008673 case kOneByteStringTag | kConsStringTag:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008674 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008675 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00008676 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008677 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00008678 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679 // Right hand side is longer. Recurse over left.
8680 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008681 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008682 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683 from = 0;
8684 } else {
8685 from -= boundary;
8686 }
8687 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00008688 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008689 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008690 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008691 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00008692 String* second = cons_string->second();
ulan@chromium.org812308e2012-02-29 15:58:45 +00008693 // When repeatedly appending to a string, we get a cons string that
8694 // is unbalanced to the left, a list, essentially. We inline the
8695 // common case of sequential ascii right child.
8696 if (to - boundary == 1) {
8697 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008698 } else if (second->IsSeqOneByteString()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00008699 CopyChars(sink + boundary - from,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008700 SeqOneByteString::cast(second)->GetChars(),
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008701 to - boundary);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008702 } else {
8703 WriteToFlat(second,
8704 sink + boundary - from,
8705 0,
8706 to - boundary);
8707 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008708 to = boundary;
8709 }
8710 source = first;
8711 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008712 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008713 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008714 case kOneByteStringTag | kSlicedStringTag:
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008715 case kTwoByteStringTag | kSlicedStringTag: {
8716 SlicedString* slice = SlicedString::cast(source);
8717 unsigned offset = slice->offset();
8718 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8719 return;
8720 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008721 }
8722 }
8723}
8724
8725
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008726// Compares the contents of two strings by reading and comparing
8727// int-sized blocks of characters.
8728template <typename Char>
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008729static inline bool CompareRawStringContents(const Char* const a,
8730 const Char* const b,
8731 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008732 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00008733#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008734 // If this architecture isn't comfortable reading unaligned ints
8735 // then we have to check that the strings are aligned before
8736 // comparing them blockwise.
8737 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008738 uint32_t pa_addr = reinterpret_cast<uint32_t>(a);
8739 uint32_t pb_addr = reinterpret_cast<uint32_t>(b);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008740 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008741#endif
8742 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
8743 int endpoint = length - kStepSize;
8744 // Compare blocks until we reach near the end of the string.
8745 for (; i <= endpoint; i += kStepSize) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008746 uint32_t wa = *reinterpret_cast<const uint32_t*>(a + i);
8747 uint32_t wb = *reinterpret_cast<const uint32_t*>(b + i);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008748 if (wa != wb) {
8749 return false;
8750 }
8751 }
ager@chromium.org9085a012009-05-11 19:22:57 +00008752#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008753 }
8754#endif
8755 // Compare the remaining characters that didn't fit into a block.
8756 for (; i < length; i++) {
8757 if (a[i] != b[i]) {
8758 return false;
8759 }
8760 }
8761 return true;
8762}
8763
8764
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008765template<typename Chars1, typename Chars2>
8766class RawStringComparator : public AllStatic {
8767 public:
8768 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
8769 ASSERT(sizeof(Chars1) != sizeof(Chars2));
8770 for (int i = 0; i < len; i++) {
8771 if (a[i] != b[i]) {
8772 return false;
8773 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00008774 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008775 return true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00008776 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008777};
8778
8779
8780template<>
8781class RawStringComparator<uint16_t, uint16_t> {
8782 public:
8783 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
8784 return CompareRawStringContents(a, b, len);
8785 }
8786};
8787
8788
8789template<>
8790class RawStringComparator<uint8_t, uint8_t> {
8791 public:
8792 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
8793 return CompareRawStringContents(a, b, len);
8794 }
8795};
8796
8797
8798class StringComparator {
8799 class State {
8800 public:
8801 explicit inline State(ConsStringIteratorOp* op)
8802 : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
8803
8804 inline void Init(String* string, unsigned len) {
8805 op_->Reset();
8806 int32_t type = string->map()->instance_type();
8807 String::Visit(string, 0, *this, *op_, type, len);
8808 }
8809
8810 inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
8811 is_one_byte_ = true;
8812 buffer8_ = chars;
8813 length_ = length;
8814 }
8815
8816 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
8817 is_one_byte_ = false;
8818 buffer16_ = chars;
8819 length_ = length;
8820 }
8821
8822 void Advance(unsigned consumed) {
8823 ASSERT(consumed <= length_);
8824 // Still in buffer.
8825 if (length_ != consumed) {
8826 if (is_one_byte_) {
8827 buffer8_ += consumed;
8828 } else {
8829 buffer16_ += consumed;
8830 }
8831 length_ -= consumed;
8832 return;
8833 }
8834 // Advance state.
8835 ASSERT(op_->HasMore());
8836 int32_t type = 0;
8837 unsigned length = 0;
8838 String* next = op_->ContinueOperation(&type, &length);
8839 ASSERT(next != NULL);
8840 ConsStringNullOp null_op;
8841 String::Visit(next, 0, *this, null_op, type, length);
8842 }
8843
8844 ConsStringIteratorOp* const op_;
8845 bool is_one_byte_;
8846 unsigned length_;
8847 union {
8848 const uint8_t* buffer8_;
8849 const uint16_t* buffer16_;
8850 };
danno@chromium.org1fd77d52013-06-07 16:01:45 +00008851
8852 private:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008853 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
8854 };
8855
8856 public:
8857 inline StringComparator(ConsStringIteratorOp* op_1,
8858 ConsStringIteratorOp* op_2)
8859 : state_1_(op_1),
8860 state_2_(op_2) {
8861 }
8862
8863 template<typename Chars1, typename Chars2>
8864 static inline bool Equals(State* state_1, State* state_2, unsigned to_check) {
8865 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
8866 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
8867 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
8868 }
8869
8870 bool Equals(unsigned length, String* string_1, String* string_2) {
8871 ASSERT(length != 0);
8872 state_1_.Init(string_1, length);
8873 state_2_.Init(string_2, length);
8874 while (true) {
8875 unsigned to_check = Min(state_1_.length_, state_2_.length_);
8876 ASSERT(to_check > 0 && to_check <= length);
8877 bool is_equal;
8878 if (state_1_.is_one_byte_) {
8879 if (state_2_.is_one_byte_) {
8880 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
8881 } else {
8882 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
8883 }
8884 } else {
8885 if (state_2_.is_one_byte_) {
8886 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
8887 } else {
8888 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
8889 }
8890 }
8891 // Looping done.
8892 if (!is_equal) return false;
8893 length -= to_check;
8894 // Exit condition. Strings are equal.
8895 if (length == 0) return true;
8896 state_1_.Advance(to_check);
8897 state_2_.Advance(to_check);
8898 }
8899 }
8900
8901 private:
8902 State state_1_;
8903 State state_2_;
8904 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
8905};
ager@chromium.org7c537e22008-10-16 08:43:32 +00008906
8907
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008908bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008909 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008910 int len = length();
8911 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 if (len == 0) return true;
8913
8914 // Fast check: if hash code is computed for both strings
8915 // a fast negative check can be performed.
8916 if (HasHashCode() && other->HasHashCode()) {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00008917#ifdef ENABLE_SLOW_ASSERTS
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008918 if (FLAG_enable_slow_asserts) {
8919 if (Hash() != other->Hash()) {
8920 bool found_difference = false;
8921 for (int i = 0; i < len; i++) {
8922 if (Get(i) != other->Get(i)) {
8923 found_difference = true;
8924 break;
8925 }
8926 }
8927 ASSERT(found_difference);
8928 }
8929 }
8930#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008931 if (Hash() != other->Hash()) return false;
8932 }
8933
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00008934 // We know the strings are both non-empty. Compare the first chars
8935 // before we try to flatten the strings.
8936 if (this->Get(0) != other->Get(0)) return false;
8937
8938 String* lhs = this->TryFlattenGetString();
8939 String* rhs = other->TryFlattenGetString();
8940
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008941 // TODO(dcarney): Compare all types of flat strings with a Visitor.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00008942 if (StringShape(lhs).IsSequentialAscii() &&
8943 StringShape(rhs).IsSequentialAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008944 const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars();
8945 const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008946 return CompareRawStringContents(str1, str2, len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008947 }
8948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008949 Isolate* isolate = GetIsolate();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008950 StringComparator comparator(isolate->objects_string_compare_iterator_a(),
8951 isolate->objects_string_compare_iterator_b());
8952
8953 return comparator.Equals(static_cast<unsigned>(len), lhs, rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008954}
8955
8956
8957bool String::MarkAsUndetectable() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008958 if (StringShape(this).IsInternalized()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008959
8960 Map* map = this->map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008961 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008962 if (map == heap->string_map()) {
8963 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008965 } else if (map == heap->ascii_string_map()) {
8966 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008967 return true;
8968 }
8969 // Rest cannot be marked as undetectable
8970 return false;
8971}
8972
8973
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008974bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008975 int slen = length();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008976 // Can't check exact length equality, but we can check bounds.
8977 int str_len = str.length();
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008978 if (!allow_prefix_match &&
8979 (str_len < slen ||
8980 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008981 return false;
8982 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983 int i;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008984 unsigned remaining_in_str = static_cast<unsigned>(str_len);
8985 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
8986 for (i = 0; i < slen && remaining_in_str > 0; i++) {
8987 unsigned cursor = 0;
8988 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
8989 ASSERT(cursor > 0 && cursor <= remaining_in_str);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008990 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
8991 if (i > slen - 1) return false;
8992 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
8993 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
8994 } else {
8995 if (Get(i) != r) return false;
8996 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008997 utf8_data += cursor;
8998 remaining_in_str -= cursor;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009000 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009001}
9002
9003
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009004bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009005 int slen = length();
9006 if (str.length() != slen) return false;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009007 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009008 FlatContent content = GetFlatContent();
9009 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009010 return CompareChars(content.ToOneByteVector().start(),
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009011 str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009012 }
9013 for (int i = 0; i < slen; i++) {
9014 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009015 }
9016 return true;
9017}
9018
9019
9020bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
9021 int slen = length();
9022 if (str.length() != slen) return false;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00009023 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009024 FlatContent content = GetFlatContent();
9025 if (content.IsTwoByte()) {
9026 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009027 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009028 for (int i = 0; i < slen; i++) {
9029 if (Get(i) != str[i]) return false;
9030 }
9031 return true;
9032}
9033
9034
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009035class IteratingStringHasher: public StringHasher {
9036 public:
9037 static inline uint32_t Hash(String* string, uint32_t seed) {
9038 const unsigned len = static_cast<unsigned>(string->length());
9039 IteratingStringHasher hasher(len, seed);
9040 if (hasher.has_trivial_hash()) {
9041 return hasher.GetHashField();
9042 }
9043 int32_t type = string->map()->instance_type();
9044 ConsStringNullOp null_op;
9045 String::Visit(string, 0, hasher, null_op, type, len);
9046 // Flat strings terminate immediately.
9047 if (hasher.consumed_ == len) {
9048 ASSERT(!string->IsConsString());
9049 return hasher.GetHashField();
9050 }
9051 ASSERT(string->IsConsString());
9052 // This is a ConsString, iterate across it.
9053 ConsStringIteratorOp op;
9054 unsigned offset = 0;
9055 unsigned leaf_length = len;
9056 string = op.Operate(string, &offset, &type, &leaf_length);
9057 while (true) {
9058 ASSERT(hasher.consumed_ < len);
9059 String::Visit(string, 0, hasher, null_op, type, leaf_length);
9060 if (hasher.consumed_ == len) break;
9061 string = op.ContinueOperation(&type, &leaf_length);
9062 // This should be taken care of by the length check.
9063 ASSERT(string != NULL);
9064 }
9065 return hasher.GetHashField();
9066 }
9067 inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
9068 AddCharacters(chars, static_cast<int>(length));
9069 consumed_ += length;
9070 }
9071 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
9072 AddCharacters(chars, static_cast<int>(length));
9073 consumed_ += length;
9074 }
9075
9076 private:
9077 inline IteratingStringHasher(int len, uint32_t seed)
9078 : StringHasher(len, seed),
9079 consumed_(0) {}
9080 unsigned consumed_;
9081 DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
9082};
9083
9084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009086 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009087 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009088
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009089 // Store the hash code in the object.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009090 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009091 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092
9093 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009094 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009095 uint32_t result = field >> kHashShift;
9096 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9097 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098}
9099
9100
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009101bool String::ComputeArrayIndex(uint32_t* index) {
9102 int length = this->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009103 if (length == 0 || length > kMaxArrayIndexSize) return false;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009104 ConsStringIteratorOp op;
9105 StringCharacterStream stream(this, &op);
9106 uint16_t ch = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009107
9108 // If the string begins with a '0' character, it must only consist
9109 // of it to be a legal array index.
9110 if (ch == '0') {
9111 *index = 0;
9112 return length == 1;
9113 }
9114
9115 // Convert string to uint32 array index; character by character.
9116 int d = ch - '0';
9117 if (d < 0 || d > 9) return false;
9118 uint32_t result = d;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009119 while (stream.HasMore()) {
9120 d = stream.GetNext() - '0';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 if (d < 0 || d > 9) return false;
9122 // Check that the new result is below the 32 bit limit.
9123 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
9124 result = (result * 10) + d;
9125 }
9126
9127 *index = result;
9128 return true;
9129}
9130
9131
9132bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009133 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009134 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009135 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009136 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009137 // Isolate the array index form the full hash field.
9138 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009139 return true;
9140 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009141 return ComputeArrayIndex(index);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009142 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143}
9144
9145
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009146Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
9147 int new_size, old_size;
9148 int old_length = string->length();
9149 if (old_length <= new_length) return string;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009150
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009151 if (string->IsSeqOneByteString()) {
9152 old_size = SeqOneByteString::SizeFor(old_length);
9153 new_size = SeqOneByteString::SizeFor(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009154 } else {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009155 ASSERT(string->IsSeqTwoByteString());
9156 old_size = SeqTwoByteString::SizeFor(old_length);
9157 new_size = SeqTwoByteString::SizeFor(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009158 }
9159
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009160 int delta = old_size - new_size;
9161 string->set_length(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009162
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009163 Address start_of_string = string->address();
9164 ASSERT_OBJECT_ALIGNED(start_of_string);
9165 ASSERT_OBJECT_ALIGNED(start_of_string + new_size);
9166
9167 Heap* heap = string->GetHeap();
9168 NewSpace* newspace = heap->new_space();
9169 if (newspace->Contains(start_of_string) &&
9170 newspace->top() == start_of_string + old_size) {
9171 // Last allocated object in new space. Simply lower allocation top.
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00009172 newspace->set_top(start_of_string + new_size);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009173 } else {
9174 // Sizes are pointer size aligned, so that we can use filler objects
9175 // that are a multiple of pointer size.
9176 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009177 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009178 if (Marking::IsBlack(Marking::MarkBitFrom(start_of_string))) {
9179 MemoryChunk::IncrementLiveBytesFromMutator(start_of_string, -delta);
9180 }
9181
9182
9183 if (new_length == 0) return heap->isolate()->factory()->empty_string();
9184 return string;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009185}
9186
9187
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00009188AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object,
9189 bool in_GC) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009190 // Currently, AllocationMemento objects are only allocated immediately
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009191 // after JSArrays in NewSpace, and detecting whether a JSArray has one
9192 // involves carefully checking the object immediately after the JSArray
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009193 // (if there is one) to see if it's an AllocationMemento.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009194 if (FLAG_track_allocation_sites && object->GetHeap()->InNewSpace(object)) {
9195 Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag) +
9196 object->Size();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00009197 Address top;
9198 if (in_GC) {
9199 top = object->GetHeap()->new_space()->FromSpacePageHigh();
9200 } else {
9201 top = object->GetHeap()->NewSpaceTop();
9202 }
9203 if ((ptr_end + AllocationMemento::kSize) <= top) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009204 // There is room in newspace for allocation info. Do we have some?
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009205 Map** possible_allocation_memento_map =
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009206 reinterpret_cast<Map**>(ptr_end);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009207 if (*possible_allocation_memento_map ==
9208 object->GetHeap()->allocation_memento_map()) {
9209 AllocationMemento* memento = AllocationMemento::cast(
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00009210 reinterpret_cast<Object*>(ptr_end + kHeapObjectTag));
hpayer@chromium.org27ce8742013-09-19 09:59:01 +00009211 return memento;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009212 }
9213 }
9214 }
9215 return NULL;
9216}
9217
9218
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009219uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009220 // For array indexes mix the length into the hash as an array index could
9221 // be zero.
9222 ASSERT(length > 0);
9223 ASSERT(length <= String::kMaxArrayIndexSize);
9224 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
9225 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009226
9227 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009228 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009229
9230 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
9231 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
9232 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009233 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009234}
9235
9236
ager@chromium.org7c537e22008-10-16 08:43:32 +00009237uint32_t StringHasher::GetHashField() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009238 if (length_ <= String::kMaxHashCalcLength) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009239 if (is_array_index_) {
9240 return MakeArrayIndexHash(array_index_, length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00009241 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009242 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
9243 String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00009244 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009245 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00009247}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009250uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
9251 uint32_t seed,
9252 int* utf16_length_out) {
9253 int vector_length = chars.length();
9254 // Handle some edge cases
9255 if (vector_length <= 1) {
9256 ASSERT(vector_length == 0 ||
9257 static_cast<uint8_t>(chars.start()[0]) <=
9258 unibrow::Utf8::kMaxOneByteChar);
9259 *utf16_length_out = vector_length;
9260 return HashSequentialString(chars.start(), vector_length, seed);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009261 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009262 // Start with a fake length which won't affect computation.
9263 // It will be updated later.
9264 StringHasher hasher(String::kMaxArrayIndexSize, seed);
9265 unsigned remaining = static_cast<unsigned>(vector_length);
9266 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
9267 int utf16_length = 0;
9268 bool is_index = true;
9269 ASSERT(hasher.is_array_index_);
9270 while (remaining > 0) {
9271 unsigned consumed = 0;
9272 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
9273 ASSERT(consumed > 0 && consumed <= remaining);
9274 stream += consumed;
9275 remaining -= consumed;
9276 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
9277 utf16_length += is_two_characters ? 2 : 1;
9278 // No need to keep hashing. But we do need to calculate utf16_length.
9279 if (utf16_length > String::kMaxHashCalcLength) continue;
9280 if (is_two_characters) {
9281 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
9282 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
9283 hasher.AddCharacter(c1);
9284 hasher.AddCharacter(c2);
9285 if (is_index) is_index = hasher.UpdateIndex(c1);
9286 if (is_index) is_index = hasher.UpdateIndex(c2);
9287 } else {
9288 hasher.AddCharacter(c);
9289 if (is_index) is_index = hasher.UpdateIndex(c);
9290 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009291 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009292 *utf16_length_out = static_cast<int>(utf16_length);
9293 // Must set length here so that hash computation is correct.
9294 hasher.length_ = utf16_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00009295 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009296}
9297
9298
lrn@chromium.org303ada72010-10-27 09:33:13 +00009299MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009300 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009301 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009303 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304}
9305
9306
9307void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009308 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009309 for (int i = 0; i < length; i++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009310 PrintF(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009311 }
9312}
9313
9314
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009315static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) {
9316 int live_enum = map->EnumLength();
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +00009317 if (live_enum == kInvalidEnumCacheSentinel) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009318 live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
9319 }
9320 if (live_enum == 0) return descriptors->ClearEnumCache();
9321
9322 FixedArray* enum_cache = descriptors->GetEnumCache();
9323
9324 int to_trim = enum_cache->length() - live_enum;
9325 if (to_trim <= 0) return;
9326 RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim);
9327
9328 if (!descriptors->HasEnumIndicesCache()) return;
9329 FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
9330 RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim);
9331}
9332
9333
9334static void TrimDescriptorArray(Heap* heap,
9335 Map* map,
9336 DescriptorArray* descriptors,
9337 int number_of_own_descriptors) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00009338 int number_of_descriptors = descriptors->number_of_descriptors_storage();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009339 int to_trim = number_of_descriptors - number_of_own_descriptors;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00009340 if (to_trim == 0) return;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009341
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00009342 RightTrimFixedArray<FROM_GC>(
9343 heap, descriptors, to_trim * DescriptorArray::kDescriptorSize);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009344 descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
9345
9346 if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors);
9347 descriptors->Sort();
9348}
9349
9350
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009351// Clear a possible back pointer in case the transition leads to a dead map.
9352// Return true in case a back pointer has been cleared and false otherwise.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009353static bool ClearBackPointer(Heap* heap, Map* target) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009354 if (Marking::MarkBitFrom(target).Get()) return false;
9355 target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009356 return true;
9357}
9358
9359
9360// TODO(mstarzinger): This method should be moved into MarkCompactCollector,
9361// because it cannot be called from outside the GC and we already have methods
9362// depending on the transitions layout in the GC anyways.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00009363void Map::ClearNonLiveTransitions(Heap* heap) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009364 // If there are no transitions to be cleared, return.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009365 // TODO(verwaest) Should be an assert, otherwise back pointers are not
9366 // properly cleared.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009367 if (!HasTransitionArray()) return;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009368
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009369 TransitionArray* t = transitions();
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00009370 MarkCompactCollector* collector = heap->mark_compact_collector();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009371
9372 int transition_index = 0;
9373
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009374 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009375 bool descriptors_owner_died = false;
9376
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009377 // Compact all live descriptors to the left.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009378 for (int i = 0; i < t->number_of_transitions(); ++i) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009379 Map* target = t->GetTarget(i);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009380 if (ClearBackPointer(heap, target)) {
9381 if (target->instance_descriptors() == descriptors) {
9382 descriptors_owner_died = true;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009383 }
9384 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009385 if (i != transition_index) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00009386 Name* key = t->GetKey(i);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009387 t->SetKey(transition_index, key);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009388 Object** key_slot = t->GetKeySlot(transition_index);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009389 collector->RecordSlot(key_slot, key_slot, key);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00009390 // Target slots do not need to be recorded since maps are not compacted.
9391 t->SetTarget(transition_index, t->GetTarget(i));
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009392 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009393 transition_index++;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009394 }
9395 }
9396
danno@chromium.orgd3c42102013-08-01 16:58:23 +00009397 // If there are no transitions to be cleared, return.
9398 // TODO(verwaest) Should be an assert, otherwise back pointers are not
9399 // properly cleared.
9400 if (transition_index == t->number_of_transitions()) return;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009401
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009402 int number_of_own_descriptors = NumberOfOwnDescriptors();
9403
9404 if (descriptors_owner_died) {
9405 if (number_of_own_descriptors > 0) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009406 TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009407 ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
mstarzinger@chromium.org2ed0d022013-10-17 08:06:21 +00009408 set_owns_descriptors(true);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009409 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009410 ASSERT(descriptors == GetHeap()->empty_descriptor_array());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009411 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009412 }
9413
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009414 int trim = t->number_of_transitions() - transition_index;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009415 if (trim > 0) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009416 RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition()
9417 ? trim : trim * TransitionArray::kTransitionSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009418 }
9419}
9420
9421
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009422int Map::Hash() {
9423 // For performance reasons we only hash the 3 most variable fields of a map:
9424 // constructor, prototype and bit_field2.
9425
9426 // Shift away the tag.
9427 int hash = (static_cast<uint32_t>(
9428 reinterpret_cast<uintptr_t>(constructor())) >> 2);
9429
9430 // XOR-ing the prototype and constructor directly yields too many zero bits
9431 // when the two pointers are close (which is fairly common).
9432 // To avoid this we shift the prototype 4 bits relatively to the constructor.
9433 hash ^= (static_cast<uint32_t>(
9434 reinterpret_cast<uintptr_t>(prototype())) << 2);
9435
9436 return hash ^ (hash >> 16) ^ bit_field2();
9437}
9438
9439
danno@chromium.orgf005df62013-04-30 16:36:45 +00009440static bool CheckEquivalent(Map* first, Map* second) {
9441 return
9442 first->constructor() == second->constructor() &&
9443 first->prototype() == second->prototype() &&
9444 first->instance_type() == second->instance_type() &&
9445 first->bit_field() == second->bit_field() &&
9446 first->bit_field2() == second->bit_field2() &&
9447 first->is_observed() == second->is_observed() &&
9448 first->function_with_prototype() == second->function_with_prototype();
9449}
9450
9451
9452bool Map::EquivalentToForTransition(Map* other) {
9453 return CheckEquivalent(this, other);
9454}
9455
9456
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009457bool Map::EquivalentToForNormalization(Map* other,
9458 PropertyNormalizationMode mode) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00009459 int properties = mode == CLEAR_INOBJECT_PROPERTIES
9460 ? 0 : other->inobject_properties();
9461 return CheckEquivalent(this, other) && inobject_properties() == properties;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009462}
9463
9464
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00009465void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
9466 int first_ptr_offset = OffsetOfElementAt(first_ptr_index());
9467 int last_ptr_offset =
9468 OffsetOfElementAt(first_ptr_index() + count_of_ptr_entries());
9469 v->VisitPointers(
9470 HeapObject::RawField(this, first_ptr_offset),
9471 HeapObject::RawField(this, last_ptr_offset));
9472}
9473
9474
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00009475void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
9476 // Iterate over all fields in the body but take care in dealing with
9477 // the code entry.
9478 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
9479 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
9480 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
9481}
9482
9483
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009484void JSFunction::MarkForLazyRecompilation() {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009485 ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009486 ASSERT(!IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00009487 ASSERT(shared()->allows_lazy_compilation() ||
9488 code()->optimizable());
danno@chromium.org59400602013-08-13 17:09:37 +00009489 ASSERT(!shared()->is_generator());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009490 set_code_no_write_barrier(
9491 GetIsolate()->builtins()->builtin(Builtins::kLazyRecompile));
9492 // No write barrier required, since the builtin is part of the root set.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009493}
9494
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009495
rossberg@chromium.org92597162013-08-23 13:28:00 +00009496void JSFunction::MarkForConcurrentRecompilation() {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009497 ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009498 ASSERT(!IsOptimized());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00009499 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
danno@chromium.org59400602013-08-13 17:09:37 +00009500 ASSERT(!shared()->is_generator());
rossberg@chromium.org92597162013-08-23 13:28:00 +00009501 ASSERT(FLAG_concurrent_recompilation);
9502 if (FLAG_trace_concurrent_recompilation) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009503 PrintF(" ** Marking ");
9504 PrintName();
rossberg@chromium.org92597162013-08-23 13:28:00 +00009505 PrintF(" for concurrent recompilation.\n");
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009506 }
9507 set_code_no_write_barrier(
rossberg@chromium.org92597162013-08-23 13:28:00 +00009508 GetIsolate()->builtins()->builtin(Builtins::kConcurrentRecompile));
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009509 // No write barrier required, since the builtin is part of the root set.
yangguo@chromium.org304cc332012-07-24 07:59:48 +00009510}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009511
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009512
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009513void JSFunction::MarkInRecompileQueue() {
rossberg@chromium.org92597162013-08-23 13:28:00 +00009514 // We can only arrive here via the concurrent-recompilation builtin. If
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009515 // break points were set, the code would point to the lazy-compile builtin.
9516 ASSERT(!GetIsolate()->DebuggerHasBreakPoints());
rossberg@chromium.org92597162013-08-23 13:28:00 +00009517 ASSERT(IsMarkedForConcurrentRecompilation() && !IsOptimized());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009518 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
rossberg@chromium.org92597162013-08-23 13:28:00 +00009519 ASSERT(FLAG_concurrent_recompilation);
9520 if (FLAG_trace_concurrent_recompilation) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009521 PrintF(" ** Queueing ");
9522 PrintName();
rossberg@chromium.org92597162013-08-23 13:28:00 +00009523 PrintF(" for concurrent recompilation.\n");
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009524 }
9525 set_code_no_write_barrier(
9526 GetIsolate()->builtins()->builtin(Builtins::kInRecompileQueue));
9527 // No write barrier required, since the builtin is part of the root set.
9528}
9529
9530
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009531static bool CompileLazyHelper(CompilationInfo* info,
9532 ClearExceptionFlag flag) {
9533 // Compile the source information to a code object.
9534 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
9535 ASSERT(!info->isolate()->has_pending_exception());
9536 bool result = Compiler::CompileLazy(info);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00009537 ASSERT(result != info->isolate()->has_pending_exception());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009538 if (!result && flag == CLEAR_EXCEPTION) {
9539 info->isolate()->clear_pending_exception();
9540 }
9541 return result;
9542}
9543
9544
9545bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
9546 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009547 ASSERT(shared->allows_lazy_compilation_without_context());
9548 CompilationInfoWithZone info(shared);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009549 return CompileLazyHelper(&info, flag);
9550}
9551
9552
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009553void SharedFunctionInfo::AddToOptimizedCodeMap(
9554 Handle<SharedFunctionInfo> shared,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009555 Handle<Context> native_context,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009556 Handle<Code> code,
9557 Handle<FixedArray> literals) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009558 CALL_HEAP_FUNCTION_VOID(
9559 shared->GetIsolate(),
9560 shared->AddToOptimizedCodeMap(*native_context, *code, *literals));
9561}
9562
9563
9564MaybeObject* SharedFunctionInfo::AddToOptimizedCodeMap(Context* native_context,
9565 Code* code,
9566 FixedArray* literals) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009567 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009568 ASSERT(native_context->IsNativeContext());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009569 STATIC_ASSERT(kEntryLength == 3);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009570 Heap* heap = GetHeap();
9571 FixedArray* new_code_map;
9572 Object* value = optimized_code_map();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009573 if (value->IsSmi()) {
9574 // No optimized code map.
9575 ASSERT_EQ(0, Smi::cast(value)->value());
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00009576 // Create 3 entries per context {context, code, literals}.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009577 MaybeObject* maybe = heap->AllocateFixedArray(kInitialLength);
9578 if (!maybe->To(&new_code_map)) return maybe;
9579 new_code_map->set(kEntriesStart + 0, native_context);
9580 new_code_map->set(kEntriesStart + 1, code);
9581 new_code_map->set(kEntriesStart + 2, literals);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009582 } else {
9583 // Copy old map and append one new entry.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009584 FixedArray* old_code_map = FixedArray::cast(value);
9585 ASSERT_EQ(-1, SearchOptimizedCodeMap(native_context));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009586 int old_length = old_code_map->length();
9587 int new_length = old_length + kEntryLength;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009588 MaybeObject* maybe = old_code_map->CopySize(new_length);
9589 if (!maybe->To(&new_code_map)) return maybe;
9590 new_code_map->set(old_length + 0, native_context);
9591 new_code_map->set(old_length + 1, code);
9592 new_code_map->set(old_length + 2, literals);
9593 // Zap the old map for the sake of the heap verifier.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00009594 if (Heap::ShouldZapGarbage()) {
9595 Object** data = old_code_map->data_start();
9596 MemsetPointer(data, heap->the_hole_value(), old_length);
9597 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009598 }
9599#ifdef DEBUG
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009600 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009601 ASSERT(new_code_map->get(i)->IsNativeContext());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009602 ASSERT(new_code_map->get(i + 1)->IsCode());
9603 ASSERT(Code::cast(new_code_map->get(i + 1))->kind() ==
9604 Code::OPTIMIZED_FUNCTION);
9605 ASSERT(new_code_map->get(i + 2)->IsFixedArray());
9606 }
9607#endif
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009608 set_optimized_code_map(new_code_map);
9609 return new_code_map;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009610}
9611
9612
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009613void SharedFunctionInfo::InstallFromOptimizedCodeMap(JSFunction* function,
9614 int index) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009615 ASSERT(index > kEntriesStart);
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009616 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9617 if (!bound()) {
9618 FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
9619 ASSERT(cached_literals != NULL);
9620 function->set_literals(cached_literals);
9621 }
9622 Code* code = Code::cast(code_map->get(index));
9623 ASSERT(code != NULL);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009624 ASSERT(function->context()->native_context() == code_map->get(index - 1));
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009625 function->ReplaceCode(code);
9626}
9627
9628
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009629void SharedFunctionInfo::ClearOptimizedCodeMap() {
9630 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9631
9632 // If the next map link slot is already used then the function was
9633 // enqueued with code flushing and we remove it now.
9634 if (!code_map->get(kNextMapIndex)->IsUndefined()) {
9635 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
9636 flusher->EvictOptimizedCodeMap(this);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009637 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009638
9639 ASSERT(code_map->get(kNextMapIndex)->IsUndefined());
9640 set_optimized_code_map(Smi::FromInt(0));
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009641}
9642
9643
9644void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
9645 const char* reason) {
9646 if (optimized_code_map()->IsSmi()) return;
9647
9648 int i;
9649 bool removed_entry = false;
9650 FixedArray* code_map = FixedArray::cast(optimized_code_map());
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009651 for (i = kEntriesStart; i < code_map->length(); i += kEntryLength) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009652 ASSERT(code_map->get(i)->IsNativeContext());
9653 if (Code::cast(code_map->get(i + 1)) == optimized_code) {
9654 if (FLAG_trace_opt) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009655 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009656 ShortPrint();
9657 PrintF("]\n");
9658 }
9659 removed_entry = true;
9660 break;
9661 }
9662 }
9663 while (i < (code_map->length() - kEntryLength)) {
9664 code_map->set(i, code_map->get(i + kEntryLength));
9665 code_map->set(i + 1, code_map->get(i + 1 + kEntryLength));
9666 code_map->set(i + 2, code_map->get(i + 2 + kEntryLength));
9667 i += kEntryLength;
9668 }
9669 if (removed_entry) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009670 // Always trim even when array is cleared because of heap verifier.
9671 RightTrimFixedArray<FROM_MUTATOR>(GetHeap(), code_map, kEntryLength);
9672 if (code_map->length() == kEntriesStart) {
9673 ClearOptimizedCodeMap();
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009674 }
9675 }
9676}
9677
9678
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009679void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
9680 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9681 ASSERT(shrink_by % kEntryLength == 0);
9682 ASSERT(shrink_by <= code_map->length() - kEntriesStart);
9683 // Always trim even when array is cleared because of heap verifier.
9684 RightTrimFixedArray<FROM_GC>(GetHeap(), code_map, shrink_by);
9685 if (code_map->length() == kEntriesStart) {
9686 ClearOptimizedCodeMap();
9687 }
9688}
9689
9690
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009691bool JSFunction::CompileLazy(Handle<JSFunction> function,
9692 ClearExceptionFlag flag) {
9693 bool result = true;
9694 if (function->shared()->is_compiled()) {
9695 function->ReplaceCode(function->shared()->code());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009696 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009697 ASSERT(function->shared()->allows_lazy_compilation());
9698 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009699 result = CompileLazyHelper(&info, flag);
9700 ASSERT(!result || function->is_compiled());
9701 }
9702 return result;
9703}
9704
9705
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009706Handle<Code> JSFunction::CompileOsr(Handle<JSFunction> function,
9707 BailoutId osr_ast_id,
9708 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009709 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009710 info.SetOptimizing(osr_ast_id);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009711 if (CompileLazyHelper(&info, flag)) {
9712 // TODO(titzer): don't install the OSR code.
9713 // ASSERT(function->code() != *info.code());
9714 return info.code();
9715 } else {
9716 return Handle<Code>::null();
9717 }
9718}
9719
9720
9721bool JSFunction::CompileOptimized(Handle<JSFunction> function,
9722 ClearExceptionFlag flag) {
9723 CompilationInfoWithZone info(function);
9724 info.SetOptimizing(BailoutId::None());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009725 return CompileLazyHelper(&info, flag);
9726}
9727
9728
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009729bool JSFunction::EnsureCompiled(Handle<JSFunction> function,
9730 ClearExceptionFlag flag) {
9731 return function->is_compiled() || CompileLazy(function, flag);
9732}
9733
9734
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009735void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009736 if (object->IsGlobalObject()) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009737
9738 // Make sure prototypes are fast objects and their maps have the bit set
9739 // so they remain fast.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009740 if (!object->HasFastProperties()) {
9741 TransformToFastProperties(object, 0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009742 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009743}
9744
9745
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009746static MUST_USE_RESULT MaybeObject* CacheInitialJSArrayMaps(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009747 Context* native_context, Map* initial_map) {
9748 // Replace all of the cached initial array maps in the native context with
9749 // the appropriate transitioned elements kind maps.
9750 Heap* heap = native_context->GetHeap();
9751 MaybeObject* maybe_maps =
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009752 heap->AllocateFixedArrayWithHoles(kElementsKindCount, TENURED);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009753 FixedArray* maps;
9754 if (!maybe_maps->To(&maps)) return maybe_maps;
9755
9756 Map* current_map = initial_map;
9757 ElementsKind kind = current_map->elements_kind();
9758 ASSERT(kind == GetInitialFastElementsKind());
9759 maps->set(kind, current_map);
9760 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
9761 i < kFastElementsKindCount; ++i) {
9762 Map* new_map;
9763 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
danno@chromium.orgf005df62013-04-30 16:36:45 +00009764 if (current_map->HasElementsTransition()) {
9765 new_map = current_map->elements_transition_map();
9766 ASSERT(new_map->elements_kind() == next_kind);
9767 } else {
9768 MaybeObject* maybe_new_map =
9769 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
9770 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9771 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009772 maps->set(next_kind, new_map);
9773 current_map = new_map;
9774 }
9775 native_context->set_js_array_maps(maps);
9776 return initial_map;
9777}
9778
9779
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009780Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
9781 Handle<Map> initial_map) {
9782 CALL_HEAP_FUNCTION(native_context->GetIsolate(),
9783 CacheInitialJSArrayMaps(*native_context, *initial_map),
9784 Object);
9785}
9786
9787
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009788void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
9789 Handle<Object> value) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00009790 ASSERT(value->IsJSReceiver());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009791
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00009792 // First some logic for the map of the prototype to make sure it is in fast
9793 // mode.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009794 if (value->IsJSObject()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009795 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009796 }
9797
9798 // Now some logic for the maps of the objects that are created by using this
9799 // function as a constructor.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009800 if (function->has_initial_map()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009801 // If the function has allocated the initial map replace it with a
9802 // copy containing the new prototype. Also complete any in-object
9803 // slack tracking that is in progress at this point because it is
9804 // still tracking the old copy.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009805 if (function->shared()->IsInobjectSlackTrackingInProgress()) {
9806 function->shared()->CompleteInobjectSlackTracking();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009807 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009808 Handle<Map> new_map = Map::Copy(handle(function->initial_map()));
9809 new_map->set_prototype(*value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009810
9811 // If the function is used as the global Array function, cache the
9812 // initial map (and transitioned versions) in the native context.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009813 Context* native_context = function->context()->native_context();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009814 Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX);
9815 if (array_function->IsJSFunction() &&
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009816 *function == JSFunction::cast(array_function)) {
9817 CacheInitialJSArrayMaps(handle(native_context), new_map);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009818 }
9819
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009820 function->set_initial_map(*new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009821 } else {
9822 // Put the value in the initial map field until an initial map is
9823 // needed. At that point, a new initial map is created and the
9824 // prototype is put into the initial map where it belongs.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009825 function->set_prototype_or_initial_map(*value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009827 function->GetHeap()->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009828}
9829
9830
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009831void JSFunction::SetPrototype(Handle<JSFunction> function,
9832 Handle<Object> value) {
9833 ASSERT(function->should_have_prototype());
9834 Handle<Object> construct_prototype = value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835
danno@chromium.org88aa0582012-03-23 15:11:57 +00009836 // If the value is not a JSReceiver, store the value in the map's
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 // constructor field so it can be accessed. Also, set the prototype
9838 // used for constructing objects to the original object prototype.
9839 // See ECMA-262 13.2.2.
danno@chromium.org88aa0582012-03-23 15:11:57 +00009840 if (!value->IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009841 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009842 // Remove map transitions because they point to maps with a
9843 // different prototype.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009844 Handle<Map> new_map = Map::Copy(handle(function->map()));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00009845
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009846 function->set_map(*new_map);
9847 new_map->set_constructor(*value);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009848 new_map->set_non_instance_prototype(true);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009849 Isolate* isolate = new_map->GetIsolate();
9850 construct_prototype = handle(
9851 isolate->context()->native_context()->initial_object_prototype(),
9852 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 } else {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009854 function->map()->set_non_instance_prototype(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009855 }
9856
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009857 return SetInstancePrototype(function, construct_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009858}
9859
9860
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009861void JSFunction::RemovePrototype() {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009862 Context* native_context = context()->native_context();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009863 Map* no_prototype_map = shared()->is_classic_mode()
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009864 ? native_context->function_without_prototype_map()
9865 : native_context->strict_mode_function_without_prototype_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009866
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009867 if (map() == no_prototype_map) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009868
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009869 ASSERT(map() == (shared()->is_classic_mode()
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009870 ? native_context->function_map()
9871 : native_context->strict_mode_function_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009872
9873 set_map(no_prototype_map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009874 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009875}
9876
9877
verwaest@chromium.org057bd502013-11-06 12:03:29 +00009878void JSFunction::EnsureHasInitialMap(Handle<JSFunction> function) {
9879 if (function->has_initial_map()) return;
9880 Isolate* isolate = function->GetIsolate();
9881
9882 // First create a new map with the size and number of in-object properties
9883 // suggested by the function.
9884 InstanceType instance_type;
9885 int instance_size;
9886 int in_object_properties;
9887 if (function->shared()->is_generator()) {
9888 instance_type = JS_GENERATOR_OBJECT_TYPE;
9889 instance_size = JSGeneratorObject::kSize;
9890 in_object_properties = 0;
9891 } else {
9892 instance_type = JS_OBJECT_TYPE;
9893 instance_size = function->shared()->CalculateInstanceSize();
9894 in_object_properties = function->shared()->CalculateInObjectProperties();
9895 }
9896 Handle<Map> map = isolate->factory()->NewMap(instance_type, instance_size);
9897
9898 // Fetch or allocate prototype.
9899 Handle<Object> prototype;
9900 if (function->has_instance_prototype()) {
9901 prototype = handle(function->instance_prototype(), isolate);
9902 } else {
9903 prototype = isolate->factory()->NewFunctionPrototype(function);
9904 }
9905 map->set_inobject_properties(in_object_properties);
9906 map->set_unused_property_fields(in_object_properties);
9907 map->set_prototype(*prototype);
9908 ASSERT(map->has_fast_object_elements());
9909
9910 if (!function->shared()->is_generator()) {
9911 function->shared()->StartInobjectSlackTracking(*map);
9912 }
9913
9914 // Finally link initial map and constructor function.
9915 function->set_initial_map(*map);
9916 map->set_constructor(*function);
9917}
9918
9919
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009920void JSFunction::SetInstanceClassName(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009921 shared()->set_instance_class_name(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922}
9923
9924
whesse@chromium.org023421e2010-12-21 12:19:12 +00009925void JSFunction::PrintName(FILE* out) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009926 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00009927 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009928}
9929
9930
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009931Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
9932 return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
ager@chromium.org236ad962008-09-25 09:45:57 +00009933}
9934
9935
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009936// The filter is a pattern that matches function names in this way:
9937// "*" all; the default
9938// "-" all but the top-level function
9939// "-name" all but the function "name"
9940// "" only the top-level function
9941// "name" only the function "name"
9942// "name*" only functions starting with "name"
9943bool JSFunction::PassesFilter(const char* raw_filter) {
9944 if (*raw_filter == '*') return true;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009945 String* name = shared()->DebugName();
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009946 Vector<const char> filter = CStrVector(raw_filter);
9947 if (filter.length() == 0) return name->length() == 0;
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +00009948 if (filter[0] == '-') {
9949 if (filter.length() == 1) {
9950 return (name->length() != 0);
9951 } else if (!name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
9952 return true;
9953 }
9954 } else if (name->IsUtf8EqualTo(filter)) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009955 return true;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009956 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009957 if (filter[filter.length() - 1] == '*' &&
9958 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
9959 return true;
9960 }
9961 return false;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009962}
9963
9964
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00009965MaybeObject* Oddball::Initialize(Heap* heap,
9966 const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009967 Object* to_number,
9968 byte kind) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009969 String* internalized_to_string;
9970 { MaybeObject* maybe_string =
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00009971 heap->InternalizeUtf8String(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009972 CStrVector(to_string));
9973 if (!maybe_string->To(&internalized_to_string)) return maybe_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009974 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009975 set_to_string(internalized_to_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009977 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 return this;
9979}
9980
9981
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00009982String* SharedFunctionInfo::DebugName() {
9983 Object* n = name();
9984 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
9985 return String::cast(n);
9986}
9987
9988
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989bool SharedFunctionInfo::HasSourceCode() {
9990 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009991 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009992}
9993
9994
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00009995Handle<Object> SharedFunctionInfo::GetSourceCode() {
9996 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
9997 Handle<String> source(String::cast(Script::cast(script())->source()));
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00009998 return GetIsolate()->factory()->NewSubString(
9999 source, start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000}
10001
10002
machenbach@chromium.org0cc09502013-11-13 12:20:55 +000010003bool SharedFunctionInfo::IsInlineable() {
10004 // Check that the function has a script associated with it.
10005 if (!script()->IsScript()) return false;
10006 if (optimization_disabled()) return false;
10007 // If we never ran this (unlikely) then lets try to optimize it.
10008 if (code()->kind() != Code::FUNCTION) return true;
10009 return code()->optimizable();
10010}
10011
10012
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010013int SharedFunctionInfo::SourceSize() {
10014 return end_position() - start_position();
10015}
10016
10017
sgjesse@chromium.org911335c2009-08-19 12:59:44 +000010018int SharedFunctionInfo::CalculateInstanceSize() {
10019 int instance_size =
10020 JSObject::kHeaderSize +
10021 expected_nof_properties() * kPointerSize;
10022 if (instance_size > JSObject::kMaxInstanceSize) {
10023 instance_size = JSObject::kMaxInstanceSize;
10024 }
10025 return instance_size;
10026}
10027
10028
10029int SharedFunctionInfo::CalculateInObjectProperties() {
10030 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
10031}
10032
10033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034// Support function for printing the source code to a StringStream
10035// without any allocation in the heap.
10036void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
10037 int max_length) {
10038 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010039 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010040 accumulator->Add("<No Source>");
10041 return;
10042 }
10043
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010044 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010045 // Don't use String::cast because we don't want more assertion errors while
10046 // we are already creating a stack dump.
10047 String* script_source =
10048 reinterpret_cast<String*>(Script::cast(script())->source());
10049
10050 if (!script_source->LooksValid()) {
10051 accumulator->Add("<Invalid Source>");
10052 return;
10053 }
10054
10055 if (!is_toplevel()) {
10056 accumulator->Add("function ");
10057 Object* name = this->name();
10058 if (name->IsString() && String::cast(name)->length() > 0) {
10059 accumulator->PrintName(name);
10060 }
10061 }
10062
10063 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010064 if (len <= max_length || max_length < 0) {
10065 accumulator->Put(script_source, start_position(), end_position());
10066 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067 accumulator->Put(script_source,
10068 start_position(),
10069 start_position() + max_length);
10070 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071 }
10072}
10073
10074
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010075static bool IsCodeEquivalent(Code* code, Code* recompiled) {
10076 if (code->instruction_size() != recompiled->instruction_size()) return false;
10077 ByteArray* code_relocation = code->relocation_info();
10078 ByteArray* recompiled_relocation = recompiled->relocation_info();
10079 int length = code_relocation->length();
10080 if (length != recompiled_relocation->length()) return false;
10081 int compare = memcmp(code_relocation->GetDataStartAddress(),
10082 recompiled_relocation->GetDataStartAddress(),
10083 length);
10084 return compare == 0;
10085}
10086
10087
10088void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
10089 ASSERT(!has_deoptimization_support());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010090 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010091 Code* code = this->code();
10092 if (IsCodeEquivalent(code, recompiled)) {
10093 // Copy the deoptimization data from the recompiled code.
10094 code->set_deoptimization_data(recompiled->deoptimization_data());
10095 code->set_has_deoptimization_support(true);
10096 } else {
10097 // TODO(3025757): In case the recompiled isn't equivalent to the
10098 // old code, we have to replace it. We should try to avoid this
10099 // altogether because it flushes valuable type feedback by
10100 // effectively resetting all IC state.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +000010101 ReplaceCode(recompiled);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010102 }
10103 ASSERT(has_deoptimization_support());
10104}
10105
10106
danno@chromium.org59400602013-08-13 17:09:37 +000010107void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010108 // Disable optimization for the shared function info and mark the
10109 // code as non-optimizable. The marker on the shared function info
10110 // is there because we flush non-optimized code thereby loosing the
10111 // non-optimizable information for the code. When the code is
10112 // regenerated and set on the shared function info it is marked as
10113 // non-optimizable if optimization is disabled for the shared
10114 // function info.
10115 set_optimization_disabled(true);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000010116 set_bailout_reason(reason);
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010117 // Code should be the lazy compilation stub or else unoptimized. If the
10118 // latter, disable optimization for the code too.
10119 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
10120 if (code()->kind() == Code::FUNCTION) {
10121 code()->set_optimizable(false);
10122 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000010123 PROFILE(GetIsolate(),
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000010124 LogExistingFunction(Handle<SharedFunctionInfo>(this),
10125 Handle<Code>(code())));
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010126 if (FLAG_trace_opt) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000010127 PrintF("[disabled optimization for ");
10128 ShortPrint();
danno@chromium.org59400602013-08-13 17:09:37 +000010129 PrintF(", reason: %s]\n", GetBailoutReason(reason));
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010130 }
10131}
10132
10133
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010134bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
10135 ASSERT(!id.IsNone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010136 Code* unoptimized = code();
10137 DeoptimizationOutputData* data =
10138 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
10139 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
10140 USE(ignore);
10141 return true; // Return true if there was no ASSERT.
10142}
10143
10144
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010145void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
10146 ASSERT(!IsInobjectSlackTrackingInProgress());
10147
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010148 if (!FLAG_clever_optimizations) return;
10149
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010150 // Only initiate the tracking the first time.
10151 if (live_objects_may_exist()) return;
10152 set_live_objects_may_exist(true);
10153
10154 // No tracking during the snapshot construction phase.
10155 if (Serializer::enabled()) return;
10156
10157 if (map->unused_property_fields() == 0) return;
10158
10159 // Nonzero counter is a leftover from the previous attempt interrupted
10160 // by GC, keep it.
10161 if (construction_count() == 0) {
10162 set_construction_count(kGenerousAllocationCount);
10163 }
10164 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010165 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010166 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010167 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010168 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010169}
10170
10171
10172// Called from GC, hence reinterpret_cast and unchecked accessors.
10173void SharedFunctionInfo::DetachInitialMap() {
10174 Map* map = reinterpret_cast<Map*>(initial_map());
10175
10176 // Make the map remember to restore the link if it survives the GC.
10177 map->set_bit_field2(
10178 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
10179
10180 // Undo state changes made by StartInobjectTracking (except the
10181 // construction_count). This way if the initial map does not survive the GC
10182 // then StartInobjectTracking will be called again the next time the
10183 // constructor is called. The countdown will continue and (possibly after
10184 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010185 Heap* heap = map->GetHeap();
danno@chromium.org72204d52012-10-31 10:02:10 +000010186 set_initial_map(heap->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010187 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010188 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010189 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010190 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010191 // It is safe to clear the flag: it will be set again if the map is live.
10192 set_live_objects_may_exist(false);
10193}
10194
10195
10196// Called from GC, hence reinterpret_cast and unchecked accessors.
10197void SharedFunctionInfo::AttachInitialMap(Map* map) {
10198 map->set_bit_field2(
10199 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
10200
10201 // Resume inobject slack tracking.
10202 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010203 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010204 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010205 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010206 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010207 // The map survived the gc, so there may be objects referencing it.
10208 set_live_objects_may_exist(true);
10209}
10210
10211
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010212void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
10213 code()->ClearInlineCaches();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010214 set_ic_age(new_ic_age);
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +000010215 if (code()->kind() == Code::FUNCTION) {
10216 code()->set_profiler_ticks(0);
10217 if (optimization_disabled() &&
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000010218 opt_count() >= FLAG_max_opt_count) {
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +000010219 // Re-enable optimizations if they were disabled due to opt_count limit.
10220 set_optimization_disabled(false);
10221 code()->set_optimizable(true);
10222 }
10223 set_opt_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010224 set_deopt_count(0);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010225 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010226}
10227
10228
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010229static void GetMinInobjectSlack(Map* map, void* data) {
10230 int slack = map->unused_property_fields();
10231 if (*reinterpret_cast<int*>(data) > slack) {
10232 *reinterpret_cast<int*>(data) = slack;
10233 }
10234}
10235
10236
10237static void ShrinkInstanceSize(Map* map, void* data) {
10238 int slack = *reinterpret_cast<int*>(data);
10239 map->set_inobject_properties(map->inobject_properties() - slack);
10240 map->set_unused_property_fields(map->unused_property_fields() - slack);
10241 map->set_instance_size(map->instance_size() - slack * kPointerSize);
10242
10243 // Visitor id might depend on the instance size, recalculate it.
10244 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
10245}
10246
10247
10248void SharedFunctionInfo::CompleteInobjectSlackTracking() {
10249 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
10250 Map* map = Map::cast(initial_map());
10251
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010252 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010253 set_initial_map(heap->undefined_value());
10254 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010255 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010256 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010257 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010258
10259 int slack = map->unused_property_fields();
10260 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
10261 if (slack != 0) {
10262 // Resize the initial map and all maps in its transition tree.
10263 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010264
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010265 // Give the correct expected_nof_properties to initial maps created later.
10266 ASSERT(expected_nof_properties() >= slack);
10267 set_expected_nof_properties(expected_nof_properties() - slack);
10268 }
10269}
10270
10271
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010272int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context) {
10273 ASSERT(native_context->IsNativeContext());
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +000010274 if (!FLAG_cache_optimized_code) return -1;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010275 Object* value = optimized_code_map();
10276 if (!value->IsSmi()) {
10277 FixedArray* optimized_code_map = FixedArray::cast(value);
10278 int length = optimized_code_map->length();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +000010279 for (int i = kEntriesStart; i < length; i += kEntryLength) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010280 if (optimized_code_map->get(i) == native_context) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010281 return i + 1;
10282 }
10283 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000010284 if (FLAG_trace_opt) {
10285 PrintF("[didn't find optimized code in optimized code map for ");
10286 ShortPrint();
10287 PrintF("]\n");
10288 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010289 }
10290 return -1;
10291}
10292
10293
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010294#define DECLARE_TAG(ignore1, name, ignore2) name,
10295const char* const VisitorSynchronization::kTags[
10296 VisitorSynchronization::kNumberOfSyncTags] = {
10297 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10298};
10299#undef DECLARE_TAG
10300
10301
10302#define DECLARE_TAG(ignore1, ignore2, name) name,
10303const char* const VisitorSynchronization::kTagNames[
10304 VisitorSynchronization::kNumberOfSyncTags] = {
10305 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10306};
10307#undef DECLARE_TAG
10308
10309
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010311 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010312 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
10313 Object* old_target = target;
10314 VisitPointer(&target);
10315 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316}
10317
10318
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010319void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
10320 ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
10321 Object* stub = rinfo->code_age_stub();
10322 if (stub) {
10323 VisitPointer(&stub);
10324 }
10325}
10326
10327
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000010328void ObjectVisitor::VisitCodeEntry(Address entry_address) {
10329 Object* code = Code::GetObjectFromEntryAddress(entry_address);
10330 Object* old_code = code;
10331 VisitPointer(&code);
10332 if (code != old_code) {
10333 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
10334 }
10335}
10336
10337
danno@chromium.org41728482013-06-12 22:31:22 +000010338void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
10339 ASSERT(rinfo->rmode() == RelocInfo::CELL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010340 Object* cell = rinfo->target_cell();
10341 Object* old_cell = cell;
10342 VisitPointer(&cell);
10343 if (cell != old_cell) {
danno@chromium.org41728482013-06-12 22:31:22 +000010344 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010345 }
10346}
10347
10348
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010350 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
10351 rinfo->IsPatchedReturnSequence()) ||
10352 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
10353 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010354 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
10355 Object* old_target = target;
10356 VisitPointer(&target);
10357 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358}
10359
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010360
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010361void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
10362 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010363 Object* p = rinfo->target_object();
10364 VisitPointer(&p);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010365}
10366
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010367
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010368void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010369 Address p = rinfo->target_reference();
10370 VisitExternalReference(&p);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010371}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010372
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010373
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010374void Code::InvalidateRelocation() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010375 set_relocation_info(GetHeap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010376}
10377
10378
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010379void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
10381 it.rinfo()->apply(delta);
10382 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010383 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384}
10385
10386
10387void Code::CopyFrom(const CodeDesc& desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010388 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
10389
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 // copy code
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010391 CopyBytes(instruction_start(), desc.buffer,
10392 static_cast<size_t>(desc.instr_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010393
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 // copy reloc info
danno@chromium.orgc99cd482013-03-21 15:26:42 +000010395 CopyBytes(relocation_start(),
10396 desc.buffer + desc.buffer_size - desc.reloc_size,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010397 static_cast<size_t>(desc.reloc_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010398
10399 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010400 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010401 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +000010402 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
danno@chromium.org41728482013-06-12 22:31:22 +000010403 RelocInfo::ModeMask(RelocInfo::CELL) |
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010404 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 RelocInfo::kApplyMask;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010406 // Needed to find target_object and runtime_entry on X64
10407 Assembler* origin = desc.origin;
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010408 AllowDeferredHandleDereference embedding_raw_address;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010410 RelocInfo::Mode mode = it.rinfo()->rmode();
10411 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010412 Handle<Object> p = it.rinfo()->target_object_handle(origin);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010413 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
danno@chromium.org41728482013-06-12 22:31:22 +000010414 } else if (mode == RelocInfo::CELL) {
10415 Handle<Cell> cell = it.rinfo()->target_cell_handle();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010416 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
ager@chromium.org236ad962008-09-25 09:45:57 +000010417 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010418 // rewrite code handles in inline cache targets to direct
10419 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010420 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010421 Code* code = Code::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010422 it.rinfo()->set_target_address(code->instruction_start(),
10423 SKIP_WRITE_BARRIER);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010424 } else if (RelocInfo::IsRuntimeEntry(mode)) {
10425 Address p = it.rinfo()->target_runtime_entry(origin);
10426 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER);
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010427 } else if (mode == RelocInfo::CODE_AGE_SEQUENCE) {
10428 Handle<Object> p = it.rinfo()->code_age_stub_handle(origin);
10429 Code* code = Code::cast(*p);
10430 it.rinfo()->set_code_age_stub(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010431 } else {
10432 it.rinfo()->apply(delta);
10433 }
10434 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010435 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010436}
10437
10438
10439// Locate the source position which is closest to the address in the code. This
10440// is using the source position information embedded in the relocation info.
10441// The position returned is relative to the beginning of the script where the
10442// source for this function is found.
10443int Code::SourcePosition(Address pc) {
10444 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +000010445 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010446 // Run through all the relocation info to find the best matching source
10447 // position. All the code needs to be considered as the sequence of the
10448 // instructions in the code does not necessarily follow the same order as the
10449 // source.
10450 RelocIterator it(this, RelocInfo::kPositionMask);
10451 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010452 // Only look at positions after the current pc.
10453 if (it.rinfo()->pc() < pc) {
10454 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010455
10456 int dist = static_cast<int>(pc - it.rinfo()->pc());
10457 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +000010458 // If this position is closer than the current candidate or if it has the
10459 // same distance as the current candidate and the position is higher then
10460 // this position is the new candidate.
10461 if ((dist < distance) ||
10462 (dist == distance && pos > position)) {
10463 position = pos;
10464 distance = dist;
10465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466 }
10467 it.next();
10468 }
10469 return position;
10470}
10471
10472
10473// Same as Code::SourcePosition above except it only looks for statement
10474// positions.
10475int Code::SourceStatementPosition(Address pc) {
10476 // First find the position as close as possible using all position
10477 // information.
10478 int position = SourcePosition(pc);
10479 // Now find the closest statement position before the position.
10480 int statement_position = 0;
10481 RelocIterator it(this, RelocInfo::kPositionMask);
10482 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010483 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010484 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010485 if (statement_position < p && p <= position) {
10486 statement_position = p;
10487 }
10488 }
10489 it.next();
10490 }
10491 return statement_position;
10492}
10493
10494
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010495SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010496 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010497 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010498}
10499
10500
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010501Object* Code::FindNthObject(int n, Map* match_map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010502 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010503 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010504 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10505 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10506 RelocInfo* info = it.rinfo();
10507 Object* object = info->target_object();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010508 if (object->IsHeapObject()) {
10509 if (HeapObject::cast(object)->map() == match_map) {
10510 if (--n == 0) return object;
10511 }
10512 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010513 }
10514 return NULL;
10515}
10516
10517
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010518Map* Code::FindFirstMap() {
10519 Object* result = FindNthObject(1, GetHeap()->meta_map());
10520 return (result != NULL) ? Map::cast(result) : NULL;
10521}
10522
10523
10524void Code::ReplaceNthObject(int n,
10525 Map* match_map,
10526 Object* replace_with) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000010527 ASSERT(is_inline_cache_stub() || is_handler());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010528 DisallowHeapAllocation no_allocation;
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010529 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10530 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10531 RelocInfo* info = it.rinfo();
10532 Object* object = info->target_object();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010533 if (object->IsHeapObject()) {
10534 if (HeapObject::cast(object)->map() == match_map) {
10535 if (--n == 0) {
10536 info->set_target_object(replace_with);
10537 return;
10538 }
10539 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010540 }
10541 }
10542 UNREACHABLE();
10543}
10544
10545
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010546void Code::FindAllMaps(MapHandleList* maps) {
10547 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010548 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010549 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10550 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10551 RelocInfo* info = it.rinfo();
10552 Object* object = info->target_object();
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +000010553 if (object->IsMap()) maps->Add(handle(Map::cast(object)));
10554 }
10555}
10556
10557
10558void Code::FindAllTypes(TypeHandleList* types) {
10559 ASSERT(is_inline_cache_stub());
10560 DisallowHeapAllocation no_allocation;
10561 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10562 Isolate* isolate = GetIsolate();
10563 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10564 RelocInfo* info = it.rinfo();
10565 Object* object = info->target_object();
10566 if (object->IsMap()) {
10567 Handle<Map> map(Map::cast(object));
10568 types->Add(handle(IC::MapToType(map), isolate));
10569 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010570 }
10571}
10572
10573
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010574void Code::ReplaceFirstMap(Map* replace_with) {
10575 ReplaceNthObject(1, GetHeap()->meta_map(), replace_with);
10576}
10577
10578
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010579Code* Code::FindFirstHandler() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010580 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010581 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010582 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10583 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10584 RelocInfo* info = it.rinfo();
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010585 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10586 if (code->kind() == Code::HANDLER) return code;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010587 }
10588 return NULL;
10589}
10590
10591
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010592bool Code::FindHandlers(CodeHandleList* code_list, int length) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010593 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010594 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010595 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10596 int i = 0;
10597 for (RelocIterator it(this, mask); !it.done(); it.next()) {
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010598 if (i == length) return true;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010599 RelocInfo* info = it.rinfo();
10600 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010601 // IC stubs with handlers never contain non-handler code objects before
10602 // handler targets.
10603 if (code->kind() != Code::HANDLER) break;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010604 code_list->Add(Handle<Code>(code));
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010605 i++;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010606 }
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010607 return i == length;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010608}
10609
10610
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010611Name* Code::FindFirstName() {
10612 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010613 DisallowHeapAllocation no_allocation;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010614 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10615 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10616 RelocInfo* info = it.rinfo();
10617 Object* object = info->target_object();
10618 if (object->IsName()) return Name::cast(object);
10619 }
10620 return NULL;
10621}
10622
10623
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010624void Code::ReplaceNthCell(int n, Cell* replace_with) {
10625 ASSERT(is_inline_cache_stub());
10626 DisallowHeapAllocation no_allocation;
10627 int mask = RelocInfo::ModeMask(RelocInfo::CELL);
10628 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10629 RelocInfo* info = it.rinfo();
10630 if (--n == 0) {
10631 info->set_target_cell(replace_with);
10632 return;
10633 }
10634 }
10635 UNREACHABLE();
10636}
10637
10638
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010639void Code::ClearInlineCaches() {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000010640 ClearInlineCaches(NULL);
10641}
10642
10643
10644void Code::ClearInlineCaches(Code::Kind kind) {
10645 ClearInlineCaches(&kind);
10646}
10647
10648
10649void Code::ClearInlineCaches(Code::Kind* kind) {
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010650 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10651 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
10652 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
10653 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
10654 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10655 RelocInfo* info = it.rinfo();
10656 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
10657 if (target->is_inline_cache_stub()) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000010658 if (kind == NULL || *kind == target->kind()) {
10659 IC::Clear(this->GetIsolate(), info->pc());
10660 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010661 }
10662 }
10663}
10664
10665
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010666void Code::ClearTypeFeedbackCells(Heap* heap) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010667 if (kind() != FUNCTION) return;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010668 Object* raw_info = type_feedback_info();
10669 if (raw_info->IsTypeFeedbackInfo()) {
10670 TypeFeedbackCells* type_feedback_cells =
10671 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
10672 for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000010673 Cell* cell = type_feedback_cells->GetCell(i);
danno@chromium.orgbee51992013-07-10 14:57:15 +000010674 // Don't clear AllocationSites
10675 Object* value = cell->value();
10676 if (value == NULL || !value->IsAllocationSite()) {
10677 cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
10678 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010679 }
10680 }
10681}
10682
10683
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010684BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
10685 DisallowHeapAllocation no_gc;
10686 ASSERT(kind() == FUNCTION);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010687 BackEdgeTable back_edges(this, &no_gc);
10688 for (uint32_t i = 0; i < back_edges.length(); i++) {
10689 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010690 }
10691 return BailoutId::None();
10692}
10693
10694
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010695void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +000010696 PatchPlatformCodeAge(isolate, sequence, kNoAgeCodeAge, NO_MARKING_PARITY);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010697}
10698
10699
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010700void Code::MarkCodeAsExecuted(byte* sequence, Isolate* isolate) {
10701 PatchPlatformCodeAge(isolate, sequence, kExecutedOnceCodeAge,
10702 NO_MARKING_PARITY);
10703}
10704
10705
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010706static Code::Age EffectiveAge(Code::Age age) {
10707 if (age == Code::kNotExecutedCodeAge) {
10708 // Treat that's never been executed as old immediately.
10709 age = Code::kIsOldCodeAge;
10710 } else if (age == Code::kExecutedOnceCodeAge) {
10711 // Pre-age code that has only been executed once.
10712 age = Code::kPreAgedCodeAge;
10713 }
10714 return age;
10715}
10716
10717
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010718void Code::MakeOlder(MarkingParity current_parity) {
10719 byte* sequence = FindCodeAgeSequence();
10720 if (sequence != NULL) {
10721 Age age;
10722 MarkingParity code_parity;
10723 GetCodeAgeAndParity(sequence, &age, &code_parity);
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010724 age = EffectiveAge(age);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010725 if (age != kLastCodeAge && code_parity != current_parity) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010726 PatchPlatformCodeAge(GetIsolate(),
10727 sequence,
10728 static_cast<Age>(age + 1),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010729 current_parity);
10730 }
10731 }
10732}
10733
10734
10735bool Code::IsOld() {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010736 return GetAge() >= kIsOldCodeAge;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010737}
10738
10739
10740byte* Code::FindCodeAgeSequence() {
10741 return FLAG_age_code &&
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010742 prologue_offset() != Code::kPrologueOffsetNotSet &&
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010743 (kind() == OPTIMIZED_FUNCTION ||
10744 (kind() == FUNCTION && !has_debug_break_slots()))
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000010745 ? instruction_start() + prologue_offset()
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010746 : NULL;
10747}
10748
10749
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010750Code::Age Code::GetAge() {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010751 return EffectiveAge(GetRawAge());
10752}
10753
10754
10755Code::Age Code::GetRawAge() {
danno@chromium.org41728482013-06-12 22:31:22 +000010756 byte* sequence = FindCodeAgeSequence();
10757 if (sequence == NULL) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010758 return kNoAgeCodeAge;
danno@chromium.org41728482013-06-12 22:31:22 +000010759 }
10760 Age age;
10761 MarkingParity parity;
10762 GetCodeAgeAndParity(sequence, &age, &parity);
10763 return age;
10764}
10765
10766
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010767void Code::GetCodeAgeAndParity(Code* code, Age* age,
10768 MarkingParity* parity) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010769 Isolate* isolate = code->GetIsolate();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010770 Builtins* builtins = isolate->builtins();
10771 Code* stub = NULL;
10772#define HANDLE_CODE_AGE(AGE) \
10773 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
10774 if (code == stub) { \
10775 *age = k##AGE##CodeAge; \
10776 *parity = EVEN_MARKING_PARITY; \
10777 return; \
10778 } \
10779 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10780 if (code == stub) { \
10781 *age = k##AGE##CodeAge; \
10782 *parity = ODD_MARKING_PARITY; \
10783 return; \
10784 }
10785 CODE_AGE_LIST(HANDLE_CODE_AGE)
10786#undef HANDLE_CODE_AGE
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010787 stub = *builtins->MarkCodeAsExecutedOnce();
10788 if (code == stub) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010789 *age = kNotExecutedCodeAge;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010790 *parity = NO_MARKING_PARITY;
10791 return;
10792 }
10793 stub = *builtins->MarkCodeAsExecutedTwice();
10794 if (code == stub) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000010795 *age = kExecutedOnceCodeAge;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010796 *parity = NO_MARKING_PARITY;
10797 return;
10798 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010799 UNREACHABLE();
10800}
10801
10802
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010803Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010804 Builtins* builtins = isolate->builtins();
10805 switch (age) {
10806#define HANDLE_CODE_AGE(AGE) \
10807 case k##AGE##CodeAge: { \
10808 Code* stub = parity == EVEN_MARKING_PARITY \
10809 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
10810 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10811 return stub; \
10812 }
10813 CODE_AGE_LIST(HANDLE_CODE_AGE)
10814#undef HANDLE_CODE_AGE
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +000010815 case kNotExecutedCodeAge: {
10816 ASSERT(parity == NO_MARKING_PARITY);
10817 return *builtins->MarkCodeAsExecutedOnce();
10818 }
10819 case kExecutedOnceCodeAge: {
10820 ASSERT(parity == NO_MARKING_PARITY);
10821 return *builtins->MarkCodeAsExecutedTwice();
10822 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010823 default:
10824 UNREACHABLE();
10825 break;
10826 }
10827 return NULL;
10828}
10829
10830
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000010831void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010832 const char* last_comment = NULL;
10833 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
10834 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
10835 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10836 RelocInfo* info = it.rinfo();
10837 if (info->rmode() == RelocInfo::COMMENT) {
10838 last_comment = reinterpret_cast<const char*>(info->data());
danno@chromium.orgaefd6072013-05-14 14:11:47 +000010839 } else if (last_comment != NULL) {
10840 if ((bailout_id == Deoptimizer::GetDeoptimizationId(
10841 GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
10842 (bailout_id == Deoptimizer::GetDeoptimizationId(
10843 GetIsolate(), info->target_address(), Deoptimizer::SOFT))) {
10844 CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000010845 PrintF(out, " %s\n", last_comment);
danno@chromium.orgaefd6072013-05-14 14:11:47 +000010846 return;
10847 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010848 }
10849 }
10850}
10851
10852
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000010853bool Code::CanDeoptAt(Address pc) {
10854 DeoptimizationInputData* deopt_data =
10855 DeoptimizationInputData::cast(deoptimization_data());
10856 Address code_start_address = instruction_start();
10857 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
10858 if (deopt_data->Pc(i)->value() == -1) continue;
10859 Address address = code_start_address + deopt_data->Pc(i)->value();
10860 if (address == pc) return true;
10861 }
10862 return false;
10863}
10864
10865
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010866// Identify kind of code.
10867const char* Code::Kind2String(Kind kind) {
10868 switch (kind) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010869#define CASE(name) case name: return #name;
10870 CODE_KIND_LIST(CASE)
10871#undef CASE
10872 case NUMBER_OF_KINDS: break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010873 }
10874 UNREACHABLE();
10875 return NULL;
10876}
10877
10878
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010879#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010880
whesse@chromium.org023421e2010-12-21 12:19:12 +000010881void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010882 disasm::NameConverter converter;
10883 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +000010884 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010885 if (0 == deopt_count) return;
10886
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010887 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010888 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010889 for (int i = 0; i < deopt_count; i++) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010890 PrintF(out, "%6d %6d %6d %6d",
10891 i,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010892 AstId(i).ToInt(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010893 ArgumentsStackHeight(i)->value(),
10894 Pc(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010895
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010896 if (!FLAG_print_code_verbose) {
10897 PrintF(out, "\n");
10898 continue;
10899 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010900 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010901 int translation_index = TranslationIndex(i)->value();
10902 TranslationIterator iterator(TranslationByteArray(), translation_index);
10903 Translation::Opcode opcode =
10904 static_cast<Translation::Opcode>(iterator.Next());
10905 ASSERT(Translation::BEGIN == opcode);
10906 int frame_count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010907 int jsframe_count = iterator.Next();
10908 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
10909 Translation::StringFor(opcode),
10910 frame_count,
10911 jsframe_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010912
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010913 while (iterator.HasNext() &&
10914 Translation::BEGIN !=
10915 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
10916 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
10917
10918 switch (opcode) {
10919 case Translation::BEGIN:
10920 UNREACHABLE();
10921 break;
10922
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010923 case Translation::JS_FRAME: {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010924 int ast_id = iterator.Next();
10925 int function_id = iterator.Next();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010926 unsigned height = iterator.Next();
fschneider@chromium.org1805e212011-09-05 10:49:12 +000010927 PrintF(out, "{ast_id=%d, function=", ast_id);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010928 if (function_id != Translation::kSelfLiteralId) {
10929 Object* function = LiteralArray()->get(function_id);
10930 JSFunction::cast(function)->PrintName(out);
10931 } else {
10932 PrintF(out, "<self>");
10933 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010934 PrintF(out, ", height=%u}", height);
10935 break;
10936 }
10937
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010938 case Translation::COMPILED_STUB_FRAME: {
10939 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
10940 PrintF(out, "{kind=%d}", stub_kind);
10941 break;
10942 }
10943
ulan@chromium.org967e2702012-02-28 09:49:15 +000010944 case Translation::ARGUMENTS_ADAPTOR_FRAME:
10945 case Translation::CONSTRUCT_STUB_FRAME: {
10946 int function_id = iterator.Next();
10947 JSFunction* function =
10948 JSFunction::cast(LiteralArray()->get(function_id));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010949 unsigned height = iterator.Next();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010950 PrintF(out, "{function=");
10951 function->PrintName(out);
10952 PrintF(out, ", height=%u}", height);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010953 break;
10954 }
10955
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000010956 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010957 case Translation::SETTER_STUB_FRAME: {
10958 int function_id = iterator.Next();
10959 JSFunction* function =
10960 JSFunction::cast(LiteralArray()->get(function_id));
10961 PrintF(out, "{function=");
10962 function->PrintName(out);
10963 PrintF(out, "}");
10964 break;
10965 }
10966
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010967 case Translation::REGISTER: {
10968 int reg_code = iterator.Next();
10969 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
10970 break;
10971 }
10972
10973 case Translation::INT32_REGISTER: {
10974 int reg_code = iterator.Next();
10975 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
10976 break;
10977 }
10978
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010979 case Translation::UINT32_REGISTER: {
10980 int reg_code = iterator.Next();
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010981 PrintF(out, "{input=%s (unsigned)}",
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010982 converter.NameOfCPURegister(reg_code));
10983 break;
10984 }
10985
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010986 case Translation::DOUBLE_REGISTER: {
10987 int reg_code = iterator.Next();
10988 PrintF(out, "{input=%s}",
10989 DoubleRegister::AllocationIndexToString(reg_code));
10990 break;
10991 }
10992
10993 case Translation::STACK_SLOT: {
10994 int input_slot_index = iterator.Next();
10995 PrintF(out, "{input=%d}", input_slot_index);
10996 break;
10997 }
10998
10999 case Translation::INT32_STACK_SLOT: {
11000 int input_slot_index = iterator.Next();
11001 PrintF(out, "{input=%d}", input_slot_index);
11002 break;
11003 }
11004
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011005 case Translation::UINT32_STACK_SLOT: {
11006 int input_slot_index = iterator.Next();
11007 PrintF(out, "{input=%d (unsigned)}", input_slot_index);
11008 break;
11009 }
11010
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011011 case Translation::DOUBLE_STACK_SLOT: {
11012 int input_slot_index = iterator.Next();
11013 PrintF(out, "{input=%d}", input_slot_index);
11014 break;
11015 }
11016
11017 case Translation::LITERAL: {
11018 unsigned literal_index = iterator.Next();
11019 PrintF(out, "{literal_id=%u}", literal_index);
11020 break;
11021 }
11022
danno@chromium.org59400602013-08-13 17:09:37 +000011023 case Translation::DUPLICATED_OBJECT: {
11024 int object_index = iterator.Next();
11025 PrintF(out, "{object_index=%d}", object_index);
11026 break;
11027 }
11028
11029 case Translation::ARGUMENTS_OBJECT:
11030 case Translation::CAPTURED_OBJECT: {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011031 int args_length = iterator.Next();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000011032 PrintF(out, "{length=%d}", args_length);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011033 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011034 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011035 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011036 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011037 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011038 }
11039}
11040
11041
whesse@chromium.org023421e2010-12-21 12:19:12 +000011042void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
11043 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011044 this->DeoptPoints());
11045 if (this->DeoptPoints() == 0) return;
11046
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011047 PrintF(out, "%6s %8s %s\n", "ast id", "pc", "state");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011048 for (int i = 0; i < this->DeoptPoints(); i++) {
11049 int pc_and_state = this->PcAndState(i)->value();
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011050 PrintF(out, "%6d %8d %s\n",
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000011051 this->AstId(i).ToInt(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011052 FullCodeGenerator::PcField::decode(pc_and_state),
11053 FullCodeGenerator::State2String(
11054 FullCodeGenerator::StateField::decode(pc_and_state)));
11055 }
11056}
11057
whesse@chromium.org7b260152011-06-20 15:33:18 +000011058
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011059const char* Code::ICState2String(InlineCacheState state) {
11060 switch (state) {
11061 case UNINITIALIZED: return "UNINITIALIZED";
11062 case PREMONOMORPHIC: return "PREMONOMORPHIC";
11063 case MONOMORPHIC: return "MONOMORPHIC";
11064 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000011065 case POLYMORPHIC: return "POLYMORPHIC";
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011066 case MEGAMORPHIC: return "MEGAMORPHIC";
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011067 case GENERIC: return "GENERIC";
yangguo@chromium.org9768bf12013-01-11 14:51:07 +000011068 case DEBUG_STUB: return "DEBUG_STUB";
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011069 }
11070 UNREACHABLE();
11071 return NULL;
11072}
11073
11074
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000011075const char* Code::StubType2String(StubType type) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011076 switch (type) {
11077 case NORMAL: return "NORMAL";
11078 case FIELD: return "FIELD";
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000011079 case CONSTANT: return "CONSTANT";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011080 case CALLBACKS: return "CALLBACKS";
11081 case INTERCEPTOR: return "INTERCEPTOR";
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011082 case TRANSITION: return "TRANSITION";
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000011083 case NONEXISTENT: return "NONEXISTENT";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011084 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000011085 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011086 return NULL;
11087}
11088
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011089
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011090void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000011091 PrintF(out, "extra_ic_state = ");
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011092 const char* name = NULL;
11093 switch (kind) {
11094 case CALL_IC:
11095 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
11096 name = "STRING_INDEX_OUT_OF_BOUNDS";
11097 }
11098 break;
11099 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011100 case KEYED_STORE_IC:
11101 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011102 name = "STRICT";
11103 }
11104 break;
11105 default:
11106 break;
11107 }
11108 if (name != NULL) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000011109 PrintF(out, "%s\n", name);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011110 } else {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000011111 PrintF(out, "%d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011112 }
11113}
11114
11115
whesse@chromium.org023421e2010-12-21 12:19:12 +000011116void Code::Disassemble(const char* name, FILE* out) {
11117 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011118 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011119 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000011120 PrintExtraICState(out, kind(), needs_extended_extra_ic_state(kind()) ?
11121 extended_extra_ic_state() : extra_ic_state());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011122 if (ic_state() == MONOMORPHIC) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000011123 PrintF(out, "type = %s\n", StubType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011124 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011125 if (is_call_stub() || is_keyed_call_stub()) {
11126 PrintF(out, "argc = %d\n", arguments_count());
11127 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000011128 if (is_compare_ic_stub()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011129 ASSERT(major_key() == CodeStub::CompareIC);
11130 CompareIC::State left_state, right_state, handler_state;
11131 Token::Value op;
11132 ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state,
11133 &handler_state, &op);
11134 PrintF(out, "compare_state = %s*%s -> %s\n",
11135 CompareIC::GetStateName(left_state),
11136 CompareIC::GetStateName(right_state),
11137 CompareIC::GetStateName(handler_state));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011138 PrintF(out, "compare_operation = %s\n", Token::Name(op));
11139 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011140 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011141 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011142 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011143 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011144 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011145 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011146 }
mads.s.ager31e71382008-08-13 09:32:07 +000011147
whesse@chromium.org023421e2010-12-21 12:19:12 +000011148 PrintF(out, "Instructions (size = %d)\n", instruction_size());
11149 Disassembler::Decode(out, this);
11150 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +000011151
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011152 if (kind() == FUNCTION) {
11153 DeoptimizationOutputData* data =
11154 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +000011155 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011156 } else if (kind() == OPTIMIZED_FUNCTION) {
11157 DeoptimizationInputData* data =
11158 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +000011159 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011160 }
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011161 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011162
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +000011163 if (is_crankshafted()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011164 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +000011165 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011166 for (unsigned i = 0; i < table.length(); i++) {
11167 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +000011168 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011169 table.PrintEntry(i, out);
whesse@chromium.org023421e2010-12-21 12:19:12 +000011170 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011171 SafepointEntry entry = table.GetEntry(i);
11172 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
11173 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011174 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011175 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011176 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011177 if (entry.argument_count() > 0) {
11178 PrintF(out, " argc: %d", entry.argument_count());
11179 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000011180 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011181 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000011182 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011183 } else if (kind() == FUNCTION) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011184 unsigned offset = back_edge_table_offset();
11185 // If there is no back edge table, the "table start" will be at or after
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011186 // (due to alignment) the end of the instruction stream.
11187 if (static_cast<int>(offset) < instruction_size()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011188 DisallowHeapAllocation no_gc;
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011189 BackEdgeTable back_edges(this, &no_gc);
danno@chromium.org59400602013-08-13 17:09:37 +000011190
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011191 PrintF(out, "Back edges (size = %u)\n", back_edges.length());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011192 PrintF(out, "ast_id pc_offset loop_depth\n");
danno@chromium.org59400602013-08-13 17:09:37 +000011193
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011194 for (uint32_t i = 0; i < back_edges.length(); i++) {
11195 PrintF(out, "%6d %9u %10u\n", back_edges.ast_id(i).ToInt(),
11196 back_edges.pc_offset(i),
11197 back_edges.loop_depth(i));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011198 }
danno@chromium.org59400602013-08-13 17:09:37 +000011199
whesse@chromium.org023421e2010-12-21 12:19:12 +000011200 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011201 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000011202#ifdef OBJECT_PRINT
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +000011203 if (!type_feedback_info()->IsUndefined()) {
11204 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(out);
11205 PrintF(out, "\n");
11206 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000011207#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011208 }
11209
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011210 PrintF(out, "RelocInfo (size = %d)\n", relocation_size());
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000011211 for (RelocIterator it(this); !it.done(); it.next()) {
11212 it.rinfo()->Print(GetIsolate(), out);
11213 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000011214 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +000011215}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000011216#endif // ENABLE_DISASSEMBLER
11217
11218
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011219Handle<FixedArray> JSObject::SetFastElementsCapacityAndLength(
11220 Handle<JSObject> object,
11221 int capacity,
11222 int length,
11223 SetFastElementsCapacitySmiMode smi_mode) {
11224 CALL_HEAP_FUNCTION(
11225 object->GetIsolate(),
11226 object->SetFastElementsCapacityAndLength(capacity, length, smi_mode),
11227 FixedArray);
11228}
11229
11230
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011231MaybeObject* JSObject::SetFastElementsCapacityAndLength(
11232 int capacity,
11233 int length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011234 SetFastElementsCapacitySmiMode smi_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011235 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011236 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011237 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011238
whesse@chromium.org7b260152011-06-20 15:33:18 +000011239 // Allocate a new fast elements backing store.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011240 FixedArray* new_elements;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011241 MaybeObject* maybe = heap->AllocateUninitializedFixedArray(capacity);
11242 if (!maybe->To(&new_elements)) return maybe;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011243
jkummerow@chromium.orgf3eae902012-05-24 16:42:53 +000011244 ElementsKind elements_kind = GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011245 ElementsKind new_elements_kind;
11246 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
11247 // or if it's allowed and the old elements array contained only SMIs.
11248 bool has_fast_smi_elements =
11249 (smi_mode == kForceSmiElements) ||
11250 ((smi_mode == kAllowSmiElements) && HasFastSmiElements());
11251 if (has_fast_smi_elements) {
11252 if (IsHoleyElementsKind(elements_kind)) {
11253 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
11254 } else {
11255 new_elements_kind = FAST_SMI_ELEMENTS;
11256 }
11257 } else {
11258 if (IsHoleyElementsKind(elements_kind)) {
11259 new_elements_kind = FAST_HOLEY_ELEMENTS;
11260 } else {
11261 new_elements_kind = FAST_ELEMENTS;
11262 }
11263 }
11264 FixedArrayBase* old_elements = elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011265 ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011266 MaybeObject* maybe_obj =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011267 accessor->CopyElements(this, new_elements, elements_kind);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011268 if (maybe_obj->IsFailure()) return maybe_obj;
11269
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011270 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011271 Map* new_map = map();
11272 if (new_elements_kind != elements_kind) {
11273 MaybeObject* maybe =
11274 GetElementsTransitionMap(GetIsolate(), new_elements_kind);
11275 if (!maybe->To(&new_map)) return maybe;
11276 }
11277 ValidateElements();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011278 set_map_and_elements(new_map, new_elements);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011279
11280 // Transition through the allocation site as well if present.
11281 maybe_obj = UpdateAllocationSite(new_elements_kind);
11282 if (maybe_obj->IsFailure()) return maybe_obj;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011283 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011284 FixedArray* parameter_map = FixedArray::cast(old_elements);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011285 parameter_map->set(1, new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011286 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011287
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011288 if (FLAG_trace_elements_transitions) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011289 PrintElementsTransition(stdout, elements_kind, old_elements,
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011290 GetElementsKind(), new_elements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011291 }
11292
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011293 if (IsJSArray()) {
11294 JSArray::cast(this)->set_length(Smi::FromInt(length));
11295 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000011296 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011297}
11298
11299
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000011300bool Code::IsWeakEmbeddedObject(Kind kind, Object* object) {
11301 if (kind != Code::OPTIMIZED_FUNCTION) return false;
11302
11303 if (object->IsMap()) {
11304 return Map::cast(object)->CanTransition() &&
11305 FLAG_collect_maps &&
11306 FLAG_weak_embedded_maps_in_optimized_code;
11307 }
11308
11309 if (object->IsJSObject()) {
11310 return FLAG_weak_embedded_objects_in_optimized_code;
11311 }
11312
11313 return false;
11314}
11315
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011316
11317void JSObject::SetFastDoubleElementsCapacityAndLength(Handle<JSObject> object,
11318 int capacity,
11319 int length) {
11320 CALL_HEAP_FUNCTION_VOID(
11321 object->GetIsolate(),
11322 object->SetFastDoubleElementsCapacityAndLength(capacity, length));
11323}
11324
11325
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011326MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
11327 int capacity,
11328 int length) {
11329 Heap* heap = GetHeap();
11330 // We should never end in here with a pixel or external array.
11331 ASSERT(!HasExternalArrayElements());
11332
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011333 FixedArrayBase* elems;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011334 { MaybeObject* maybe_obj =
11335 heap->AllocateUninitializedFixedDoubleArray(capacity);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011336 if (!maybe_obj->To(&elems)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011337 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011338
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011339 ElementsKind elements_kind = GetElementsKind();
11340 ElementsKind new_elements_kind = elements_kind;
11341 if (IsHoleyElementsKind(elements_kind)) {
11342 new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
11343 } else {
11344 new_elements_kind = FAST_DOUBLE_ELEMENTS;
11345 }
11346
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011347 Map* new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011348 { MaybeObject* maybe_obj =
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011349 GetElementsTransitionMap(heap->isolate(), new_elements_kind);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011350 if (!maybe_obj->To(&new_map)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011351 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011352
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011353 FixedArrayBase* old_elements = elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011354 ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011355 { MaybeObject* maybe_obj =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011356 accessor->CopyElements(this, elems, elements_kind);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011357 if (maybe_obj->IsFailure()) return maybe_obj;
11358 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011359 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011360 ValidateElements();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011361 set_map_and_elements(new_map, elems);
11362 } else {
11363 FixedArray* parameter_map = FixedArray::cast(old_elements);
11364 parameter_map->set(1, elems);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011365 }
11366
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011367 if (FLAG_trace_elements_transitions) {
11368 PrintElementsTransition(stdout, elements_kind, old_elements,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011369 GetElementsKind(), elems);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011370 }
11371
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011372 if (IsJSArray()) {
11373 JSArray::cast(this)->set_length(Smi::FromInt(length));
11374 }
11375
11376 return this;
11377}
11378
11379
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011380MaybeObject* JSArray::Initialize(int capacity, int length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011381 ASSERT(capacity >= 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011382 return GetHeap()->AllocateJSArrayStorage(this, length, capacity,
11383 INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011384}
11385
11386
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011387void JSArray::Expand(int required_size) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011388 GetIsolate()->factory()->SetElementsCapacityAndLength(
11389 Handle<JSArray>(this), required_size, required_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011390}
11391
11392
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011393// Returns false if the passed-in index is marked non-configurable,
11394// which will cause the ES5 truncation operation to halt, and thus
11395// no further old values need be collected.
11396static bool GetOldValue(Isolate* isolate,
11397 Handle<JSObject> object,
11398 uint32_t index,
11399 List<Handle<Object> >* old_values,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011400 List<uint32_t>* indices) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011401 PropertyAttributes attributes = object->GetLocalElementAttribute(index);
11402 ASSERT(attributes != ABSENT);
11403 if (attributes == DONT_DELETE) return false;
11404 old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011405 ? Object::GetElement(isolate, object, index)
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011406 : Handle<Object>::cast(isolate->factory()->the_hole_value()));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011407 indices->Add(index);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011408 return true;
11409}
11410
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011411static void EnqueueSpliceRecord(Handle<JSArray> object,
11412 uint32_t index,
11413 Handle<JSArray> deleted,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011414 uint32_t add_count) {
11415 Isolate* isolate = object->GetIsolate();
11416 HandleScope scope(isolate);
11417 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011418 Handle<Object> add_count_object =
11419 isolate->factory()->NewNumberFromUint(add_count);
11420
11421 Handle<Object> args[] =
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011422 { object, index_object, deleted, add_count_object };
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011423
11424 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000011425 Execution::Call(isolate,
11426 Handle<JSFunction>(isolate->observers_enqueue_splice()),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011427 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
11428 &threw);
11429 ASSERT(!threw);
11430}
11431
11432
11433static void BeginPerformSplice(Handle<JSArray> object) {
11434 Isolate* isolate = object->GetIsolate();
11435 HandleScope scope(isolate);
11436 Handle<Object> args[] = { object };
11437
11438 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000011439 Execution::Call(isolate,
11440 Handle<JSFunction>(isolate->observers_begin_perform_splice()),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011441 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
11442 &threw);
11443 ASSERT(!threw);
11444}
11445
11446
11447static void EndPerformSplice(Handle<JSArray> object) {
11448 Isolate* isolate = object->GetIsolate();
11449 HandleScope scope(isolate);
11450 Handle<Object> args[] = { object };
11451
11452 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000011453 Execution::Call(isolate,
11454 Handle<JSFunction>(isolate->observers_end_perform_splice()),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011455 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
11456 &threw);
11457 ASSERT(!threw);
11458}
11459
11460
ricow@chromium.org7ad65222011-12-19 12:13:11 +000011461MaybeObject* JSArray::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011462 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +000011463 ASSERT(AllowsSetElementsLength());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011464 if (!(FLAG_harmony_observation && map()->is_observed()))
11465 return GetElementsAccessor()->SetLength(this, len);
11466
11467 Isolate* isolate = GetIsolate();
11468 HandleScope scope(isolate);
11469 Handle<JSArray> self(this);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011470 List<uint32_t> indices;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011471 List<Handle<Object> > old_values;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011472 Handle<Object> old_length_handle(self->length(), isolate);
11473 Handle<Object> new_length_handle(len, isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011474 uint32_t old_length = 0;
11475 CHECK(old_length_handle->ToArrayIndex(&old_length));
11476 uint32_t new_length = 0;
11477 if (!new_length_handle->ToArrayIndex(&new_length))
11478 return Failure::InternalError();
11479
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011480 static const PropertyAttributes kNoAttrFilter = NONE;
11481 int num_elements = self->NumberOfLocalElements(kNoAttrFilter);
11482 if (num_elements > 0) {
11483 if (old_length == static_cast<uint32_t>(num_elements)) {
11484 // Simple case for arrays without holes.
11485 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
11486 if (!GetOldValue(isolate, self, i, &old_values, &indices)) break;
11487 }
11488 } else {
11489 // For sparse arrays, only iterate over existing elements.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011490 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over
11491 // the to-be-removed indices twice.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011492 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
11493 self->GetLocalElementKeys(*keys, kNoAttrFilter);
11494 while (num_elements-- > 0) {
11495 uint32_t index = NumberToUint32(keys->get(num_elements));
11496 if (index < new_length) break;
11497 if (!GetOldValue(isolate, self, index, &old_values, &indices)) break;
11498 }
11499 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011500 }
11501
11502 MaybeObject* result =
11503 self->GetElementsAccessor()->SetLength(*self, *new_length_handle);
11504 Handle<Object> hresult;
11505 if (!result->ToHandle(&hresult, isolate)) return result;
11506
11507 CHECK(self->length()->ToArrayIndex(&new_length));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011508 if (old_length == new_length) return *hresult;
11509
11510 BeginPerformSplice(self);
11511
11512 for (int i = 0; i < indices.length(); ++i) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011513 JSObject::EnqueueChangeRecord(
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011514 self, "delete", isolate->factory()->Uint32ToString(indices[i]),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011515 old_values[i]);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011516 }
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011517 JSObject::EnqueueChangeRecord(
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011518 self, "update", isolate->factory()->length_string(),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011519 old_length_handle);
11520
11521 EndPerformSplice(self);
11522
11523 uint32_t index = Min(old_length, new_length);
11524 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
11525 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
11526 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011527 if (delete_count > 0) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011528 for (int i = indices.length() - 1; i >= 0; i--) {
11529 JSObject::SetElement(deleted, indices[i] - index, old_values[i], NONE,
11530 kNonStrictMode);
11531 }
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011532
11533 SetProperty(deleted, isolate->factory()->length_string(),
11534 isolate->factory()->NewNumberFromUint(delete_count),
11535 NONE, kNonStrictMode);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011536 }
11537
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011538 EnqueueSpliceRecord(self, index, deleted, add_count);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011539
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011540 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011541}
11542
11543
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011544Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
11545 Handle<Object> prototype) {
11546 FixedArray* cache = map->GetPrototypeTransitions();
11547 int number_of_transitions = map->NumberOfProtoTransitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011548 const int proto_offset =
11549 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
11550 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
11551 const int step = kProtoTransitionElementsPerEntry;
11552 for (int i = 0; i < number_of_transitions; i++) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011553 if (cache->get(proto_offset + i * step) == *prototype) {
11554 Object* result = cache->get(map_offset + i * step);
11555 return Handle<Map>(Map::cast(result));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011556 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011557 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011558 return Handle<Map>();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011559}
11560
11561
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011562Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
11563 Handle<Object> prototype,
11564 Handle<Map> target_map) {
11565 ASSERT(target_map->IsMap());
11566 ASSERT(HeapObject::cast(*prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011567 // Don't cache prototype transition if this map is shared.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011568 if (map->is_shared() || !FLAG_cache_prototype_transitions) return map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011569
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011570 const int step = kProtoTransitionElementsPerEntry;
11571 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011572
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011573 Handle<FixedArray> cache(map->GetPrototypeTransitions());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011574 int capacity = (cache->length() - header) / step;
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011575 int transitions = map->NumberOfProtoTransitions() + 1;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011576
11577 if (transitions > capacity) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011578 if (capacity > kMaxCachedPrototypeTransitions) return map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011579
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011580 // Grow array by factor 2 over and above what we need.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011581 Factory* factory = map->GetIsolate()->factory();
11582 cache = factory->CopySizeFixedArray(cache, transitions * 2 * step + header);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011583
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011584 CALL_AND_RETRY_OR_DIE(map->GetIsolate(),
11585 map->SetPrototypeTransitions(*cache),
11586 break,
11587 return Handle<Map>());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011588 }
11589
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011590 // Reload number of transitions as GC might shrink them.
11591 int last = map->NumberOfProtoTransitions();
11592 int entry = header + last * step;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011593
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011594 cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
11595 cache->set(entry + kProtoTransitionMapOffset, *target_map);
11596 map->SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011597
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011598 return map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011599}
11600
11601
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011602void Map::ZapTransitions() {
11603 TransitionArray* transition_array = transitions();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000011604 // TODO(mstarzinger): Temporarily use a slower version instead of the faster
11605 // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
11606 Object** data = transition_array->data_start();
11607 Object* the_hole = GetHeap()->the_hole_value();
11608 int length = transition_array->length();
11609 for (int i = 0; i < length; i++) {
11610 data[i] = the_hole;
11611 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011612}
11613
11614
11615void Map::ZapPrototypeTransitions() {
11616 FixedArray* proto_transitions = GetPrototypeTransitions();
11617 MemsetPointer(proto_transitions->data_start(),
11618 GetHeap()->the_hole_value(),
11619 proto_transitions->length());
11620}
11621
11622
danno@chromium.org41728482013-06-12 22:31:22 +000011623void Map::AddDependentCompilationInfo(DependentCode::DependencyGroup group,
11624 CompilationInfo* info) {
11625 Handle<DependentCode> dep(dependent_code());
11626 Handle<DependentCode> codes =
11627 DependentCode::Insert(dep, group, info->object_wrapper());
11628 if (*codes != dependent_code()) set_dependent_code(*codes);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011629 info->dependencies(group)->Add(Handle<HeapObject>(this), info->zone());
danno@chromium.org41728482013-06-12 22:31:22 +000011630}
11631
11632
11633void Map::AddDependentCode(DependentCode::DependencyGroup group,
11634 Handle<Code> code) {
11635 Handle<DependentCode> codes = DependentCode::Insert(
11636 Handle<DependentCode>(dependent_code()), group, code);
11637 if (*codes != dependent_code()) set_dependent_code(*codes);
11638}
11639
11640
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011641DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
11642 Recompute(entries);
yangguo@chromium.org003650e2013-01-24 16:31:08 +000011643}
11644
11645
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011646void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
11647 start_indexes_[0] = 0;
11648 for (int g = 1; g <= kGroupCount; g++) {
11649 int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
11650 start_indexes_[g] = start_indexes_[g - 1] + count;
11651 }
11652}
11653
11654
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011655DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
11656 DependencyGroup group) {
11657 AllowDeferredHandleDereference dependencies_are_safe;
11658 if (group == DependentCode::kPropertyCellChangedGroup) {
11659 return Handle<PropertyCell>::cast(object)->dependent_code();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011660 } else if (group == DependentCode::kAllocationSiteTenuringChangedGroup ||
11661 group == DependentCode::kAllocationSiteTransitionChangedGroup) {
11662 return Handle<AllocationSite>::cast(object)->dependent_code();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011663 }
11664 return Handle<Map>::cast(object)->dependent_code();
11665}
11666
11667
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011668Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
11669 DependencyGroup group,
danno@chromium.org41728482013-06-12 22:31:22 +000011670 Handle<Object> object) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011671 GroupStartIndexes starts(*entries);
11672 int start = starts.at(group);
11673 int end = starts.at(group + 1);
11674 int number_of_entries = starts.number_of_entries();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011675 // Check for existing entry to avoid duplicates.
11676 for (int i = start; i < end; i++) {
11677 if (entries->object_at(i) == *object) return entries;
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011678 }
11679 if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
11680 Factory* factory = entries->GetIsolate()->factory();
11681 int capacity = kCodesStartIndex + number_of_entries + 1;
11682 if (capacity > 5) capacity = capacity * 5 / 4;
11683 Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000011684 factory->CopySizeFixedArray(entries, capacity, TENURED));
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011685 // The number of codes can change after GC.
11686 starts.Recompute(*entries);
11687 start = starts.at(group);
11688 end = starts.at(group + 1);
11689 number_of_entries = starts.number_of_entries();
11690 for (int i = 0; i < number_of_entries; i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000011691 entries->clear_at(i);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011692 }
11693 // If the old fixed array was empty, we need to reset counters of the
11694 // new array.
11695 if (number_of_entries == 0) {
11696 for (int g = 0; g < kGroupCount; g++) {
11697 new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
11698 }
11699 }
11700 entries = new_entries;
11701 }
11702 entries->ExtendGroup(group);
danno@chromium.org41728482013-06-12 22:31:22 +000011703 entries->set_object_at(end, *object);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011704 entries->set_number_of_entries(group, end + 1 - start);
11705 return entries;
11706}
11707
11708
danno@chromium.org41728482013-06-12 22:31:22 +000011709void DependentCode::UpdateToFinishedCode(DependencyGroup group,
11710 CompilationInfo* info,
11711 Code* code) {
11712 DisallowHeapAllocation no_gc;
11713 AllowDeferredHandleDereference get_object_wrapper;
11714 Foreign* info_wrapper = *info->object_wrapper();
11715 GroupStartIndexes starts(this);
11716 int start = starts.at(group);
11717 int end = starts.at(group + 1);
11718 for (int i = start; i < end; i++) {
11719 if (object_at(i) == info_wrapper) {
11720 set_object_at(i, code);
11721 break;
11722 }
11723 }
11724
11725#ifdef DEBUG
11726 for (int i = start; i < end; i++) {
11727 ASSERT(is_code_at(i) || compilation_info_at(i) != info);
11728 }
11729#endif
11730}
11731
11732
11733void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
11734 CompilationInfo* info) {
11735 DisallowHeapAllocation no_allocation;
11736 AllowDeferredHandleDereference get_object_wrapper;
11737 Foreign* info_wrapper = *info->object_wrapper();
11738 GroupStartIndexes starts(this);
11739 int start = starts.at(group);
11740 int end = starts.at(group + 1);
11741 // Find compilation info wrapper.
11742 int info_pos = -1;
11743 for (int i = start; i < end; i++) {
11744 if (object_at(i) == info_wrapper) {
11745 info_pos = i;
11746 break;
11747 }
11748 }
11749 if (info_pos == -1) return; // Not found.
11750 int gap = info_pos;
11751 // Use the last of each group to fill the gap in the previous group.
11752 for (int i = group; i < kGroupCount; i++) {
11753 int last_of_group = starts.at(i + 1) - 1;
11754 ASSERT(last_of_group >= gap);
11755 if (last_of_group == gap) continue;
11756 copy(last_of_group, gap);
11757 gap = last_of_group;
11758 }
11759 ASSERT(gap == starts.number_of_entries() - 1);
11760 clear_at(gap); // Clear last gap.
11761 set_number_of_entries(group, end - start - 1);
11762
11763#ifdef DEBUG
11764 for (int i = start; i < end - 1; i++) {
11765 ASSERT(is_code_at(i) || compilation_info_at(i) != info);
11766 }
11767#endif
11768}
11769
11770
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011771bool DependentCode::Contains(DependencyGroup group, Code* code) {
11772 GroupStartIndexes starts(this);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000011773 int start = starts.at(group);
11774 int end = starts.at(group + 1);
11775 for (int i = start; i < end; i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000011776 if (object_at(i) == code) return true;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000011777 }
11778 return false;
11779}
11780
11781
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011782void DependentCode::DeoptimizeDependentCodeGroup(
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000011783 Isolate* isolate,
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011784 DependentCode::DependencyGroup group) {
danno@chromium.org59400602013-08-13 17:09:37 +000011785 ASSERT(AllowCodeDependencyChange::IsAllowed());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000011786 DisallowHeapAllocation no_allocation_scope;
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011787 DependentCode::GroupStartIndexes starts(this);
11788 int start = starts.at(group);
11789 int end = starts.at(group + 1);
danno@chromium.org41728482013-06-12 22:31:22 +000011790 int code_entries = starts.number_of_entries();
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011791 if (start == end) return;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000011792
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011793 // Mark all the code that needs to be deoptimized.
11794 bool marked = false;
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011795 for (int i = start; i < end; i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000011796 if (is_code_at(i)) {
11797 Code* code = code_at(i);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011798 if (!code->marked_for_deoptimization()) {
11799 code->set_marked_for_deoptimization(true);
11800 marked = true;
11801 }
danno@chromium.org41728482013-06-12 22:31:22 +000011802 } else {
11803 CompilationInfo* info = compilation_info_at(i);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011804 info->AbortDueToDependencyChange();
danno@chromium.org41728482013-06-12 22:31:22 +000011805 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011806 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011807 // Compact the array by moving all subsequent groups to fill in the new holes.
danno@chromium.org41728482013-06-12 22:31:22 +000011808 for (int src = end, dst = start; src < code_entries; src++, dst++) {
11809 copy(src, dst);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011810 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011811 // Now the holes are at the end of the array, zap them for heap-verifier.
11812 int removed = end - start;
danno@chromium.org41728482013-06-12 22:31:22 +000011813 for (int i = code_entries - removed; i < code_entries; i++) {
11814 clear_at(i);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011815 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011816 set_number_of_entries(group, 0);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011817
11818 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011819}
11820
11821
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011822Handle<Object> JSObject::SetPrototype(Handle<JSObject> object,
11823 Handle<Object> value,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000011824 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011825#ifdef DEBUG
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011826 int size = object->Size();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011827#endif
11828
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011829 Isolate* isolate = object->GetIsolate();
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011830 Heap* heap = isolate->heap();
ager@chromium.org5c838252010-02-19 08:53:10 +000011831 // Silently ignore the change if value is not a JSObject or null.
11832 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000011833 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +000011834
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011835 // From 8.6.2 Object Internal Methods
11836 // ...
11837 // In addition, if [[Extensible]] is false the value of the [[Class]] and
11838 // [[Prototype]] internal properties of the object may not be modified.
11839 // ...
11840 // Implementation specific extensions that modify [[Class]], [[Prototype]]
11841 // or [[Extensible]] must not violate the invariants defined in the preceding
11842 // paragraph.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011843 if (!object->map()->is_extensible()) {
11844 Handle<Object> args[] = { object };
11845 Handle<Object> error = isolate->factory()->NewTypeError(
11846 "non_extensible_proto", HandleVector(args, ARRAY_SIZE(args)));
11847 isolate->Throw(*error);
11848 return Handle<Object>();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011849 }
11850
ager@chromium.org5c838252010-02-19 08:53:10 +000011851 // Before we can set the prototype we need to be sure
11852 // prototype cycles are prevented.
11853 // It is sufficient to validate that the receiver is not in the new prototype
11854 // chain.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011855 for (Object* pt = *value;
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011856 pt != heap->null_value();
11857 pt = pt->GetPrototype(isolate)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011858 if (JSReceiver::cast(pt) == *object) {
ager@chromium.org5c838252010-02-19 08:53:10 +000011859 // Cycle detected.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011860 Handle<Object> error = isolate->factory()->NewError(
11861 "cyclic_proto", HandleVector<Object>(NULL, 0));
11862 isolate->Throw(*error);
11863 return Handle<Object>();
ager@chromium.org5c838252010-02-19 08:53:10 +000011864 }
11865 }
11866
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011867 bool dictionary_elements_in_chain =
11868 object->map()->DictionaryElementsInPrototypeChainOnly();
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011869 Handle<JSObject> real_receiver = object;
ager@chromium.org5c838252010-02-19 08:53:10 +000011870
11871 if (skip_hidden_prototypes) {
11872 // Find the first object in the chain whose prototype object is not
11873 // hidden and set the new prototype on that object.
11874 Object* current_proto = real_receiver->GetPrototype();
11875 while (current_proto->IsJSObject() &&
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011876 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
11877 real_receiver = handle(JSObject::cast(current_proto), isolate);
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011878 current_proto = current_proto->GetPrototype(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +000011879 }
11880 }
11881
11882 // Set the new prototype of the object.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011883 Handle<Map> map(real_receiver->map());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011884
11885 // Nothing to do if prototype is already set.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011886 if (map->prototype() == *value) return value;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011887
mmassi@chromium.org7028c052012-06-13 11:51:58 +000011888 if (value->IsJSObject()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011889 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
mmassi@chromium.org7028c052012-06-13 11:51:58 +000011890 }
11891
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011892 Handle<Map> new_map = Map::GetPrototypeTransition(map, value);
11893 if (new_map.is_null()) {
11894 new_map = Map::Copy(map);
11895 Map::PutPrototypeTransition(map, value, new_map);
11896 new_map->set_prototype(*value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011897 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011898 ASSERT(new_map->prototype() == *value);
11899 real_receiver->set_map(*new_map);
ager@chromium.org5c838252010-02-19 08:53:10 +000011900
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000011901 if (!dictionary_elements_in_chain &&
11902 new_map->DictionaryElementsInPrototypeChainOnly()) {
11903 // If the prototype chain didn't previously have element callbacks, then
11904 // KeyedStoreICs need to be cleared to ensure any that involve this
11905 // map go generic.
11906 object->GetHeap()->ClearAllICsByKind(Code::KEYED_STORE_IC);
11907 }
11908
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 heap->ClearInstanceofCache();
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011910 ASSERT(size == object->Size());
ager@chromium.org5c838252010-02-19 08:53:10 +000011911 return value;
11912}
11913
11914
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011915MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
11916 uint32_t first_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011917 uint32_t arg_count,
11918 EnsureElementsMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011919 // Elements in |Arguments| are ordered backwards (because they're on the
11920 // stack), but the method that's called here iterates over them in forward
11921 // direction.
11922 return EnsureCanContainElements(
11923 args->arguments() - first_arg - (arg_count - 1),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011924 arg_count, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011925}
11926
11927
ulan@chromium.org750145a2013-03-07 15:14:13 +000011928AccessorPair* JSObject::GetLocalPropertyAccessorPair(Name* name) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011929 uint32_t index = 0;
11930 if (name->AsArrayIndex(&index)) {
11931 return GetLocalElementAccessorPair(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011932 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011933
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011934 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011935 LocalLookupRealNamedProperty(name, &lookup);
11936
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011937 if (lookup.IsPropertyCallbacks() &&
11938 lookup.GetCallbackObject()->IsAccessorPair()) {
11939 return AccessorPair::cast(lookup.GetCallbackObject());
11940 }
11941 return NULL;
11942}
11943
11944
11945AccessorPair* JSObject::GetLocalElementAccessorPair(uint32_t index) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011946 if (IsJSGlobalProxy()) {
11947 Object* proto = GetPrototype();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011948 if (proto->IsNull()) return NULL;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011949 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011950 return JSObject::cast(proto)->GetLocalElementAccessorPair(index);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011952
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011953 // Check for lookup interceptor.
11954 if (HasIndexedInterceptor()) return NULL;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011955
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011956 return GetElementsAccessor()->GetAccessorPair(this, this, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011957}
11958
11959
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011960Handle<Object> JSObject::SetElementWithInterceptor(
11961 Handle<JSObject> object,
11962 uint32_t index,
11963 Handle<Object> value,
11964 PropertyAttributes attributes,
11965 StrictModeFlag strict_mode,
11966 bool check_prototype,
11967 SetPropertyMode set_mode) {
11968 Isolate* isolate = object->GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000011969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970 // Make sure that the top context does not change when doing
11971 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000011972 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000011973
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011974 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011975 if (!interceptor->setter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +000011976 v8::IndexedPropertySetterCallback setter =
11977 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011978 LOG(isolate,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011979 ApiIndexedPropertyAccess("interceptor-indexed-set", *object, index));
11980 PropertyCallbackArguments args(isolate, interceptor->data(), *object,
11981 *object);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011982 v8::Handle<v8::Value> result =
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011983 args.Call(setter, index, v8::Utils::ToLocal(value));
11984 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
11985 if (!result.IsEmpty()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000011987
11988 return SetElementWithoutInterceptor(object, index, value, attributes,
11989 strict_mode,
11990 check_prototype,
11991 set_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011992}
11993
11994
lrn@chromium.org303ada72010-10-27 09:33:13 +000011995MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
11996 Object* structure,
11997 uint32_t index,
11998 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011999 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000012000 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012001
12002 // api style callbacks.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012003 if (structure->IsExecutableAccessorInfo()) {
12004 Handle<ExecutableAccessorInfo> data(
12005 ExecutableAccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012006 Object* fun_obj = data->getter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +000012007 v8::AccessorGetterCallback call_fun =
12008 v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000012009 if (call_fun == NULL) return isolate->heap()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012010 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012011 Handle<JSObject> self(JSObject::cast(receiver));
12012 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012013 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012014 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012015 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000012016 PropertyCallbackArguments
12017 args(isolate, data->data(), *self, *holder_handle);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012018 v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012019 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
12020 if (result.IsEmpty()) return isolate->heap()->undefined_value();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012021 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12022 result_internal->VerifyApiCallResultType();
12023 return *result_internal;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012024 }
12025
12026 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012027 if (structure->IsAccessorPair()) {
12028 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012029 if (getter->IsSpecFunction()) {
12030 // TODO(rossberg): nicer would be to cast to some JSCallable here...
12031 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012032 }
12033 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012035 }
12036
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012037 if (structure->IsDeclaredAccessorInfo()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +000012038 return GetDeclaredAccessorProperty(receiver,
12039 DeclaredAccessorInfo::cast(structure),
12040 isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012041 }
12042
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012043 UNREACHABLE();
12044 return NULL;
12045}
12046
12047
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012048Handle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
12049 Handle<Object> structure,
12050 uint32_t index,
12051 Handle<Object> value,
12052 Handle<JSObject> holder,
12053 StrictModeFlag strict_mode) {
12054 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012055
12056 // We should never get here to initialize a const with the hole
12057 // value since a const declaration would conflict with the setter.
12058 ASSERT(!value->IsTheHole());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012059
12060 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +000012061 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012062 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +000012063 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012064
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012065 if (structure->IsExecutableAccessorInfo()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012066 // api style callbacks
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012067 Handle<ExecutableAccessorInfo> data =
12068 Handle<ExecutableAccessorInfo>::cast(structure);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012069 Object* call_obj = data->setter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +000012070 v8::AccessorSetterCallback call_fun =
12071 v8::ToCData<v8::AccessorSetterCallback>(call_obj);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012072 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012073 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12074 Handle<String> key(isolate->factory()->NumberToString(number));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012075 LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000012076 PropertyCallbackArguments
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012077 args(isolate, data->data(), *object, *holder);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012078 args.Call(call_fun,
12079 v8::Utils::ToLocal(key),
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012080 v8::Utils::ToLocal(value));
12081 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
12082 return value;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012083 }
12084
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012085 if (structure->IsAccessorPair()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012086 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012087 if (setter->IsSpecFunction()) {
12088 // TODO(rossberg): nicer would be to cast to some JSCallable here...
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012089 return SetPropertyWithDefinedSetter(
12090 object, Handle<JSReceiver>::cast(setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012091 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000012092 if (strict_mode == kNonStrictMode) {
12093 return value;
12094 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012095 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012096 Handle<Object> args[2] = { key, holder };
12097 Handle<Object> error = isolate->factory()->NewTypeError(
12098 "no_setter_in_callback", HandleVector(args, 2));
12099 isolate->Throw(*error);
12100 return Handle<Object>();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012101 }
12102 }
12103
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012104 // TODO(dcarney): Handle correctly.
12105 if (structure->IsDeclaredAccessorInfo()) return value;
12106
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012107 UNREACHABLE();
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012108 return Handle<Object>();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000012109}
12110
12111
whesse@chromium.org7b260152011-06-20 15:33:18 +000012112bool JSObject::HasFastArgumentsElements() {
12113 Heap* heap = GetHeap();
12114 if (!elements()->IsFixedArray()) return false;
12115 FixedArray* elements = FixedArray::cast(this->elements());
12116 if (elements->map() != heap->non_strict_arguments_elements_map()) {
12117 return false;
12118 }
12119 FixedArray* arguments = FixedArray::cast(elements->get(1));
12120 return !arguments->IsDictionary();
12121}
12122
12123
12124bool JSObject::HasDictionaryArgumentsElements() {
12125 Heap* heap = GetHeap();
12126 if (!elements()->IsFixedArray()) return false;
12127 FixedArray* elements = FixedArray::cast(this->elements());
12128 if (elements->map() != heap->non_strict_arguments_elements_map()) {
12129 return false;
12130 }
12131 FixedArray* arguments = FixedArray::cast(elements->get(1));
12132 return arguments->IsDictionary();
12133}
12134
12135
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012136// Adding n elements in fast case is O(n*n).
12137// Note: revisit design to have dual undefined values to capture absent
12138// elements.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012139Handle<Object> JSObject::SetFastElement(Handle<JSObject> object,
12140 uint32_t index,
12141 Handle<Object> value,
12142 StrictModeFlag strict_mode,
12143 bool check_prototype) {
12144 ASSERT(object->HasFastSmiOrObjectElements() ||
12145 object->HasFastArgumentsElements());
12146
12147 Isolate* isolate = object->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000012149 // Array optimizations rely on the prototype lookups of Array objects always
12150 // returning undefined. If there is a store to the initial prototype object,
12151 // make sure all of these optimizations are invalidated.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012152 if (isolate->is_initial_object_prototype(*object) ||
12153 isolate->is_initial_array_prototype(*object)) {
12154 object->map()->dependent_code()->DeoptimizeDependentCodeGroup(isolate,
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000012155 DependentCode::kElementsCantBeAddedGroup);
12156 }
12157
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012158 Handle<FixedArray> backing_store(FixedArray::cast(object->elements()));
12159 if (backing_store->map() ==
12160 isolate->heap()->non_strict_arguments_elements_map()) {
12161 backing_store = handle(FixedArray::cast(backing_store->get(1)));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012162 } else {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012163 backing_store = EnsureWritableFastElements(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012164 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012165 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012166
lrn@chromium.org5d00b602011-01-05 09:51:43 +000012167 if (check_prototype &&
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012168 (index >= capacity || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000012169 bool found;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012170 Handle<Object> result = SetElementWithCallbackSetterInPrototypes(
12171 object, index, value, &found, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000012172 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012173 }
12174
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012175 uint32_t new_capacity = capacity;
12176 // Check if the length property of this object needs to be updated.
12177 uint32_t array_length = 0;
12178 bool must_update_array_length = false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012179 bool introduces_holes = true;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012180 if (object->IsJSArray()) {
12181 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012182 introduces_holes = index > array_length;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012183 if (index >= array_length) {
12184 must_update_array_length = true;
12185 array_length = index + 1;
12186 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012187 } else {
12188 introduces_holes = index >= capacity;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012189 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012190
12191 // If the array is growing, and it's not growth by a single element at the
12192 // end, make sure that the ElementsKind is HOLEY.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012193 ElementsKind elements_kind = object->GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012194 if (introduces_holes &&
12195 IsFastElementsKind(elements_kind) &&
12196 !IsFastHoleyElementsKind(elements_kind)) {
12197 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012198 TransitionElementsKind(object, transitioned_kind);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012199 }
12200
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012201 // Check if the capacity of the backing store needs to be increased, or if
12202 // a transition to slow elements is necessary.
12203 if (index >= capacity) {
12204 bool convert_to_slow = true;
12205 if ((index - capacity) < kMaxGap) {
12206 new_capacity = NewElementsCapacity(index + 1);
12207 ASSERT(new_capacity > index);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012208 if (!object->ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012209 convert_to_slow = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012210 }
12211 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012212 if (convert_to_slow) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012213 NormalizeElements(object);
12214 return SetDictionaryElement(object, index, value, NONE, strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012215 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012216 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012217 }
12218 // Convert to fast double elements if appropriate.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012219 if (object->HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012220 // Consider fixing the boilerplate as well if we have one.
12221 ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
12222 ? FAST_HOLEY_DOUBLE_ELEMENTS
12223 : FAST_DOUBLE_ELEMENTS;
12224
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012225 UpdateAllocationSite(object, to_kind);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012226
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012227 SetFastDoubleElementsCapacityAndLength(object, new_capacity, array_length);
12228 FixedDoubleArray::cast(object->elements())->set(index, value->Number());
12229 object->ValidateElements();
ager@chromium.orgbdf2f942008-10-17 07:23:00 +000012230 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012232 // Change elements kind from Smi-only to generic FAST if necessary.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012233 if (object->HasFastSmiElements() && !value->IsSmi()) {
12234 ElementsKind kind = object->HasFastHoleyElements()
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012235 ? FAST_HOLEY_ELEMENTS
12236 : FAST_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012237
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012238 UpdateAllocationSite(object, kind);
12239 Handle<Map> new_map = GetElementsTransitionMap(object, kind);
12240 object->set_map(*new_map);
12241 ASSERT(IsFastObjectElementsKind(object->GetElementsKind()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012243 // Increase backing store capacity if that's been decided previously.
12244 if (new_capacity != capacity) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012245 SetFastElementsCapacitySmiMode smi_mode =
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012246 value->IsSmi() && object->HasFastSmiElements()
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012247 ? kAllowSmiElements
12248 : kDontAllowSmiElements;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012249 Handle<FixedArray> new_elements =
12250 SetFastElementsCapacityAndLength(object, new_capacity, array_length,
12251 smi_mode);
12252 new_elements->set(index, *value);
12253 object->ValidateElements();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012254 return value;
12255 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012256
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012257 // Finally, set the new element and length.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012258 ASSERT(object->elements()->IsFixedArray());
12259 backing_store->set(index, *value);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012260 if (must_update_array_length) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012261 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(array_length));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012262 }
12263 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012264}
12265
12266
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012267Handle<Object> JSObject::SetDictionaryElement(Handle<JSObject> object,
12268 uint32_t index,
12269 Handle<Object> value,
12270 PropertyAttributes attributes,
12271 StrictModeFlag strict_mode,
12272 bool check_prototype,
12273 SetPropertyMode set_mode) {
12274 ASSERT(object->HasDictionaryElements() ||
12275 object->HasDictionaryArgumentsElements());
12276 Isolate* isolate = object->GetIsolate();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012277
12278 // Insert element in the dictionary.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012279 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012280 bool is_arguments =
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012281 (elements->map() == isolate->heap()->non_strict_arguments_elements_map());
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012282 Handle<SeededNumberDictionary> dictionary(is_arguments
12283 ? SeededNumberDictionary::cast(elements->get(1))
12284 : SeededNumberDictionary::cast(*elements));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012285
12286 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012287 if (entry != SeededNumberDictionary::kNotFound) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012288 Handle<Object> element(dictionary->ValueAt(entry), isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012289 PropertyDetails details = dictionary->DetailsAt(entry);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012290 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012291 return SetElementWithCallback(object, element, index, value, object,
12292 strict_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012293 } else {
12294 dictionary->UpdateMaxNumberKey(index);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012295 // If a value has not been initialized we allow writing to it even if it
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012296 // is read-only (a declared const that has not been initialized). If a
12297 // value is being defined we skip attribute checks completely.
12298 if (set_mode == DEFINE_PROPERTY) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +000012299 details = PropertyDetails(
12300 attributes, NORMAL, details.dictionary_index());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012301 dictionary->DetailsAtPut(entry, details);
12302 } else if (details.IsReadOnly() && !element->IsTheHole()) {
12303 if (strict_mode == kNonStrictMode) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012304 return isolate->factory()->undefined_value();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012305 } else {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012306 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012307 Handle<Object> args[2] = { number, object };
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012308 Handle<Object> error =
12309 isolate->factory()->NewTypeError("strict_read_only_property",
12310 HandleVector(args, 2));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012311 isolate->Throw(*error);
12312 return Handle<Object>();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012313 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012314 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012315 // Elements of the arguments object in slow mode might be slow aliases.
12316 if (is_arguments && element->IsAliasedArgumentsEntry()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012317 Handle<AliasedArgumentsEntry> entry =
12318 Handle<AliasedArgumentsEntry>::cast(element);
12319 Handle<Context> context(Context::cast(elements->get(0)));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012320 int context_index = entry->aliased_context_slot();
12321 ASSERT(!context->get(context_index)->IsTheHole());
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012322 context->set(context_index, *value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012323 // For elements that are still writable we keep slow aliasing.
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012324 if (!details.IsReadOnly()) value = element;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012325 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012326 dictionary->ValueAtPut(entry, *value);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012327 }
12328 } else {
12329 // Index not already used. Look for an accessor in the prototype chain.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012330 // Can cause GC!
whesse@chromium.org7b260152011-06-20 15:33:18 +000012331 if (check_prototype) {
12332 bool found;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012333 Handle<Object> result = SetElementWithCallbackSetterInPrototypes(object,
12334 index, value, &found, strict_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012335 if (found) return result;
12336 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012337
whesse@chromium.org7b260152011-06-20 15:33:18 +000012338 // When we set the is_extensible flag to false we always force the
12339 // element into dictionary mode (and force them to stay there).
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012340 if (!object->map()->is_extensible()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012341 if (strict_mode == kNonStrictMode) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012342 return isolate->factory()->undefined_value();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012343 } else {
12344 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12345 Handle<String> name = isolate->factory()->NumberToString(number);
12346 Handle<Object> args[1] = { name };
12347 Handle<Object> error =
12348 isolate->factory()->NewTypeError("object_not_extensible",
12349 HandleVector(args, 1));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012350 isolate->Throw(*error);
12351 return Handle<Object>();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012352 }
12353 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012354
ulan@chromium.org57ff8812013-05-10 08:16:55 +000012355 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012356 Handle<SeededNumberDictionary> new_dictionary =
12357 SeededNumberDictionary::AddNumberEntry(dictionary, index, value,
12358 details);
12359 if (*dictionary != *new_dictionary) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012360 if (is_arguments) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012361 elements->set(1, *new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012362 } else {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012363 object->set_elements(*new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012364 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012365 dictionary = new_dictionary;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012366 }
12367 }
12368
12369 // Update the array length if this JSObject is an array.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012370 if (object->IsJSArray()) {
12371 JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray>::cast(object), index,
12372 value);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012373 }
12374
12375 // Attempt to put this object back in fast case.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012376 if (object->ShouldConvertToFastElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012377 uint32_t new_length = 0;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012378 if (object->IsJSArray()) {
12379 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&new_length));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012380 } else {
12381 new_length = dictionary->max_number_key() + 1;
12382 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012383 SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays
12384 ? kAllowSmiElements
12385 : kDontAllowSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012386 bool has_smi_only_elements = false;
12387 bool should_convert_to_fast_double_elements =
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012388 object->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012389 if (has_smi_only_elements) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012390 smi_mode = kForceSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012391 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012392
12393 if (should_convert_to_fast_double_elements) {
12394 SetFastDoubleElementsCapacityAndLength(object, new_length, new_length);
12395 } else {
12396 SetFastElementsCapacityAndLength(object, new_length, new_length,
12397 smi_mode);
12398 }
12399 object->ValidateElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012400#ifdef DEBUG
12401 if (FLAG_trace_normalization) {
12402 PrintF("Object elements are fast case again:\n");
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012403 object->Print();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012404 }
12405#endif
12406 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012407 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012408}
12409
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012410Handle<Object> JSObject::SetFastDoubleElement(
12411 Handle<JSObject> object,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012412 uint32_t index,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012413 Handle<Object> value,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012414 StrictModeFlag strict_mode,
12415 bool check_prototype) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012416 ASSERT(object->HasFastDoubleElements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012417
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012418 Handle<FixedArrayBase> base_elms(FixedArrayBase::cast(object->elements()));
yangguo@chromium.org56454712012-02-16 15:33:53 +000012419 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012420
12421 // If storing to an element that isn't in the array, pass the store request
12422 // up the prototype chain before storing in the receiver's elements.
12423 if (check_prototype &&
yangguo@chromium.org56454712012-02-16 15:33:53 +000012424 (index >= elms_length ||
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012425 Handle<FixedDoubleArray>::cast(base_elms)->is_the_hole(index))) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012426 bool found;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012427 Handle<Object> result = SetElementWithCallbackSetterInPrototypes(object,
12428 index, value, &found, strict_mode);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012429 if (found) return result;
12430 }
12431
12432 // If the value object is not a heap number, switch to fast elements and try
12433 // again.
12434 bool value_is_smi = value->IsSmi();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012435 bool introduces_holes = true;
12436 uint32_t length = elms_length;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012437 if (object->IsJSArray()) {
12438 CHECK(Handle<JSArray>::cast(object)->length()->ToArrayIndex(&length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012439 introduces_holes = index > length;
12440 } else {
12441 introduces_holes = index >= elms_length;
12442 }
12443
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012444 if (!value->IsNumber()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012445 SetFastElementsCapacityAndLength(object, elms_length, length,
12446 kDontAllowSmiElements);
12447 Handle<Object> result = SetFastElement(object, index, value, strict_mode,
12448 check_prototype);
12449 RETURN_IF_EMPTY_HANDLE_VALUE(object->GetIsolate(), result,
12450 Handle<Object>());
12451 object->ValidateElements();
12452 return result;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012453 }
12454
12455 double double_value = value_is_smi
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012456 ? static_cast<double>(Handle<Smi>::cast(value)->value())
12457 : Handle<HeapNumber>::cast(value)->value();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012458
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012459 // If the array is growing, and it's not growth by a single element at the
12460 // end, make sure that the ElementsKind is HOLEY.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012461 ElementsKind elements_kind = object->GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012462 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
12463 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012464 TransitionElementsKind(object, transitioned_kind);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012465 }
12466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012467 // Check whether there is extra space in the fixed array.
12468 if (index < elms_length) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012469 Handle<FixedDoubleArray> elms(FixedDoubleArray::cast(object->elements()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012470 elms->set(index, double_value);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012471 if (object->IsJSArray()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012472 // Update the length of the array if needed.
12473 uint32_t array_length = 0;
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012474 CHECK(
12475 Handle<JSArray>::cast(object)->length()->ToArrayIndex(&array_length));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012476 if (index >= array_length) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012477 Handle<JSArray>::cast(object)->set_length(Smi::FromInt(index + 1));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012478 }
12479 }
12480 return value;
12481 }
12482
12483 // Allow gap in fast case.
12484 if ((index - elms_length) < kMaxGap) {
12485 // Try allocating extra space.
12486 int new_capacity = NewElementsCapacity(index+1);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012487 if (!object->ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012488 ASSERT(static_cast<uint32_t>(new_capacity) > index);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012489 SetFastDoubleElementsCapacityAndLength(object, new_capacity, index + 1);
12490 FixedDoubleArray::cast(object->elements())->set(index, double_value);
12491 object->ValidateElements();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012492 return value;
12493 }
12494 }
12495
12496 // Otherwise default to slow case.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012497 ASSERT(object->HasFastDoubleElements());
12498 ASSERT(object->map()->has_fast_double_elements());
12499 ASSERT(object->elements()->IsFixedDoubleArray());
12500
12501 NormalizeElements(object);
12502 ASSERT(object->HasDictionaryElements());
12503 return SetElement(object, index, value, NONE, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012504}
12505
12506
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000012507Handle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
12508 uint32_t index,
12509 Handle<Object> value,
12510 PropertyAttributes attributes,
12511 StrictModeFlag strict_mode) {
12512 if (object->IsJSProxy()) {
12513 return JSProxy::SetElementWithHandler(
12514 Handle<JSProxy>::cast(object), object, index, value, strict_mode);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012515 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000012516 return JSObject::SetElement(
12517 Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012518}
12519
12520
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012521Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
12522 uint32_t index,
12523 Handle<Object> value,
12524 StrictModeFlag strict_mode) {
12525 ASSERT(!object->HasExternalArrayElements());
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012526 return JSObject::SetElement(object, index, value, NONE, strict_mode, false);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012527}
12528
12529
12530Handle<Object> JSObject::SetElement(Handle<JSObject> object,
12531 uint32_t index,
12532 Handle<Object> value,
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012533 PropertyAttributes attributes,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012534 StrictModeFlag strict_mode,
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000012535 bool check_prototype,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012536 SetPropertyMode set_mode) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012537 Isolate* isolate = object->GetIsolate();
12538
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012539 if (object->HasExternalArrayElements()) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000012540 if (!value->IsNumber() && !value->IsUndefined()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012541 bool has_exception;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012542 Handle<Object> number =
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012543 Execution::ToNumber(isolate, value, &has_exception);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012544 if (has_exception) return Handle<Object>();
12545 value = number;
12546 }
12547 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012548
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012549 // Check access rights if needed.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012550 if (object->IsAccessCheckNeeded()) {
12551 if (!isolate->MayIndexedAccess(*object, index, v8::ACCESS_SET)) {
12552 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
12553 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
12554 return value;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012556 }
12557
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012558 if (object->IsJSGlobalProxy()) {
12559 Handle<Object> proto(object->GetPrototype(), isolate);
12560 if (proto->IsNull()) return value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012561 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012562 return SetElement(Handle<JSObject>::cast(proto), index, value, attributes,
12563 strict_mode,
12564 check_prototype,
12565 set_mode);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012566 }
12567
12568 // Don't allow element properties to be redefined for external arrays.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012569 if (object->HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012570 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012571 Handle<Object> args[] = { object, number };
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012572 Handle<Object> error = isolate->factory()->NewTypeError(
12573 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012574 isolate->Throw(*error);
12575 return Handle<Object>();
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012576 }
12577
12578 // Normalize the elements to enable attributes on the property.
12579 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012580 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012581 // Make sure that we never go back to fast case.
12582 dictionary->set_requires_slow_elements();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012583 }
12584
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012585 if (!(FLAG_harmony_observation && object->map()->is_observed())) {
12586 return object->HasIndexedInterceptor()
12587 ? SetElementWithInterceptor(object, index, value, attributes, strict_mode,
12588 check_prototype,
12589 set_mode)
12590 : SetElementWithoutInterceptor(object, index, value, attributes,
12591 strict_mode,
12592 check_prototype,
12593 set_mode);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012594 }
12595
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012596 PropertyAttributes old_attributes = object->GetLocalElementAttribute(index);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012597 Handle<Object> old_value = isolate->factory()->the_hole_value();
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012598 Handle<Object> old_length_handle;
12599 Handle<Object> new_length_handle;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012600
12601 if (old_attributes != ABSENT) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012602 if (object->GetLocalElementAccessorPair(index) == NULL)
12603 old_value = Object::GetElement(isolate, object, index);
12604 } else if (object->IsJSArray()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012605 // Store old array length in case adding an element grows the array.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012606 old_length_handle = handle(Handle<JSArray>::cast(object)->length(),
12607 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012608 }
12609
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012610 // Check for lookup interceptor
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012611 Handle<Object> result = object->HasIndexedInterceptor()
12612 ? SetElementWithInterceptor(object, index, value, attributes, strict_mode,
12613 check_prototype,
12614 set_mode)
12615 : SetElementWithoutInterceptor(object, index, value, attributes,
12616 strict_mode,
12617 check_prototype,
12618 set_mode);
12619 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012620
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012621 Handle<String> name = isolate->factory()->Uint32ToString(index);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012622 PropertyAttributes new_attributes = object->GetLocalElementAttribute(index);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012623 if (old_attributes == ABSENT) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012624 if (object->IsJSArray() &&
12625 !old_length_handle->SameValue(
12626 Handle<JSArray>::cast(object)->length())) {
12627 new_length_handle = handle(Handle<JSArray>::cast(object)->length(),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012628 isolate);
12629 uint32_t old_length = 0;
12630 uint32_t new_length = 0;
12631 CHECK(old_length_handle->ToArrayIndex(&old_length));
12632 CHECK(new_length_handle->ToArrayIndex(&new_length));
12633
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012634 BeginPerformSplice(Handle<JSArray>::cast(object));
12635 EnqueueChangeRecord(object, "add", name, old_value);
12636 EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012637 old_length_handle);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012638 EndPerformSplice(Handle<JSArray>::cast(object));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012639 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012640 EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012641 new_length - old_length);
12642 } else {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012643 EnqueueChangeRecord(object, "add", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012644 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012645 } else if (old_value->IsTheHole()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012646 EnqueueChangeRecord(object, "reconfigure", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012647 } else {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012648 Handle<Object> new_value = Object::GetElement(isolate, object, index);
danno@chromium.orgca29dd82013-04-26 11:59:48 +000012649 bool value_changed = !old_value->SameValue(*new_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012650 if (old_attributes != new_attributes) {
12651 if (!value_changed) old_value = isolate->factory()->the_hole_value();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012652 EnqueueChangeRecord(object, "reconfigure", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012653 } else if (value_changed) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012654 EnqueueChangeRecord(object, "update", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012655 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012656 }
12657
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012658 return result;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012659}
12660
12661
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012662Handle<Object> JSObject::SetElementWithoutInterceptor(
12663 Handle<JSObject> object,
12664 uint32_t index,
12665 Handle<Object> value,
12666 PropertyAttributes attributes,
12667 StrictModeFlag strict_mode,
12668 bool check_prototype,
12669 SetPropertyMode set_mode) {
12670 ASSERT(object->HasDictionaryElements() ||
12671 object->HasDictionaryArgumentsElements() ||
12672 (attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
12673 Isolate* isolate = object->GetIsolate();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012674 if (FLAG_trace_external_array_abuse &&
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012675 IsExternalArrayElementsKind(object->GetElementsKind())) {
12676 CheckArrayAbuse(*object, "external elements write", index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012677 }
12678 if (FLAG_trace_js_array_abuse &&
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012679 !IsExternalArrayElementsKind(object->GetElementsKind())) {
12680 if (object->IsJSArray()) {
12681 CheckArrayAbuse(*object, "elements write", index, true);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012682 }
12683 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012684 switch (object->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012685 case FAST_SMI_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012686 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012687 case FAST_HOLEY_SMI_ELEMENTS:
12688 case FAST_HOLEY_ELEMENTS:
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012689 return SetFastElement(object, index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012690 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012691 case FAST_HOLEY_DOUBLE_ELEMENTS:
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012692 return SetFastDoubleElement(object, index, value, strict_mode,
12693 check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012694 case EXTERNAL_PIXEL_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012695 ExternalPixelArray* pixels = ExternalPixelArray::cast(object->elements());
12696 return handle(pixels->SetValue(index, *value), isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012697 }
ager@chromium.org3811b432009-10-28 14:53:37 +000012698 case EXTERNAL_BYTE_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012699 Handle<ExternalByteArray> array(
12700 ExternalByteArray::cast(object->elements()));
12701 return ExternalByteArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012702 }
12703 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012704 Handle<ExternalUnsignedByteArray> array(
12705 ExternalUnsignedByteArray::cast(object->elements()));
12706 return ExternalUnsignedByteArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012707 }
12708 case EXTERNAL_SHORT_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012709 Handle<ExternalShortArray> array(ExternalShortArray::cast(
12710 object->elements()));
12711 return ExternalShortArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012712 }
12713 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012714 Handle<ExternalUnsignedShortArray> array(
12715 ExternalUnsignedShortArray::cast(object->elements()));
12716 return ExternalUnsignedShortArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012717 }
12718 case EXTERNAL_INT_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012719 Handle<ExternalIntArray> array(
12720 ExternalIntArray::cast(object->elements()));
12721 return ExternalIntArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012722 }
12723 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012724 Handle<ExternalUnsignedIntArray> array(
12725 ExternalUnsignedIntArray::cast(object->elements()));
12726 return ExternalUnsignedIntArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012727 }
12728 case EXTERNAL_FLOAT_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012729 Handle<ExternalFloatArray> array(
12730 ExternalFloatArray::cast(object->elements()));
12731 return ExternalFloatArray::SetValue(array, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000012732 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012733 case EXTERNAL_DOUBLE_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012734 Handle<ExternalDoubleArray> array(
12735 ExternalDoubleArray::cast(object->elements()));
12736 return ExternalDoubleArray::SetValue(array, index, value);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012737 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012738 case DICTIONARY_ELEMENTS:
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012739 return SetDictionaryElement(object, index, value, attributes, strict_mode,
12740 check_prototype,
12741 set_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012742 case NON_STRICT_ARGUMENTS_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012743 Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012744 uint32_t length = parameter_map->length();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012745 Handle<Object> probe = index < length - 2 ?
12746 Handle<Object>(parameter_map->get(index + 2), isolate) :
12747 Handle<Object>();
12748 if (!probe.is_null() && !probe->IsTheHole()) {
12749 Handle<Context> context(Context::cast(parameter_map->get(0)));
12750 int context_index = Handle<Smi>::cast(probe)->value();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012751 ASSERT(!context->get(context_index)->IsTheHole());
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012752 context->set(context_index, *value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012753 // Redefining attributes of an aliased element destroys fast aliasing.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012754 if (set_mode == SET_PROPERTY || attributes == NONE) return value;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012755 parameter_map->set_the_hole(index + 2);
12756 // For elements that are still writable we re-establish slow aliasing.
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012757 if ((attributes & READ_ONLY) == 0) {
12758 value = Handle<Object>::cast(
12759 isolate->factory()->NewAliasedArgumentsEntry(context_index));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012760 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012761 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012762 Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012763 if (arguments->IsDictionary()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012764 return SetDictionaryElement(object, index, value, attributes,
12765 strict_mode,
12766 check_prototype,
12767 set_mode);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012768 } else {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012769 return SetFastElement(object, index, value, strict_mode,
12770 check_prototype);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012771 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012772 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012773 }
12774 // All possible cases have been handled above. Add a return to avoid the
12775 // complaints from the compiler.
12776 UNREACHABLE();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012777 return isolate->factory()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012778}
12779
12780
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012781void JSObject::TransitionElementsKind(Handle<JSObject> object,
12782 ElementsKind to_kind) {
12783 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
12784 object->TransitionElementsKind(to_kind));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012785}
12786
12787
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000012788bool AllocationSite::IsNestedSite() {
12789 ASSERT(FLAG_trace_track_allocation_sites);
12790 Object* current = GetHeap()->allocation_sites_list();
12791 while (current != NULL && current->IsAllocationSite()) {
12792 AllocationSite* current_site = AllocationSite::cast(current);
12793 if (current_site->nested_site() == this) {
12794 return true;
12795 }
12796 current = current_site->weak_next();
12797 }
12798 return false;
12799}
12800
12801
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012802MaybeObject* AllocationSite::DigestTransitionFeedback(ElementsKind to_kind) {
12803 Isolate* isolate = GetIsolate();
12804
12805 if (SitePointsToLiteral() && transition_info()->IsJSArray()) {
12806 JSArray* transition_info = JSArray::cast(this->transition_info());
12807 ElementsKind kind = transition_info->GetElementsKind();
12808 // if kind is holey ensure that to_kind is as well.
12809 if (IsHoleyElementsKind(kind)) {
12810 to_kind = GetHoleyElementsKind(to_kind);
12811 }
12812 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
12813 // If the array is huge, it's not likely to be defined in a local
12814 // function, so we shouldn't make new instances of it very often.
12815 uint32_t length = 0;
12816 CHECK(transition_info->length()->ToArrayIndex(&length));
12817 if (length <= kMaximumArrayBytesToPretransition) {
12818 if (FLAG_trace_track_allocation_sites) {
12819 bool is_nested = IsNestedSite();
12820 PrintF(
12821 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
12822 reinterpret_cast<void*>(this),
12823 is_nested ? "(nested)" : "",
12824 ElementsKindToString(kind),
12825 ElementsKindToString(to_kind));
12826 }
12827 MaybeObject* result = transition_info->TransitionElementsKind(to_kind);
12828 if (result->IsFailure()) return result;
12829 dependent_code()->DeoptimizeDependentCodeGroup(
12830 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
12831 }
12832 }
12833 } else {
12834 ElementsKind kind = GetElementsKind();
12835 // if kind is holey ensure that to_kind is as well.
12836 if (IsHoleyElementsKind(kind)) {
12837 to_kind = GetHoleyElementsKind(to_kind);
12838 }
12839 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
12840 if (FLAG_trace_track_allocation_sites) {
12841 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
12842 reinterpret_cast<void*>(this),
12843 ElementsKindToString(kind),
12844 ElementsKindToString(to_kind));
12845 }
12846 SetElementsKind(to_kind);
12847 dependent_code()->DeoptimizeDependentCodeGroup(
12848 isolate, DependentCode::kAllocationSiteTransitionChangedGroup);
12849 }
12850 }
12851 return this;
12852}
12853
12854
12855void AllocationSite::AddDependentCompilationInfo(Reason reason,
12856 CompilationInfo* info) {
12857 DependentCode::DependencyGroup group = ToDependencyGroup(reason);
12858 Handle<DependentCode> dep(dependent_code());
12859 Handle<DependentCode> codes =
12860 DependentCode::Insert(dep, group, info->object_wrapper());
12861 if (*codes != dependent_code()) set_dependent_code(*codes);
12862 info->dependencies(group)->Add(Handle<HeapObject>(this), info->zone());
12863}
12864
12865
12866void AllocationSite::AddDependentCode(Reason reason, Handle<Code> code) {
12867 DependentCode::DependencyGroup group = ToDependencyGroup(reason);
12868 Handle<DependentCode> codes = DependentCode::Insert(
12869 Handle<DependentCode>(dependent_code()), group, code);
12870 if (*codes != dependent_code()) set_dependent_code(*codes);
12871}
12872
12873
12874void JSObject::UpdateAllocationSite(Handle<JSObject> object,
12875 ElementsKind to_kind) {
12876 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
12877 object->UpdateAllocationSite(to_kind));
12878}
12879
12880
danno@chromium.orgbee51992013-07-10 14:57:15 +000012881MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012882 if (!FLAG_track_allocation_sites || !IsJSArray()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012883 return this;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012884 }
12885
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012886 AllocationMemento* memento = AllocationMemento::FindForJSObject(this);
12887 if (memento == NULL || !memento->IsValid()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012888 return this;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012889 }
12890
danno@chromium.orgbee51992013-07-10 14:57:15 +000012891 // Walk through to the Allocation Site
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012892 AllocationSite* site = memento->GetAllocationSite();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012893 return site->DigestTransitionFeedback(to_kind);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012894}
12895
12896
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012897MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012898 ElementsKind from_kind = map()->elements_kind();
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012899
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012900 if (IsFastHoleyElementsKind(from_kind)) {
12901 to_kind = GetHoleyElementsKind(to_kind);
12902 }
12903
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000012904 if (from_kind == to_kind) return this;
machenbach@chromium.orge8412be2013-11-08 10:23:52 +000012905 // Don't update the site if to_kind isn't fast
12906 if (IsFastElementsKind(to_kind)) {
12907 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
12908 if (maybe_failure->IsFailure()) return maybe_failure;
12909 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012910
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012911 Isolate* isolate = GetIsolate();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012912 if (elements() == isolate->heap()->empty_fixed_array() ||
12913 (IsFastSmiOrObjectElementsKind(from_kind) &&
12914 IsFastSmiOrObjectElementsKind(to_kind)) ||
12915 (from_kind == FAST_DOUBLE_ELEMENTS &&
12916 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
12917 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
12918 // No change is needed to the elements() buffer, the transition
12919 // only requires a map change.
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012920 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
12921 Map* new_map;
12922 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
12923 set_map(new_map);
12924 if (FLAG_trace_elements_transitions) {
12925 FixedArrayBase* elms = FixedArrayBase::cast(elements());
12926 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
12927 }
12928 return this;
12929 }
12930
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012931 FixedArrayBase* elms = FixedArrayBase::cast(elements());
12932 uint32_t capacity = static_cast<uint32_t>(elms->length());
12933 uint32_t length = capacity;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012934
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012935 if (IsJSArray()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012936 Object* raw_length = JSArray::cast(this)->length();
12937 if (raw_length->IsUndefined()) {
12938 // If length is undefined, then JSArray is being initialized and has no
12939 // elements, assume a length of zero.
12940 length = 0;
12941 } else {
12942 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012943 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012944 }
12945
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012946 if (IsFastSmiElementsKind(from_kind) &&
12947 IsFastDoubleElementsKind(to_kind)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012948 MaybeObject* maybe_result =
12949 SetFastDoubleElementsCapacityAndLength(capacity, length);
12950 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012951 ValidateElements();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012952 return this;
12953 }
12954
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012955 if (IsFastDoubleElementsKind(from_kind) &&
12956 IsFastObjectElementsKind(to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012957 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012958 capacity, length, kDontAllowSmiElements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012959 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012960 ValidateElements();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012961 return this;
12962 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012963
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012964 // This method should never be called for any other case than the ones
12965 // handled above.
12966 UNREACHABLE();
12967 return GetIsolate()->heap()->null_value();
12968}
12969
12970
12971// static
12972bool Map::IsValidElementsTransition(ElementsKind from_kind,
12973 ElementsKind to_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012974 // Transitions can't go backwards.
12975 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
12976 return false;
12977 }
12978
12979 // Transitions from HOLEY -> PACKED are not allowed.
12980 return !IsFastHoleyElementsKind(from_kind) ||
12981 IsFastHoleyElementsKind(to_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012982}
12983
12984
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000012985void JSArray::JSArrayUpdateLengthFromIndex(Handle<JSArray> array,
12986 uint32_t index,
12987 Handle<Object> value) {
12988 CALL_HEAP_FUNCTION_VOID(array->GetIsolate(),
12989 array->JSArrayUpdateLengthFromIndex(index, *value));
12990}
12991
12992
lrn@chromium.org303ada72010-10-27 09:33:13 +000012993MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
12994 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012995 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000012996 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012997 // Check to see if we need to update the length. For now, we make
12998 // sure that the length stays within 32-bits (unsigned).
12999 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013000 Object* len;
13001 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013002 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013003 if (!maybe_len->ToObject(&len)) return maybe_len;
13004 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013005 set_length(len);
13006 }
13007 return value;
13008}
13009
13010
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000013011MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013012 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013013 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000013014 HandleScope scope(isolate);
13015
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013016 // Make sure that the top context does not change when doing
13017 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000013018 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000013019
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013020 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
13021 Handle<Object> this_handle(receiver, isolate);
13022 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013023 if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +000013024 v8::IndexedPropertyGetterCallback getter =
13025 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013026 LOG(isolate,
13027 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000013028 PropertyCallbackArguments
13029 args(isolate, interceptor->data(), receiver, this);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013030 v8::Handle<v8::Value> result = args.Call(getter, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013031 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013032 if (!result.IsEmpty()) {
13033 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13034 result_internal->VerifyApiCallResultType();
13035 return *result_internal;
13036 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013037 }
13038
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013039 Heap* heap = holder_handle->GetHeap();
13040 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000013041 MaybeObject* raw_result = handler->Get(*this_handle,
rossberg@chromium.org28a37082011-08-22 11:03:23 +000013042 *holder_handle,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000013043 index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013044 if (raw_result != heap->the_hole_value()) return raw_result;
13045
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013046 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013047
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013048 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013049 if (pt == heap->null_value()) return heap->undefined_value();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000013050 return pt->GetElementWithReceiver(isolate, *this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013051}
13052
13053
13054bool JSObject::HasDenseElements() {
13055 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013056 int used = 0;
13057 GetElementsCapacityAndUsage(&capacity, &used);
13058 return (capacity == 0) || (used > (capacity / 2));
13059}
13060
13061
13062void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
13063 *capacity = 0;
13064 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013065
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000013066 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
13067 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013068 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000013069 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000013070 backing_store_base =
13071 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
13072 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +000013073 if (backing_store->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013074 SeededNumberDictionary* dictionary =
13075 SeededNumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013076 *capacity = dictionary->Capacity();
13077 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000013078 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013079 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013080 // Fall through.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013081 case FAST_SMI_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +000013082 case FAST_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013083 if (IsJSArray()) {
13084 *capacity = backing_store_base->length();
13085 *used = Smi::cast(JSArray::cast(this)->length())->value();
13086 break;
13087 }
13088 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013089 case FAST_HOLEY_SMI_ELEMENTS:
13090 case FAST_HOLEY_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000013091 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013092 *capacity = backing_store->length();
13093 for (int i = 0; i < *capacity; ++i) {
13094 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +000013095 }
13096 break;
13097 case DICTIONARY_ELEMENTS: {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000013098 SeededNumberDictionary* dictionary = element_dictionary();
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013099 *capacity = dictionary->Capacity();
13100 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013101 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013102 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013103 case FAST_DOUBLE_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +000013104 if (IsJSArray()) {
13105 *capacity = backing_store_base->length();
13106 *used = Smi::cast(JSArray::cast(this)->length())->value();
13107 break;
13108 }
13109 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013110 case FAST_HOLEY_DOUBLE_ELEMENTS: {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013111 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013112 *capacity = elms->length();
13113 for (int i = 0; i < *capacity; i++) {
13114 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013115 }
13116 break;
13117 }
ager@chromium.org3811b432009-10-28 14:53:37 +000013118 case EXTERNAL_BYTE_ELEMENTS:
13119 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
13120 case EXTERNAL_SHORT_ELEMENTS:
13121 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
13122 case EXTERNAL_INT_ELEMENTS:
13123 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013124 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013125 case EXTERNAL_DOUBLE_ELEMENTS:
13126 case EXTERNAL_PIXEL_ELEMENTS:
13127 // External arrays are considered 100% used.
13128 ExternalArray* external_array = ExternalArray::cast(elements());
13129 *capacity = external_array->length();
13130 *used = external_array->length();
13131 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013132 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013133}
13134
13135
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013136bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013137 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
13138 kMaxUncheckedFastElementsLength);
13139 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
13140 (new_capacity <= kMaxUncheckedFastElementsLength &&
13141 GetHeap()->InNewSpace(this))) {
13142 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013143 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013144 // If the fast-case backing storage takes up roughly three times as
13145 // much space (in machine words) as a dictionary backing storage
13146 // would, the object should have slow elements.
13147 int old_capacity = 0;
13148 int used_elements = 0;
13149 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013150 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
13151 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013152 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013153}
13154
13155
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013156bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +000013157 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013158 // If the elements are sparse, we should not go back to fast case.
13159 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013160 // An object requiring access checks is never allowed to have fast
13161 // elements. If it had fast elements we would skip security checks.
13162 if (IsAccessCheckNeeded()) return false;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013163 // Observed objects may not go to fast mode because they rely on map checks,
13164 // and for fast element accesses we sometimes check element kinds only.
13165 if (FLAG_harmony_observation && map()->is_observed()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +000013166
13167 FixedArray* elements = FixedArray::cast(this->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013168 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000013169 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013170 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +000013171 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013172 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +000013173 }
13174 // If an element has been added at a very high index in the elements
13175 // dictionary, we cannot go back to fast case.
13176 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013177 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013178 // space (in machine words) as a fast-case backing storage would,
13179 // the object should have fast elements.
13180 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013181 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013182 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013183 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013184 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013185 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013186 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013187 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013188 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013189}
13190
13191
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013192bool JSObject::ShouldConvertToFastDoubleElements(
13193 bool* has_smi_only_elements) {
13194 *has_smi_only_elements = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013195 if (FLAG_unbox_double_arrays) {
13196 ASSERT(HasDictionaryElements());
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000013197 SeededNumberDictionary* dictionary = element_dictionary();
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013198 bool found_double = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013199 for (int i = 0; i < dictionary->Capacity(); i++) {
13200 Object* key = dictionary->KeyAt(i);
13201 if (key->IsNumber()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013202 Object* value = dictionary->ValueAt(i);
13203 if (!value->IsNumber()) return false;
13204 if (!value->IsSmi()) {
13205 found_double = true;
13206 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013207 }
13208 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013209 *has_smi_only_elements = !found_double;
13210 return found_double;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013211 } else {
13212 return false;
13213 }
13214}
13215
13216
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013217// Certain compilers request function template instantiation when they
13218// see the definition of the other template functions in the
13219// class. This requires us to have the template functions put
13220// together, so even though this function belongs in objects-debug.cc,
13221// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +000013222#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013223template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +000013224void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013225 int capacity = HashTable<Shape, Key>::Capacity();
13226 for (int i = 0; i < capacity; i++) {
13227 Object* k = HashTable<Shape, Key>::KeyAt(i);
13228 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000013229 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013230 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000013231 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013232 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000013233 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013234 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000013235 PrintF(out, ": ");
13236 ValueAt(i)->ShortPrint(out);
13237 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013238 }
13239 }
13240}
13241#endif
13242
13243
13244template<typename Shape, typename Key>
13245void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013246 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013247 int capacity = HashTable<Shape, Key>::Capacity();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013248 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013249 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013250 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013251 Object* k = Dictionary<Shape, Key>::KeyAt(i);
13252 if (Dictionary<Shape, Key>::IsKey(k)) {
13253 elements->set(pos++, ValueAt(i), mode);
13254 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013255 }
13256 ASSERT(pos == elements->length());
13257}
13258
13259
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013260InterceptorInfo* JSObject::GetNamedInterceptor() {
13261 ASSERT(map()->has_named_interceptor());
13262 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013263 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013264 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013265 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013266 return InterceptorInfo::cast(result);
13267}
13268
13269
13270InterceptorInfo* JSObject::GetIndexedInterceptor() {
13271 ASSERT(map()->has_indexed_interceptor());
13272 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013273 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013274 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013275 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013276 return InterceptorInfo::cast(result);
13277}
13278
13279
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013280Handle<Object> JSObject::GetPropertyPostInterceptor(
13281 Handle<JSObject> object,
13282 Handle<Object> receiver,
13283 Handle<Name> name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013284 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013285 // Check local property in holder, ignore interceptor.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013286 Isolate* isolate = object->GetIsolate();
13287 LookupResult lookup(isolate);
13288 object->LocalLookupRealNamedProperty(*name, &lookup);
13289 Handle<Object> result;
13290 if (lookup.IsFound()) {
13291 result = GetProperty(object, receiver, &lookup, name, attributes);
13292 } else {
13293 // Continue searching via the prototype chain.
13294 Handle<Object> prototype(object->GetPrototype(), isolate);
13295 *attributes = ABSENT;
13296 if (prototype->IsNull()) return isolate->factory()->undefined_value();
13297 result = GetPropertyWithReceiver(prototype, receiver, name, attributes);
ager@chromium.org5c838252010-02-19 08:53:10 +000013298 }
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013299 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013300}
13301
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013302
lrn@chromium.org303ada72010-10-27 09:33:13 +000013303MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013304 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000013305 Name* name,
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013306 PropertyAttributes* attributes) {
13307 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013308 LookupResult result(GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013309 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000013310 if (result.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013311 return GetProperty(receiver, &result, name, attributes);
13312 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013313 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013314}
13315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013316
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013317Handle<Object> JSObject::GetPropertyWithInterceptor(
13318 Handle<JSObject> object,
13319 Handle<Object> receiver,
13320 Handle<Name> name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013321 PropertyAttributes* attributes) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013322 Isolate* isolate = object->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +000013323
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013324 // TODO(rossberg): Support symbols in the API.
13325 if (name->IsSymbol()) return isolate->factory()->undefined_value();
13326
13327 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor(), isolate);
13328 Handle<String> name_string = Handle<String>::cast(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013329
13330 if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +000013331 v8::NamedPropertyGetterCallback getter =
13332 v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013333 LOG(isolate,
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013334 ApiNamedPropertyAccess("interceptor-named-get", *object, *name));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000013335 PropertyCallbackArguments
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013336 args(isolate, interceptor->data(), *receiver, *object);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013337 v8::Handle<v8::Value> result =
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013338 args.Call(getter, v8::Utils::ToLocal(name_string));
13339 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013340 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013341 *attributes = NONE;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013342 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13343 result_internal->VerifyApiCallResultType();
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013344 // Rebox handle to escape this scope.
13345 return handle(*result_internal, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013346 }
13347 }
13348
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013349 return GetPropertyPostInterceptor(object, receiver, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013350}
13351
13352
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013353bool JSObject::HasRealNamedProperty(Handle<JSObject> object,
13354 Handle<Name> key) {
13355 Isolate* isolate = object->GetIsolate();
13356 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013357 // Check access rights if needed.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013358 if (object->IsAccessCheckNeeded()) {
13359 if (!isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS)) {
13360 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013361 return false;
13362 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013363 }
13364
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013365 LookupResult result(isolate);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013366 object->LocalLookupRealNamedProperty(*key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000013367 return result.IsFound() && !result.IsInterceptor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013368}
13369
13370
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013371bool JSObject::HasRealElementProperty(Handle<JSObject> object, uint32_t index) {
13372 Isolate* isolate = object->GetIsolate();
13373 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013374 // Check access rights if needed.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013375 if (object->IsAccessCheckNeeded()) {
13376 if (!isolate->MayIndexedAccess(*object, index, v8::ACCESS_HAS)) {
13377 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013378 return false;
13379 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013380 }
13381
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013382 if (object->IsJSGlobalProxy()) {
13383 HandleScope scope(isolate);
13384 Handle<Object> proto(object->GetPrototype(), isolate);
danno@chromium.org169691d2013-07-15 08:01:13 +000013385 if (proto->IsNull()) return false;
13386 ASSERT(proto->IsJSGlobalObject());
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013387 return HasRealElementProperty(Handle<JSObject>::cast(proto), index);
danno@chromium.org169691d2013-07-15 08:01:13 +000013388 }
13389
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013390 return object->GetElementAttributeWithoutInterceptor(
13391 *object, index, false) != ABSENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013392}
13393
13394
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013395bool JSObject::HasRealNamedCallbackProperty(Handle<JSObject> object,
13396 Handle<Name> key) {
13397 Isolate* isolate = object->GetIsolate();
13398 SealHandleScope shs(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013399 // Check access rights if needed.
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013400 if (object->IsAccessCheckNeeded()) {
13401 if (!isolate->MayNamedAccess(*object, *key, v8::ACCESS_HAS)) {
13402 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013403 return false;
13404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013405 }
13406
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013407 LookupResult result(isolate);
bmeurer@chromium.org0fdb2a62013-10-21 07:19:36 +000013408 object->LocalLookupRealNamedProperty(*key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000013409 return result.IsPropertyCallbacks();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013410}
13411
13412
13413int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013414 if (HasFastProperties()) {
13415 Map* map = this->map();
13416 if (filter == NONE) return map->NumberOfOwnDescriptors();
ulan@chromium.org750145a2013-03-07 15:14:13 +000013417 if (filter & DONT_ENUM) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013418 int result = map->EnumLength();
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +000013419 if (result != kInvalidEnumCacheSentinel) return result;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013420 }
13421 return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
13422 }
13423 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013424}
13425
13426
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013427void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013428 Object* temp = get(i);
13429 set(i, get(j));
13430 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013431 if (this != numbers) {
13432 temp = numbers->get(i);
erikcorry0ad885c2011-11-21 13:51:57 +000013433 numbers->set(i, Smi::cast(numbers->get(j)));
13434 numbers->set(j, Smi::cast(temp));
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013435 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013436}
13437
13438
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013439static void InsertionSortPairs(FixedArray* content,
13440 FixedArray* numbers,
13441 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013442 for (int i = 1; i < len; i++) {
13443 int j = i;
13444 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013445 (NumberToUint32(numbers->get(j - 1)) >
13446 NumberToUint32(numbers->get(j)))) {
13447 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013448 j--;
13449 }
13450 }
13451}
13452
13453
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013454void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013455 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013456 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013457
13458 // Bottom-up max-heap construction.
13459 for (int i = 1; i < len; ++i) {
13460 int child_index = i;
13461 while (child_index > 0) {
13462 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013463 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13464 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013465 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013466 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013467 } else {
13468 break;
13469 }
13470 child_index = parent_index;
13471 }
13472 }
13473
13474 // Extract elements and create sorted array.
13475 for (int i = len - 1; i > 0; --i) {
13476 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013477 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013478 // Sift down the new top element.
13479 int parent_index = 0;
13480 while (true) {
13481 int child_index = ((parent_index + 1) << 1) - 1;
13482 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013483 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
13484 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
13485 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013486 if (child_index + 1 >= i || child1_value > child2_value) {
13487 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013488 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013489 parent_index = child_index;
13490 } else {
13491 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013492 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013493 parent_index = child_index + 1;
13494 }
13495 }
13496 }
13497}
13498
13499
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013500// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
13501void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
13502 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013503 // For small arrays, simply use insertion sort.
13504 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013505 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013506 return;
13507 }
13508 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013509 uint32_t min_index = NumberToUint32(numbers->get(0));
13510 uint32_t max_index = min_index;
13511 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013512 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013513 if (NumberToUint32(numbers->get(i)) < min_index) {
13514 min_index = NumberToUint32(numbers->get(i));
13515 } else if (NumberToUint32(numbers->get(i)) > max_index) {
13516 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013517 }
13518 }
13519 if (max_index - min_index + 1 == len) {
13520 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013521 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013522 // avoid hanging in case they are not.
13523 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013524 uint32_t p;
13525 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013526 // While the current element at i is not at its correct position p,
13527 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013528 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013529 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013530 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013531 }
13532 }
13533 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013534 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013535 return;
13536 }
13537}
13538
13539
13540// Fill in the names of local properties into the supplied storage. The main
13541// purpose of this function is to provide reflection information for the object
13542// mirrors.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013543void JSObject::GetLocalPropertyNames(
13544 FixedArray* storage, int index, PropertyAttributes filter) {
13545 ASSERT(storage->length() >= (NumberOfLocalProperties(filter) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013546 if (HasFastProperties()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000013547 int real_size = map()->NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000013548 DescriptorArray* descs = map()->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000013549 for (int i = 0; i < real_size; i++) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013550 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
13551 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
13552 storage->set(index++, descs->GetKey(i));
13553 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013554 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013555 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013556 property_dictionary()->CopyKeysTo(storage,
13557 index,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013558 filter,
ulan@chromium.org750145a2013-03-07 15:14:13 +000013559 NameDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013560 }
13561}
13562
13563
13564int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
13565 return GetLocalElementKeys(NULL, filter);
13566}
13567
13568
13569int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013570 // Fast case for objects with no elements.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013571 if (!IsJSValue() && HasFastObjectElements()) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013572 uint32_t length = IsJSArray() ?
13573 static_cast<uint32_t>(
13574 Smi::cast(JSArray::cast(this)->length())->value()) :
13575 static_cast<uint32_t>(FixedArray::cast(elements())->length());
13576 if (length == 0) return 0;
13577 }
13578 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013579 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
13580}
13581
13582
13583int JSObject::GetLocalElementKeys(FixedArray* storage,
13584 PropertyAttributes filter) {
13585 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013586 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013587 case FAST_SMI_ELEMENTS:
13588 case FAST_ELEMENTS:
13589 case FAST_HOLEY_SMI_ELEMENTS:
13590 case FAST_HOLEY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013591 int length = IsJSArray() ?
13592 Smi::cast(JSArray::cast(this)->length())->value() :
13593 FixedArray::cast(elements())->length();
13594 for (int i = 0; i < length; i++) {
13595 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
13596 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013597 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013598 }
13599 counter++;
13600 }
13601 }
13602 ASSERT(!storage || storage->length() >= counter);
13603 break;
13604 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013605 case FAST_DOUBLE_ELEMENTS:
13606 case FAST_HOLEY_DOUBLE_ELEMENTS: {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013607 int length = IsJSArray() ?
13608 Smi::cast(JSArray::cast(this)->length())->value() :
13609 FixedDoubleArray::cast(elements())->length();
13610 for (int i = 0; i < length; i++) {
13611 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
13612 if (storage != NULL) {
13613 storage->set(counter, Smi::FromInt(i));
13614 }
13615 counter++;
13616 }
13617 }
13618 ASSERT(!storage || storage->length() >= counter);
13619 break;
13620 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013621 case EXTERNAL_PIXEL_ELEMENTS: {
13622 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013623 while (counter < length) {
13624 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013625 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013626 }
13627 counter++;
13628 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013629 ASSERT(!storage || storage->length() >= counter);
13630 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013631 }
ager@chromium.org3811b432009-10-28 14:53:37 +000013632 case EXTERNAL_BYTE_ELEMENTS:
13633 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
13634 case EXTERNAL_SHORT_ELEMENTS:
13635 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
13636 case EXTERNAL_INT_ELEMENTS:
13637 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013638 case EXTERNAL_FLOAT_ELEMENTS:
13639 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000013640 int length = ExternalArray::cast(elements())->length();
13641 while (counter < length) {
13642 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013643 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +000013644 }
13645 counter++;
13646 }
13647 ASSERT(!storage || storage->length() >= counter);
13648 break;
13649 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013650 case DICTIONARY_ELEMENTS: {
13651 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013652 element_dictionary()->CopyKeysTo(storage,
13653 filter,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013654 SeededNumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013655 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013656 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013657 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013658 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013659 case NON_STRICT_ARGUMENTS_ELEMENTS: {
13660 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013661 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +000013662 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
13663 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013664 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
13665 // will insert in storage starting at index 0.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013666 SeededNumberDictionary* dictionary =
13667 SeededNumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013668 if (storage != NULL) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013669 dictionary->CopyKeysTo(
13670 storage, filter, SeededNumberDictionary::UNSORTED);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013671 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013672 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013673 for (int i = 0; i < mapped_length; ++i) {
13674 if (!parameter_map->get(i + 2)->IsTheHole()) {
13675 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +000013676 ++counter;
13677 }
13678 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013679 if (storage != NULL) storage->SortPairs(storage, counter);
13680
13681 } else {
13682 int backing_length = arguments->length();
13683 int i = 0;
13684 for (; i < mapped_length; ++i) {
13685 if (!parameter_map->get(i + 2)->IsTheHole()) {
13686 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13687 ++counter;
13688 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
13689 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13690 ++counter;
13691 }
13692 }
13693 for (; i < backing_length; ++i) {
13694 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13695 ++counter;
13696 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013697 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013698 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +000013699 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013700 }
13701
13702 if (this->IsJSValue()) {
13703 Object* val = JSValue::cast(this)->value();
13704 if (val->IsString()) {
13705 String* str = String::cast(val);
13706 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013707 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013708 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013709 }
13710 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013711 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013712 }
13713 }
13714 ASSERT(!storage || storage->length() == counter);
13715 return counter;
13716}
13717
13718
13719int JSObject::GetEnumElementKeys(FixedArray* storage) {
13720 return GetLocalElementKeys(storage,
13721 static_cast<PropertyAttributes>(DONT_ENUM));
13722}
13723
13724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013725// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000013726class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013727 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013728 explicit StringKey(String* string) :
13729 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013730 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013731
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013732 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013733 // We know that all entries in a hash table had their hash keys created.
13734 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013735 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013736 return false;
13737 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013738 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013739 }
13740
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013741 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013742
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013743 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013744
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013745 Object* AsObject(Heap* heap) { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013746
13747 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013748 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013749};
13750
ager@chromium.org381abbb2009-02-25 13:23:22 +000013751
13752// StringSharedKeys are used as keys in the eval cache.
13753class StringSharedKey : public HashTableKey {
13754 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013755 StringSharedKey(String* source,
13756 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013757 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013758 int scope_position)
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013759 : source_(source),
13760 shared_(shared),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013761 language_mode_(language_mode),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013762 scope_position_(scope_position) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +000013763
13764 bool IsMatch(Object* other) {
13765 if (!other->IsFixedArray()) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013766 FixedArray* other_array = FixedArray::cast(other);
13767 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
ager@chromium.org381abbb2009-02-25 13:23:22 +000013768 if (shared != shared_) return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013769 int language_unchecked = Smi::cast(other_array->get(2))->value();
13770 ASSERT(language_unchecked == CLASSIC_MODE ||
13771 language_unchecked == STRICT_MODE ||
13772 language_unchecked == EXTENDED_MODE);
13773 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
13774 if (language_mode != language_mode_) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013775 int scope_position = Smi::cast(other_array->get(3))->value();
13776 if (scope_position != scope_position_) return false;
13777 String* source = String::cast(other_array->get(1));
ager@chromium.org381abbb2009-02-25 13:23:22 +000013778 return source->Equals(source_);
13779 }
13780
ager@chromium.org381abbb2009-02-25 13:23:22 +000013781 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013782 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013783 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013784 int scope_position) {
ager@chromium.org381abbb2009-02-25 13:23:22 +000013785 uint32_t hash = source->Hash();
13786 if (shared->HasSourceCode()) {
13787 // Instead of using the SharedFunctionInfo pointer in the hash
13788 // code computation, we use a combination of the hash of the
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013789 // script source code and the start position of the calling scope.
13790 // We do this to ensure that the cache entries can survive garbage
ager@chromium.org381abbb2009-02-25 13:23:22 +000013791 // collection.
13792 Script* script = Script::cast(shared->script());
13793 hash ^= String::cast(script->source())->Hash();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013794 if (language_mode == STRICT_MODE) hash ^= 0x8000;
13795 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013796 hash += scope_position;
ager@chromium.org381abbb2009-02-25 13:23:22 +000013797 }
13798 return hash;
13799 }
13800
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013801 uint32_t Hash() {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013802 return StringSharedHashHelper(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013803 source_, shared_, language_mode_, scope_position_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013804 }
13805
13806 uint32_t HashForObject(Object* obj) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013807 FixedArray* other_array = FixedArray::cast(obj);
13808 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
13809 String* source = String::cast(other_array->get(1));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013810 int language_unchecked = Smi::cast(other_array->get(2))->value();
13811 ASSERT(language_unchecked == CLASSIC_MODE ||
13812 language_unchecked == STRICT_MODE ||
13813 language_unchecked == EXTENDED_MODE);
13814 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013815 int scope_position = Smi::cast(other_array->get(3))->value();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013816 return StringSharedHashHelper(
13817 source, shared, language_mode, scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013818 }
13819
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013820 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013821 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013822 { MaybeObject* maybe_obj = heap->AllocateFixedArray(4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013823 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13824 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013825 FixedArray* other_array = FixedArray::cast(obj);
13826 other_array->set(0, shared_);
13827 other_array->set(1, source_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013828 other_array->set(2, Smi::FromInt(language_mode_));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013829 other_array->set(3, Smi::FromInt(scope_position_));
13830 return other_array;
ager@chromium.org381abbb2009-02-25 13:23:22 +000013831 }
13832
ager@chromium.org381abbb2009-02-25 13:23:22 +000013833 private:
13834 String* source_;
13835 SharedFunctionInfo* shared_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013836 LanguageMode language_mode_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013837 int scope_position_;
ager@chromium.org381abbb2009-02-25 13:23:22 +000013838};
13839
13840
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013841// RegExpKey carries the source and flags of a regular expression as key.
13842class RegExpKey : public HashTableKey {
13843 public:
13844 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000013845 : string_(string),
13846 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013847
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000013848 // Rather than storing the key in the hash table, a pointer to the
13849 // stored value is stored where the key should be. IsMatch then
13850 // compares the search key to the found object, rather than comparing
13851 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013852 bool IsMatch(Object* obj) {
13853 FixedArray* val = FixedArray::cast(obj);
13854 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
13855 && (flags_ == val->get(JSRegExp::kFlagsIndex));
13856 }
13857
13858 uint32_t Hash() { return RegExpHash(string_, flags_); }
13859
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013860 Object* AsObject(Heap* heap) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013861 // Plain hash maps, which is where regexp keys are used, don't
13862 // use this function.
13863 UNREACHABLE();
13864 return NULL;
13865 }
13866
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013867 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013868 FixedArray* val = FixedArray::cast(obj);
13869 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
13870 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
13871 }
13872
13873 static uint32_t RegExpHash(String* string, Smi* flags) {
13874 return string->Hash() + flags->value();
13875 }
13876
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013877 String* string_;
13878 Smi* flags_;
13879};
13880
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013881
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013882// Utf8StringKey carries a vector of chars as key.
13883class Utf8StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013884 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013885 explicit Utf8StringKey(Vector<const char> string, uint32_t seed)
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013886 : string_(string), hash_field_(0), seed_(seed) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013887
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013888 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013889 return String::cast(string)->IsUtf8EqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013890 }
13891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013892 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013893 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013894 hash_field_ = StringHasher::ComputeUtf8Hash(string_, seed_, &chars_);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013895 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013896 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
13897 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013898 }
13899
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013900 uint32_t HashForObject(Object* other) {
13901 return String::cast(other)->Hash();
13902 }
13903
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013904 MaybeObject* AsObject(Heap* heap) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013905 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013906 return heap->AllocateInternalizedStringFromUtf8(string_,
13907 chars_,
13908 hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013909 }
13910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013911 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013912 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013913 int chars_; // Caches the number of characters when computing the hash code.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013914 uint32_t seed_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013915};
13916
13917
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013918template <typename Char>
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013919class SequentialStringKey : public HashTableKey {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013920 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013921 explicit SequentialStringKey(Vector<const Char> string, uint32_t seed)
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013922 : string_(string), hash_field_(0), seed_(seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013923
13924 uint32_t Hash() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013925 hash_field_ = StringHasher::HashSequentialString<Char>(string_.start(),
13926 string_.length(),
13927 seed_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013928
13929 uint32_t result = hash_field_ >> String::kHashShift;
13930 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
13931 return result;
13932 }
13933
13934
13935 uint32_t HashForObject(Object* other) {
13936 return String::cast(other)->Hash();
13937 }
13938
13939 Vector<const Char> string_;
13940 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013941 uint32_t seed_;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013942};
13943
13944
13945
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013946class OneByteStringKey : public SequentialStringKey<uint8_t> {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013947 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013948 OneByteStringKey(Vector<const uint8_t> str, uint32_t seed)
13949 : SequentialStringKey<uint8_t>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013950
13951 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013952 return String::cast(string)->IsOneByteEqualTo(string_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013953 }
13954
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013955 MaybeObject* AsObject(Heap* heap) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013956 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013957 return heap->AllocateOneByteInternalizedString(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013958 }
13959};
13960
13961
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013962class SubStringOneByteStringKey : public HashTableKey {
danno@chromium.org40cb8782011-05-25 07:58:50 +000013963 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013964 explicit SubStringOneByteStringKey(Handle<SeqOneByteString> string,
13965 int from,
13966 int length)
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000013967 : string_(string), from_(from), length_(length) { }
danno@chromium.org40cb8782011-05-25 07:58:50 +000013968
13969 uint32_t Hash() {
13970 ASSERT(length_ >= 0);
13971 ASSERT(from_ + length_ <= string_->length());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013972 uint8_t* chars = string_->GetChars() + from_;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013973 hash_field_ = StringHasher::HashSequentialString(
13974 chars, length_, string_->GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000013975 uint32_t result = hash_field_ >> String::kHashShift;
13976 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
13977 return result;
13978 }
13979
13980
13981 uint32_t HashForObject(Object* other) {
13982 return String::cast(other)->Hash();
13983 }
13984
13985 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013986 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
13987 return String::cast(string)->IsOneByteEqualTo(chars);
danno@chromium.org40cb8782011-05-25 07:58:50 +000013988 }
13989
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013990 MaybeObject* AsObject(Heap* heap) {
danno@chromium.org40cb8782011-05-25 07:58:50 +000013991 if (hash_field_ == 0) Hash();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013992 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013993 return heap->AllocateOneByteInternalizedString(chars, hash_field_);
danno@chromium.org40cb8782011-05-25 07:58:50 +000013994 }
13995
13996 private:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000013997 Handle<SeqOneByteString> string_;
danno@chromium.org40cb8782011-05-25 07:58:50 +000013998 int from_;
13999 int length_;
14000 uint32_t hash_field_;
14001};
14002
14003
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014004class TwoByteStringKey : public SequentialStringKey<uc16> {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014005 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014006 explicit TwoByteStringKey(Vector<const uc16> str, uint32_t seed)
14007 : SequentialStringKey<uc16>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014008
14009 bool IsMatch(Object* string) {
14010 return String::cast(string)->IsTwoByteEqualTo(string_);
14011 }
14012
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014013 MaybeObject* AsObject(Heap* heap) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014014 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014015 return heap->AllocateTwoByteInternalizedString(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014016 }
14017};
14018
14019
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014020// InternalizedStringKey carries a string/internalized-string object as key.
14021class InternalizedStringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014022 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014023 explicit InternalizedStringKey(String* string)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014024 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014025
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014026 bool IsMatch(Object* string) {
14027 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014028 }
14029
14030 uint32_t Hash() { return string_->Hash(); }
14031
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014032 uint32_t HashForObject(Object* other) {
14033 return String::cast(other)->Hash();
14034 }
14035
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014036 MaybeObject* AsObject(Heap* heap) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014037 // Attempt to flatten the string, so that internalized strings will most
14038 // often be flat strings.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000014039 string_ = string_->TryFlattenGetString();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014040 // Internalize the string if possible.
14041 Map* map = heap->InternalizedStringMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014042 if (map != NULL) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000014043 string_->set_map_no_write_barrier(map);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014044 ASSERT(string_->IsInternalizedString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014045 return string_;
14046 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014047 // Otherwise allocate a new internalized string.
14048 return heap->AllocateInternalizedStringImpl(
14049 string_, string_->length(), string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014050 }
14051
14052 static uint32_t StringHash(Object* obj) {
14053 return String::cast(obj)->Hash();
14054 }
14055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014056 String* string_;
14057};
14058
14059
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014060template<typename Shape, typename Key>
14061void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014062 IteratePointers(v, 0, kElementsStartOffset);
14063}
14064
14065
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014066template<typename Shape, typename Key>
14067void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014068 IteratePointers(v,
14069 kElementsStartOffset,
14070 kHeaderSize + length() * kPointerSize);
14071}
14072
14073
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014074template<typename Shape, typename Key>
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014075MaybeObject* HashTable<Shape, Key>::Allocate(Heap* heap,
14076 int at_least_space_for,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014077 MinimumCapacity capacity_option,
lrn@chromium.org303ada72010-10-27 09:33:13 +000014078 PretenureFlag pretenure) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014079 ASSERT(!capacity_option || IS_POWER_OF_TWO(at_least_space_for));
14080 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
14081 ? at_least_space_for
14082 : ComputeCapacity(at_least_space_for);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000014083 if (capacity > HashTable::kMaxCapacity) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014084 return Failure::OutOfMemoryException(0x10);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014085 }
14086
lrn@chromium.org303ada72010-10-27 09:33:13 +000014087 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014088 { MaybeObject* maybe_obj =
14089 heap-> AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014090 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014091 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000014092 HashTable::cast(obj)->SetNumberOfElements(0);
14093 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
14094 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014095 return obj;
14096}
14097
14098
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014099// Find entry for key otherwise return kNotFound.
ulan@chromium.org750145a2013-03-07 15:14:13 +000014100int NameDictionary::FindEntry(Name* key) {
14101 if (!key->IsUniqueName()) {
14102 return HashTable<NameDictionaryShape, Name*>::FindEntry(key);
ricow@chromium.org4980dff2010-07-19 08:33:45 +000014103 }
14104
ulan@chromium.org750145a2013-03-07 15:14:13 +000014105 // Optimized for unique names. Knowledge of the key type allows:
14106 // 1. Move the check if the key is unique out of the loop.
14107 // 2. Avoid comparing hash codes in unique-to-unique comparison.
14108 // 3. Detect a case when a dictionary key is not unique but the key is.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014109 // In case of positive result the dictionary key may be replaced by the
14110 // internalized string with minimal performance penalty. It gives a chance
14111 // to perform further lookups in code stubs (and significant performance
14112 // boost a certain style of code).
ricow@chromium.org4980dff2010-07-19 08:33:45 +000014113
14114 // EnsureCapacity will guarantee the hash table is never full.
14115 uint32_t capacity = Capacity();
14116 uint32_t entry = FirstProbe(key->Hash(), capacity);
14117 uint32_t count = 1;
14118
14119 while (true) {
14120 int index = EntryToIndex(entry);
14121 Object* element = get(index);
14122 if (element->IsUndefined()) break; // Empty entry.
14123 if (key == element) return entry;
ulan@chromium.org750145a2013-03-07 15:14:13 +000014124 if (!element->IsUniqueName() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014125 !element->IsTheHole() &&
ulan@chromium.org750145a2013-03-07 15:14:13 +000014126 Name::cast(element)->Equals(key)) {
14127 // Replace a key that is a non-internalized string by the equivalent
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014128 // internalized string for faster further lookups.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000014129 set(index, key);
14130 return entry;
14131 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000014132 ASSERT(element->IsTheHole() || !Name::cast(element)->Equals(key));
ricow@chromium.org4980dff2010-07-19 08:33:45 +000014133 entry = NextProbe(entry, count++, capacity);
14134 }
14135 return kNotFound;
14136}
14137
14138
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014139template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000014140MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
14141 ASSERT(NumberOfElements() < new_table->Capacity());
14142
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014143 DisallowHeapAllocation no_gc;
ager@chromium.org04921a82011-06-27 13:21:41 +000014144 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
14145
14146 // Copy prefix to new array.
14147 for (int i = kPrefixStartIndex;
14148 i < kPrefixStartIndex + Shape::kPrefixSize;
14149 i++) {
14150 new_table->set(i, get(i), mode);
14151 }
14152
14153 // Rehash the elements.
14154 int capacity = Capacity();
14155 for (int i = 0; i < capacity; i++) {
14156 uint32_t from_index = EntryToIndex(i);
14157 Object* k = get(from_index);
14158 if (IsKey(k)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014159 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
ager@chromium.org04921a82011-06-27 13:21:41 +000014160 uint32_t insertion_index =
14161 EntryToIndex(new_table->FindInsertionEntry(hash));
14162 for (int j = 0; j < Shape::kEntrySize; j++) {
14163 new_table->set(insertion_index + j, get(from_index + j), mode);
14164 }
14165 }
14166 }
14167 new_table->SetNumberOfElements(NumberOfElements());
14168 new_table->SetNumberOfDeletedElements(0);
14169 return new_table;
14170}
14171
14172
14173template<typename Shape, typename Key>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000014174uint32_t HashTable<Shape, Key>::EntryForProbe(Key key,
14175 Object* k,
14176 int probe,
14177 uint32_t expected) {
14178 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
14179 uint32_t capacity = Capacity();
14180 uint32_t entry = FirstProbe(hash, capacity);
14181 for (int i = 1; i < probe; i++) {
14182 if (entry == expected) return expected;
14183 entry = NextProbe(entry, i, capacity);
14184 }
14185 return entry;
14186}
14187
14188
14189template<typename Shape, typename Key>
14190void HashTable<Shape, Key>::Swap(uint32_t entry1,
14191 uint32_t entry2,
14192 WriteBarrierMode mode) {
14193 int index1 = EntryToIndex(entry1);
14194 int index2 = EntryToIndex(entry2);
14195 Object* temp[Shape::kEntrySize];
14196 for (int j = 0; j < Shape::kEntrySize; j++) {
14197 temp[j] = get(index1 + j);
14198 }
14199 for (int j = 0; j < Shape::kEntrySize; j++) {
14200 set(index1 + j, get(index2 + j), mode);
14201 }
14202 for (int j = 0; j < Shape::kEntrySize; j++) {
14203 set(index2 + j, temp[j], mode);
14204 }
14205}
14206
14207
14208template<typename Shape, typename Key>
14209void HashTable<Shape, Key>::Rehash(Key key) {
14210 DisallowHeapAllocation no_gc;
14211 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
14212 uint32_t capacity = Capacity();
14213 bool done = false;
14214 for (int probe = 1; !done; probe++) {
14215 // All elements at entries given by one of the first _probe_ probes
14216 // are placed correctly. Other elements might need to be moved.
14217 done = true;
14218 for (uint32_t current = 0; current < capacity; current++) {
14219 Object* current_key = get(EntryToIndex(current));
14220 if (IsKey(current_key)) {
14221 uint32_t target = EntryForProbe(key, current_key, probe, current);
14222 if (current == target) continue;
14223 Object* target_key = get(EntryToIndex(target));
14224 if (!IsKey(target_key) ||
14225 EntryForProbe(key, target_key, probe, target) != target) {
14226 // Put the current element into the correct position.
14227 Swap(current, target, mode);
14228 // The other element will be processed on the next iteration.
14229 current--;
14230 } else {
14231 // The place for the current element is occupied. Leave the element
14232 // for the next probe.
14233 done = false;
14234 }
14235 }
14236 }
14237 }
14238}
14239
14240
14241template<typename Shape, typename Key>
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014242MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n,
14243 Key key,
14244 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014245 int capacity = Capacity();
14246 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000014247 int nod = NumberOfDeletedElements();
14248 // Return if:
14249 // 50% is still free after adding n elements and
14250 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014251 if (nod <= (capacity - nof) >> 1) {
14252 int needed_free = nof >> 1;
14253 if (nof + needed_free <= capacity) return this;
14254 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014255
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014256 const int kMinCapacityForPretenure = 256;
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014257 bool should_pretenure = pretenure == TENURED ||
14258 ((capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this));
lrn@chromium.org303ada72010-10-27 09:33:13 +000014259 Object* obj;
14260 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014261 Allocate(GetHeap(),
14262 nof * 2,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014263 USE_DEFAULT_MINIMUM_CAPACITY,
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014264 should_pretenure ? TENURED : NOT_TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014265 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14266 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014267
ager@chromium.org04921a82011-06-27 13:21:41 +000014268 return Rehash(HashTable::cast(obj), key);
14269}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014270
ager@chromium.org04921a82011-06-27 13:21:41 +000014271
14272template<typename Shape, typename Key>
14273MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
14274 int capacity = Capacity();
14275 int nof = NumberOfElements();
14276
14277 // Shrink to fit the number of elements if only a quarter of the
14278 // capacity is filled with elements.
14279 if (nof > (capacity >> 2)) return this;
14280 // Allocate a new dictionary with room for at least the current
14281 // number of elements. The allocation method will make sure that
14282 // there is extra room in the dictionary for additions. Don't go
14283 // lower than room for 16 elements.
14284 int at_least_room_for = nof;
14285 if (at_least_room_for < 16) return this;
14286
14287 const int kMinCapacityForPretenure = 256;
14288 bool pretenure =
14289 (at_least_room_for > kMinCapacityForPretenure) &&
14290 !GetHeap()->InNewSpace(this);
14291 Object* obj;
14292 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014293 Allocate(GetHeap(),
14294 at_least_room_for,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014295 USE_DEFAULT_MINIMUM_CAPACITY,
14296 pretenure ? TENURED : NOT_TENURED);
ager@chromium.org04921a82011-06-27 13:21:41 +000014297 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014298 }
ager@chromium.org04921a82011-06-27 13:21:41 +000014299
14300 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014301}
14302
14303
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014304template<typename Shape, typename Key>
14305uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014306 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014307 uint32_t entry = FirstProbe(hash, capacity);
14308 uint32_t count = 1;
14309 // EnsureCapacity will guarantee the hash table is never full.
14310 while (true) {
14311 Object* element = KeyAt(entry);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014312 if (element->IsUndefined() || element->IsTheHole()) break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014313 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014315 return entry;
14316}
14317
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014318
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014319// Force instantiation of template instances class.
14320// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014321
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014322template class HashTable<StringTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014323
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014324template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014325
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014326template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014327
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014328template class HashTable<ObjectHashTableShape<1>, Object*>;
14329
14330template class HashTable<ObjectHashTableShape<2>, Object*>;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014331
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014332template class HashTable<WeakHashTableShape<2>, Object*>;
14333
ulan@chromium.org750145a2013-03-07 15:14:13 +000014334template class Dictionary<NameDictionaryShape, Name*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014335
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014336template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014337
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014338template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
14339
14340template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014341 Allocate(Heap* heap, int at_least_space_for, PretenureFlag pretenure);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014342
14343template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014344 Allocate(Heap* heap, int at_least_space_for, PretenureFlag pretenure);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014345
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014346template MaybeObject* Dictionary<NameDictionaryShape, Name*>::
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014347 Allocate(Heap* heap, int n, PretenureFlag pretenure);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014348
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014349template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014350 uint32_t, Object*);
14351
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014352template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
14353 AtPut(uint32_t, Object*);
14354
ulan@chromium.org65a89c22012-02-14 11:46:07 +000014355template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14356 SlowReverseLookup(Object* value);
14357
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014358template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
14359 SlowReverseLookup(Object* value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014360
ulan@chromium.org750145a2013-03-07 15:14:13 +000014361template Object* Dictionary<NameDictionaryShape, Name*>::SlowReverseLookup(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014362 Object*);
14363
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014364template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014365 FixedArray*,
14366 PropertyAttributes,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014367 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014368
ulan@chromium.org750145a2013-03-07 15:14:13 +000014369template Object* Dictionary<NameDictionaryShape, Name*>::DeleteProperty(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014370 int, JSObject::DeleteMode);
14371
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014372template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14373 DeleteProperty(int, JSObject::DeleteMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014374
ulan@chromium.org750145a2013-03-07 15:14:13 +000014375template MaybeObject* Dictionary<NameDictionaryShape, Name*>::Shrink(Name* n);
ager@chromium.org04921a82011-06-27 13:21:41 +000014376
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014377template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
ager@chromium.org04921a82011-06-27 13:21:41 +000014378 uint32_t);
14379
ulan@chromium.org750145a2013-03-07 15:14:13 +000014380template void Dictionary<NameDictionaryShape, Name*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014381 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000014382 int,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014383 PropertyAttributes,
ulan@chromium.org750145a2013-03-07 15:14:13 +000014384 Dictionary<NameDictionaryShape, Name*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014385
14386template int
ulan@chromium.org750145a2013-03-07 15:14:13 +000014387Dictionary<NameDictionaryShape, Name*>::NumberOfElementsFilterAttributes(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014388 PropertyAttributes);
14389
ulan@chromium.org750145a2013-03-07 15:14:13 +000014390template MaybeObject* Dictionary<NameDictionaryShape, Name*>::Add(
14391 Name*, Object*, PropertyDetails);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014392
lrn@chromium.org303ada72010-10-27 09:33:13 +000014393template MaybeObject*
ulan@chromium.org750145a2013-03-07 15:14:13 +000014394Dictionary<NameDictionaryShape, Name*>::GenerateNewEnumerationIndices();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014395
14396template int
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014397Dictionary<SeededNumberDictionaryShape, uint32_t>::
14398 NumberOfElementsFilterAttributes(PropertyAttributes);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014399
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014400template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014401 uint32_t, Object*, PropertyDetails);
14402
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014403template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
14404 uint32_t, Object*, PropertyDetails);
14405
14406template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14407 EnsureCapacity(int, uint32_t);
14408
14409template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
lrn@chromium.org303ada72010-10-27 09:33:13 +000014410 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014411
ulan@chromium.org750145a2013-03-07 15:14:13 +000014412template MaybeObject* Dictionary<NameDictionaryShape, Name*>::
14413 EnsureCapacity(int, Name*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014414
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014415template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14416 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
14417
14418template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
14419 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014420
ulan@chromium.org750145a2013-03-07 15:14:13 +000014421template MaybeObject* Dictionary<NameDictionaryShape, Name*>::AddEntry(
14422 Name*, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014423
14424template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014425int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014426
14427template
ulan@chromium.org750145a2013-03-07 15:14:13 +000014428int Dictionary<NameDictionaryShape, Name*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014429
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014430template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014431int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014432
14433
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014434Handle<Object> JSObject::PrepareSlowElementsForSort(
14435 Handle<JSObject> object, uint32_t limit) {
14436 CALL_HEAP_FUNCTION(object->GetIsolate(),
14437 object->PrepareSlowElementsForSort(limit),
14438 Object);
14439}
14440
14441
ager@chromium.org5ec48922009-05-05 07:25:34 +000014442// Collates undefined and unexisting elements below limit from position
14443// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014444MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014445 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000014446 // Must stay in dictionary mode, either because of requires_slow_elements,
14447 // or because we are not going to sort (and therefore compact) all of the
14448 // elements.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014449 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014450 HeapNumber* result_double = NULL;
14451 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
14452 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014453 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014454 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014455 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
14456 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014457 result_double = HeapNumber::cast(new_double);
14458 }
14459
lrn@chromium.org303ada72010-10-27 09:33:13 +000014460 Object* obj;
14461 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014462 SeededNumberDictionary::Allocate(GetHeap(), dict->NumberOfElements());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014463 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14464 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014465 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014466
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014467 DisallowHeapAllocation no_alloc;
ager@chromium.org5ec48922009-05-05 07:25:34 +000014468
ager@chromium.org5ec48922009-05-05 07:25:34 +000014469 uint32_t pos = 0;
14470 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014471 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014472 for (int i = 0; i < capacity; i++) {
14473 Object* k = dict->KeyAt(i);
14474 if (dict->IsKey(k)) {
14475 ASSERT(k->IsNumber());
14476 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
14477 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
14478 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
14479 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000014480 PropertyDetails details = dict->DetailsAt(i);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014481 if (details.type() == CALLBACKS || details.IsReadOnly()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000014482 // Bail out and do the sorting of undefineds and array holes in JS.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014483 // Also bail out if the element is not supposed to be moved.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000014484 return Smi::FromInt(-1);
14485 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014486 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014487 // In the following we assert that adding the entry to the new dictionary
14488 // does not cause GC. This is the case because we made sure to allocate
14489 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000014490 if (key < limit) {
14491 if (value->IsUndefined()) {
14492 undefs++;
14493 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014494 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14495 // Adding an entry with the key beyond smi-range requires
14496 // allocation. Bailout.
14497 return Smi::FromInt(-1);
14498 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000014499 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014500 pos++;
14501 }
14502 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014503 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
14504 // Adding an entry with the key beyond smi-range requires
14505 // allocation. Bailout.
14506 return Smi::FromInt(-1);
14507 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000014508 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014509 }
14510 }
14511 }
14512
14513 uint32_t result = pos;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014514 PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014515 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014516 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014517 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14518 // Adding an entry with the key beyond smi-range requires
14519 // allocation. Bailout.
14520 return Smi::FromInt(-1);
14521 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014522 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000014523 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014524 pos++;
14525 undefs--;
14526 }
14527
14528 set_elements(new_dict);
14529
14530 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
14531 return Smi::FromInt(static_cast<int>(result));
14532 }
14533
14534 ASSERT_NE(NULL, result_double);
14535 result_double->set_value(static_cast<double>(result));
14536 return result_double;
14537}
14538
14539
14540// Collects all defined (non-hole) and non-undefined (array) elements at
14541// the start of the elements array.
14542// If the object is in dictionary mode, it is converted to fast elements
14543// mode.
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014544Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object,
14545 uint32_t limit) {
14546 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014547
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014548 ASSERT(!object->map()->is_observed());
14549 if (object->HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000014550 // Convert to fast elements containing only the existing properties.
14551 // Ordering is irrelevant, since we are going to sort anyway.
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014552 Handle<SeededNumberDictionary> dict(object->element_dictionary());
14553 if (object->IsJSArray() || dict->requires_slow_elements() ||
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +000014554 dict->max_number_key() >= limit) {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014555 return JSObject::PrepareSlowElementsForSort(object, limit);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014556 }
14557 // Convert to fast elements.
14558
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014559 Handle<Map> new_map =
14560 JSObject::GetElementsTransitionMap(object, FAST_HOLEY_ELEMENTS);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000014561
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014562 PretenureFlag tenure = isolate->heap()->InNewSpace(*object) ?
14563 NOT_TENURED: TENURED;
14564 Handle<FixedArray> fast_elements =
14565 isolate->factory()->NewFixedArray(dict->NumberOfElements(), tenure);
14566 dict->CopyValuesTo(*fast_elements);
14567 object->ValidateElements();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000014568
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014569 object->set_map_and_elements(*new_map, *fast_elements);
14570 } else if (object->HasExternalArrayElements()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014571 // External arrays cannot have holes or undefined elements.
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014572 return handle(Smi::FromInt(
14573 ExternalArray::cast(object->elements())->length()), isolate);
14574 } else if (!object->HasFastDoubleElements()) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014575 EnsureWritableFastElements(object);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014576 }
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014577 ASSERT(object->HasFastSmiOrObjectElements() ||
14578 object->HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000014579
14580 // Collect holes at the end, undefined before that and the rest at the
14581 // start, and return the number of non-hole, non-undefined values.
14582
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014583 Handle<FixedArrayBase> elements_base(object->elements());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014584 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000014585 if (limit > elements_length) {
14586 limit = elements_length ;
14587 }
14588 if (limit == 0) {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014589 return handle(Smi::FromInt(0), isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014590 }
14591
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014592 uint32_t result = 0;
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014593 if (elements_base->map() == isolate->heap()->fixed_double_array_map()) {
14594 FixedDoubleArray* elements = FixedDoubleArray::cast(*elements_base);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014595 // Split elements into defined and the_hole, in that order.
14596 unsigned int holes = limit;
14597 // Assume most arrays contain no holes and undefined values, so minimize the
14598 // number of stores of non-undefined, non-the-hole values.
14599 for (unsigned int i = 0; i < holes; i++) {
14600 if (elements->is_the_hole(i)) {
14601 holes--;
14602 } else {
14603 continue;
14604 }
14605 // Position i needs to be filled.
14606 while (holes > i) {
14607 if (elements->is_the_hole(holes)) {
14608 holes--;
14609 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000014610 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014611 break;
14612 }
14613 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014614 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014615 result = holes;
14616 while (holes < limit) {
14617 elements->set_the_hole(holes);
14618 holes++;
14619 }
14620 } else {
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014621 FixedArray* elements = FixedArray::cast(*elements_base);
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014622 DisallowHeapAllocation no_gc;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014623
14624 // Split elements into defined, undefined and the_hole, in that order. Only
14625 // count locations for undefined and the hole, and fill them afterwards.
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014626 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014627 unsigned int undefs = limit;
14628 unsigned int holes = limit;
14629 // Assume most arrays contain no holes and undefined values, so minimize the
14630 // number of stores of non-undefined, non-the-hole values.
14631 for (unsigned int i = 0; i < undefs; i++) {
14632 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014633 if (current->IsTheHole()) {
14634 holes--;
14635 undefs--;
14636 } else if (current->IsUndefined()) {
14637 undefs--;
14638 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014639 continue;
14640 }
14641 // Position i needs to be filled.
14642 while (undefs > i) {
14643 current = elements->get(undefs);
14644 if (current->IsTheHole()) {
14645 holes--;
14646 undefs--;
14647 } else if (current->IsUndefined()) {
14648 undefs--;
14649 } else {
14650 elements->set(i, current, write_barrier);
14651 break;
14652 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014653 }
14654 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014655 result = undefs;
14656 while (undefs < holes) {
14657 elements->set_undefined(undefs);
14658 undefs++;
14659 }
14660 while (holes < limit) {
14661 elements->set_the_hole(holes);
14662 holes++;
14663 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014664 }
14665
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +000014666 return isolate->factory()->NewNumberFromUint(result);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014667}
14668
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014669
danno@chromium.orgf005df62013-04-30 16:36:45 +000014670ExternalArrayType JSTypedArray::type() {
14671 switch (elements()->map()->instance_type()) {
14672 case EXTERNAL_BYTE_ARRAY_TYPE:
14673 return kExternalByteArray;
14674 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
14675 return kExternalUnsignedByteArray;
14676 case EXTERNAL_SHORT_ARRAY_TYPE:
14677 return kExternalShortArray;
14678 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
14679 return kExternalUnsignedShortArray;
14680 case EXTERNAL_INT_ARRAY_TYPE:
14681 return kExternalIntArray;
14682 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
14683 return kExternalUnsignedIntArray;
14684 case EXTERNAL_FLOAT_ARRAY_TYPE:
14685 return kExternalFloatArray;
14686 case EXTERNAL_DOUBLE_ARRAY_TYPE:
14687 return kExternalDoubleArray;
14688 case EXTERNAL_PIXEL_ARRAY_TYPE:
14689 return kExternalPixelArray;
14690 default:
14691 return static_cast<ExternalArrayType>(-1);
14692 }
14693}
14694
ager@chromium.org5ec48922009-05-05 07:25:34 +000014695
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014696size_t JSTypedArray::element_size() {
14697 switch (elements()->map()->instance_type()) {
14698 case EXTERNAL_BYTE_ARRAY_TYPE:
14699 return 1;
14700 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
14701 return 1;
14702 case EXTERNAL_SHORT_ARRAY_TYPE:
14703 return 2;
14704 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
14705 return 2;
14706 case EXTERNAL_INT_ARRAY_TYPE:
14707 return 4;
14708 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
14709 return 4;
14710 case EXTERNAL_FLOAT_ARRAY_TYPE:
14711 return 4;
14712 case EXTERNAL_DOUBLE_ARRAY_TYPE:
14713 return 8;
14714 case EXTERNAL_PIXEL_ARRAY_TYPE:
14715 return 1;
14716 default:
14717 UNREACHABLE();
14718 return 0;
14719 }
14720}
14721
14722
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014723Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014724 uint8_t clamped_value = 0;
14725 if (index < static_cast<uint32_t>(length())) {
14726 if (value->IsSmi()) {
14727 int int_value = Smi::cast(value)->value();
14728 if (int_value < 0) {
14729 clamped_value = 0;
14730 } else if (int_value > 255) {
14731 clamped_value = 255;
14732 } else {
14733 clamped_value = static_cast<uint8_t>(int_value);
14734 }
14735 } else if (value->IsHeapNumber()) {
14736 double double_value = HeapNumber::cast(value)->value();
14737 if (!(double_value > 0)) {
14738 // NaN and less than zero clamp to zero.
14739 clamped_value = 0;
14740 } else if (double_value > 255) {
14741 // Greater than 255 clamp to 255.
14742 clamped_value = 255;
14743 } else {
14744 // Other doubles are rounded to the nearest integer.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014745 clamped_value = static_cast<uint8_t>(lrint(double_value));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014746 }
14747 } else {
14748 // Clamp undefined to zero (default). All other types have been
14749 // converted to a number type further up in the call chain.
14750 ASSERT(value->IsUndefined());
14751 }
14752 set(index, clamped_value);
14753 }
14754 return Smi::FromInt(clamped_value);
14755}
14756
14757
ager@chromium.org3811b432009-10-28 14:53:37 +000014758template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014759static MaybeObject* ExternalArrayIntSetter(Heap* heap,
14760 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000014761 uint32_t index,
14762 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014763 ValueType cast_value = 0;
14764 if (index < static_cast<uint32_t>(receiver->length())) {
14765 if (value->IsSmi()) {
14766 int int_value = Smi::cast(value)->value();
14767 cast_value = static_cast<ValueType>(int_value);
14768 } else if (value->IsHeapNumber()) {
14769 double double_value = HeapNumber::cast(value)->value();
14770 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
14771 } else {
14772 // Clamp undefined to zero (default). All other types have been
14773 // converted to a number type further up in the call chain.
14774 ASSERT(value->IsUndefined());
14775 }
14776 receiver->set(index, cast_value);
14777 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014778 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014779}
14780
14781
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014782Handle<Object> ExternalByteArray::SetValue(Handle<ExternalByteArray> array,
14783 uint32_t index,
14784 Handle<Object> value) {
14785 CALL_HEAP_FUNCTION(array->GetIsolate(),
14786 array->SetValue(index, *value),
14787 Object);
14788}
14789
14790
lrn@chromium.org303ada72010-10-27 09:33:13 +000014791MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014792 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014793 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014794}
14795
14796
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014797Handle<Object> ExternalUnsignedByteArray::SetValue(
14798 Handle<ExternalUnsignedByteArray> array,
14799 uint32_t index,
14800 Handle<Object> value) {
14801 CALL_HEAP_FUNCTION(array->GetIsolate(),
14802 array->SetValue(index, *value),
14803 Object);
14804}
14805
14806
lrn@chromium.org303ada72010-10-27 09:33:13 +000014807MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
14808 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014809 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014810 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014811}
14812
14813
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014814Handle<Object> ExternalShortArray::SetValue(
14815 Handle<ExternalShortArray> array,
14816 uint32_t index,
14817 Handle<Object> value) {
14818 CALL_HEAP_FUNCTION(array->GetIsolate(),
14819 array->SetValue(index, *value),
14820 Object);
14821}
14822
14823
lrn@chromium.org303ada72010-10-27 09:33:13 +000014824MaybeObject* ExternalShortArray::SetValue(uint32_t index,
14825 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014826 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014827 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014828}
14829
14830
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014831Handle<Object> ExternalUnsignedShortArray::SetValue(
14832 Handle<ExternalUnsignedShortArray> array,
14833 uint32_t index,
14834 Handle<Object> value) {
14835 CALL_HEAP_FUNCTION(array->GetIsolate(),
14836 array->SetValue(index, *value),
14837 Object);
14838}
14839
14840
lrn@chromium.org303ada72010-10-27 09:33:13 +000014841MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
14842 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014843 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014844 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014845}
14846
14847
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014848Handle<Object> ExternalIntArray::SetValue(Handle<ExternalIntArray> array,
14849 uint32_t index,
14850 Handle<Object> value) {
14851 CALL_HEAP_FUNCTION(array->GetIsolate(),
14852 array->SetValue(index, *value),
14853 Object);
14854}
14855
14856
lrn@chromium.org303ada72010-10-27 09:33:13 +000014857MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014858 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014859 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014860}
14861
14862
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014863Handle<Object> ExternalUnsignedIntArray::SetValue(
14864 Handle<ExternalUnsignedIntArray> array,
14865 uint32_t index,
14866 Handle<Object> value) {
14867 CALL_HEAP_FUNCTION(array->GetIsolate(),
14868 array->SetValue(index, *value),
14869 Object);
14870}
14871
14872
lrn@chromium.org303ada72010-10-27 09:33:13 +000014873MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014874 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014875 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000014876 if (index < static_cast<uint32_t>(length())) {
14877 if (value->IsSmi()) {
14878 int int_value = Smi::cast(value)->value();
14879 cast_value = static_cast<uint32_t>(int_value);
14880 } else if (value->IsHeapNumber()) {
14881 double double_value = HeapNumber::cast(value)->value();
14882 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
14883 } else {
14884 // Clamp undefined to zero (default). All other types have been
14885 // converted to a number type further up in the call chain.
14886 ASSERT(value->IsUndefined());
14887 }
14888 set(index, cast_value);
14889 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014890 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014891}
14892
14893
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014894Handle<Object> ExternalFloatArray::SetValue(Handle<ExternalFloatArray> array,
14895 uint32_t index,
14896 Handle<Object> value) {
14897 CALL_HEAP_FUNCTION(array->GetIsolate(),
14898 array->SetValue(index, *value),
14899 Object);
14900}
14901
14902
lrn@chromium.org303ada72010-10-27 09:33:13 +000014903MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014904 float cast_value = static_cast<float>(OS::nan_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014905 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000014906 if (index < static_cast<uint32_t>(length())) {
14907 if (value->IsSmi()) {
14908 int int_value = Smi::cast(value)->value();
14909 cast_value = static_cast<float>(int_value);
14910 } else if (value->IsHeapNumber()) {
14911 double double_value = HeapNumber::cast(value)->value();
14912 cast_value = static_cast<float>(double_value);
14913 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014914 // Clamp undefined to NaN (default). All other types have been
ager@chromium.org3811b432009-10-28 14:53:37 +000014915 // converted to a number type further up in the call chain.
14916 ASSERT(value->IsUndefined());
14917 }
14918 set(index, cast_value);
14919 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014920 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014921}
14922
14923
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000014924Handle<Object> ExternalDoubleArray::SetValue(Handle<ExternalDoubleArray> array,
14925 uint32_t index,
14926 Handle<Object> value) {
14927 CALL_HEAP_FUNCTION(array->GetIsolate(),
14928 array->SetValue(index, *value),
14929 Object);
14930}
14931
14932
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014933MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014934 double double_value = OS::nan_value();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014935 Heap* heap = GetHeap();
14936 if (index < static_cast<uint32_t>(length())) {
14937 if (value->IsSmi()) {
14938 int int_value = Smi::cast(value)->value();
14939 double_value = static_cast<double>(int_value);
14940 } else if (value->IsHeapNumber()) {
14941 double_value = HeapNumber::cast(value)->value();
14942 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014943 // Clamp undefined to NaN (default). All other types have been
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014944 // converted to a number type further up in the call chain.
14945 ASSERT(value->IsUndefined());
14946 }
14947 set(index, double_value);
14948 }
14949 return heap->AllocateHeapNumber(double_value);
14950}
14951
14952
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000014953PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014954 ASSERT(!HasFastProperties());
14955 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000014956 return PropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014957}
14958
14959
verwaest@chromium.org057bd502013-11-06 12:03:29 +000014960Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
14961 Handle<JSGlobalObject> global,
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014962 Handle<Name> name) {
14963 ASSERT(!global->HasFastProperties());
14964 int entry = global->property_dictionary()->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014965 if (entry == NameDictionary::kNotFound) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014966 Isolate* isolate = global->GetIsolate();
14967 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
14968 isolate->factory()->the_hole_value());
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014969 PropertyDetails details(NONE, NORMAL, 0);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014970 details = details.AsDeleted();
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014971 Handle<NameDictionary> dictionary = NameDictionaryAdd(
14972 handle(global->property_dictionary()), name, cell, details);
14973 global->set_properties(*dictionary);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014974 return cell;
14975 } else {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014976 Object* value = global->property_dictionary()->ValueAt(entry);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000014977 ASSERT(value->IsPropertyCell());
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014978 return handle(PropertyCell::cast(value));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014979 }
14980}
14981
14982
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014983MaybeObject* StringTable::LookupString(String* string, Object** s) {
14984 InternalizedStringKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014985 return LookupKey(&key, s);
14986}
14987
14988
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014989// This class is used for looking up two character strings in the string table.
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014990// If we don't have a hit we don't want to waste much time so we unroll the
14991// string hash calculation loop here for speed. Doesn't work if the two
14992// characters form a decimal integer, since such strings have a different hash
14993// algorithm.
14994class TwoCharHashTableKey : public HashTableKey {
14995 public:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014996 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014997 : c1_(c1), c2_(c2) {
14998 // Char 1.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000014999 uint32_t hash = seed;
15000 hash += c1;
15001 hash += hash << 10;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015002 hash ^= hash >> 6;
15003 // Char 2.
15004 hash += c2;
15005 hash += hash << 10;
15006 hash ^= hash >> 6;
15007 // GetHash.
15008 hash += hash << 3;
15009 hash ^= hash >> 11;
15010 hash += hash << 15;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000015011 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000015012 hash_ = hash;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015013#ifdef DEBUG
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015014 // If this assert fails then we failed to reproduce the two-character
15015 // version of the string hashing algorithm above. One reason could be
15016 // that we were passed two digits as characters, since the hash
15017 // algorithm is different in that case.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000015018 uint16_t chars[2] = {c1, c2};
15019 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
15020 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
15021 ASSERT_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015022#endif
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015023 }
15024
15025 bool IsMatch(Object* o) {
15026 if (!o->IsString()) return false;
15027 String* other = String::cast(o);
15028 if (other->length() != 2) return false;
15029 if (other->Get(0) != c1_) return false;
15030 return other->Get(1) == c2_;
15031 }
15032
15033 uint32_t Hash() { return hash_; }
15034 uint32_t HashForObject(Object* key) {
15035 if (!key->IsString()) return 0;
15036 return String::cast(key)->Hash();
15037 }
15038
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015039 Object* AsObject(Heap* heap) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015040 // The TwoCharHashTableKey is only used for looking in the string
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015041 // table, not for adding to it.
15042 UNREACHABLE();
15043 return NULL;
15044 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000015045
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015046 private:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000015047 uint16_t c1_;
15048 uint16_t c2_;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015049 uint32_t hash_;
15050};
15051
15052
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015053bool StringTable::LookupStringIfExists(String* string, String** result) {
15054 InternalizedStringKey key(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +000015055 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000015056 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000015057 return false;
15058 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015059 *result = String::cast(KeyAt(entry));
15060 ASSERT(StringShape(*result).IsInternalized());
ager@chromium.org7c537e22008-10-16 08:43:32 +000015061 return true;
15062 }
15063}
15064
15065
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015066bool StringTable::LookupTwoCharsStringIfExists(uint16_t c1,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000015067 uint16_t c2,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015068 String** result) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015069 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015070 int entry = FindEntry(&key);
15071 if (entry == kNotFound) {
15072 return false;
15073 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015074 *result = String::cast(KeyAt(entry));
15075 ASSERT(StringShape(*result).IsInternalized());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000015076 return true;
15077 }
15078}
15079
15080
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015081MaybeObject* StringTable::LookupUtf8String(Vector<const char> str,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000015082 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015083 Utf8StringKey key(str, GetHeap()->HashSeed());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015084 return LookupKey(&key, s);
15085}
15086
15087
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015088MaybeObject* StringTable::LookupOneByteString(Vector<const uint8_t> str,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000015089 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015090 OneByteStringKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000015091 return LookupKey(&key, s);
15092}
15093
15094
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015095MaybeObject* StringTable::LookupSubStringOneByteString(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000015096 Handle<SeqOneByteString> str,
15097 int from,
15098 int length,
15099 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015100 SubStringOneByteStringKey key(str, from, length);
danno@chromium.org40cb8782011-05-25 07:58:50 +000015101 return LookupKey(&key, s);
15102}
15103
15104
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015105MaybeObject* StringTable::LookupTwoByteString(Vector<const uc16> str,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000015106 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015107 TwoByteStringKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000015108 return LookupKey(&key, s);
15109}
15110
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000015111
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015112MaybeObject* StringTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015113 int entry = FindEntry(key);
15114
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015115 // String already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000015116 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015117 *s = KeyAt(entry);
15118 return this;
15119 }
15120
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015121 // Adding new string. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015122 Object* obj;
15123 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15124 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015126
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015127 // Create string object.
15128 Object* string;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015129 { MaybeObject* maybe_string = key->AsObject(GetHeap());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015130 if (!maybe_string->ToObject(&string)) return maybe_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000015131 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015132
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015133 // If the string table grew as part of EnsureCapacity, obj is not
15134 // the current string table and therefore we cannot use
15135 // StringTable::cast here.
15136 StringTable* table = reinterpret_cast<StringTable*>(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015137
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015138 // Add the new string and return it along with the string table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015139 entry = table->FindInsertionEntry(key->Hash());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015140 table->set(EntryToIndex(entry), string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015141 table->ElementAdded();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015142 *s = string;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015143 return table;
15144}
15145
15146
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000015147// The key for the script compilation cache is dependent on the mode flags,
15148// because they change the global language mode and thus binding behaviour.
15149// If flags change at some point, we must ensure that we do not hit the cache
15150// for code compiled with different settings.
15151static LanguageMode CurrentGlobalLanguageMode() {
15152 return FLAG_use_strict
15153 ? (FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE)
15154 : CLASSIC_MODE;
15155}
15156
15157
15158Object* CompilationCacheTable::Lookup(String* src, Context* context) {
15159 SharedFunctionInfo* shared = context->closure()->shared();
15160 StringSharedKey key(src,
15161 shared,
15162 CurrentGlobalLanguageMode(),
15163 RelocInfo::kNoPosition);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000015164 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015165 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015166 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000015167}
15168
15169
ricow@chromium.org83aa5492011-02-07 12:42:56 +000015170Object* CompilationCacheTable::LookupEval(String* src,
15171 Context* context,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000015172 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000015173 int scope_position) {
15174 StringSharedKey key(src,
15175 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000015176 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000015177 scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000015178 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015179 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000015180 return get(EntryToIndex(entry) + 1);
15181}
15182
15183
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000015184Object* CompilationCacheTable::LookupRegExp(String* src,
15185 JSRegExp::Flags flags) {
15186 RegExpKey key(src, flags);
15187 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015188 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000015189 return get(EntryToIndex(entry) + 1);
15190}
15191
15192
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000015193MaybeObject* CompilationCacheTable::Put(String* src,
15194 Context* context,
15195 Object* value) {
15196 SharedFunctionInfo* shared = context->closure()->shared();
15197 StringSharedKey key(src,
15198 shared,
15199 CurrentGlobalLanguageMode(),
15200 RelocInfo::kNoPosition);
15201 CompilationCacheTable* cache;
15202 MaybeObject* maybe_cache = EnsureCapacity(1, &key);
15203 if (!maybe_cache->To(&cache)) return maybe_cache;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000015204
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000015205 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015206 MaybeObject* maybe_k = key.AsObject(GetHeap());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000015207 if (!maybe_k->To(&k)) return maybe_k;
15208
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015209 int entry = cache->FindInsertionEntry(key.Hash());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000015210 cache->set(EntryToIndex(entry), k);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000015211 cache->set(EntryToIndex(entry) + 1, value);
15212 cache->ElementAdded();
15213 return cache;
15214}
15215
15216
lrn@chromium.org303ada72010-10-27 09:33:13 +000015217MaybeObject* CompilationCacheTable::PutEval(String* src,
15218 Context* context,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000015219 SharedFunctionInfo* value,
15220 int scope_position) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +000015221 StringSharedKey key(src,
15222 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000015223 value->language_mode(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000015224 scope_position);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015225 Object* obj;
15226 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
15227 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15228 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000015229
15230 CompilationCacheTable* cache =
15231 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015232 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000015233
lrn@chromium.org303ada72010-10-27 09:33:13 +000015234 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015235 { MaybeObject* maybe_k = key.AsObject(GetHeap());
lrn@chromium.org303ada72010-10-27 09:33:13 +000015236 if (!maybe_k->ToObject(&k)) return maybe_k;
15237 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000015238
15239 cache->set(EntryToIndex(entry), k);
15240 cache->set(EntryToIndex(entry) + 1, value);
15241 cache->ElementAdded();
15242 return cache;
15243}
15244
15245
lrn@chromium.org303ada72010-10-27 09:33:13 +000015246MaybeObject* CompilationCacheTable::PutRegExp(String* src,
15247 JSRegExp::Flags flags,
15248 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000015249 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015250 Object* obj;
15251 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
15252 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15253 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000015254
15255 CompilationCacheTable* cache =
15256 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015257 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000015258 // We store the value in the key slot, and compare the search key
15259 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000015260 cache->set(EntryToIndex(entry), value);
15261 cache->set(EntryToIndex(entry) + 1, value);
15262 cache->ElementAdded();
15263 return cache;
15264}
15265
15266
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015267void CompilationCacheTable::Remove(Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015268 Object* the_hole_value = GetHeap()->the_hole_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015269 for (int entry = 0, size = Capacity(); entry < size; entry++) {
15270 int entry_index = EntryToIndex(entry);
15271 int value_index = entry_index + 1;
15272 if (get(value_index) == value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015273 NoWriteBarrierSet(this, entry_index, the_hole_value);
15274 NoWriteBarrierSet(this, value_index, the_hole_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015275 ElementRemoved();
15276 }
15277 }
15278 return;
15279}
15280
15281
ulan@chromium.org750145a2013-03-07 15:14:13 +000015282// StringsKey used for HashTable where key is array of internalized strings.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015283class StringsKey : public HashTableKey {
ager@chromium.org236ad962008-09-25 09:45:57 +000015284 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015285 explicit StringsKey(FixedArray* strings) : strings_(strings) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000015286
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015287 bool IsMatch(Object* strings) {
15288 FixedArray* o = FixedArray::cast(strings);
15289 int len = strings_->length();
ager@chromium.org236ad962008-09-25 09:45:57 +000015290 if (o->length() != len) return false;
15291 for (int i = 0; i < len; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015292 if (o->get(i) != strings_->get(i)) return false;
ager@chromium.org236ad962008-09-25 09:45:57 +000015293 }
15294 return true;
15295 }
15296
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015297 uint32_t Hash() { return HashForObject(strings_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000015298
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015299 uint32_t HashForObject(Object* obj) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015300 FixedArray* strings = FixedArray::cast(obj);
15301 int len = strings->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015302 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000015303 for (int i = 0; i < len; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015304 hash ^= String::cast(strings->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000015305 }
15306 return hash;
15307 }
15308
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015309 Object* AsObject(Heap* heap) { return strings_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000015310
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015311 private:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015312 FixedArray* strings_;
ager@chromium.org236ad962008-09-25 09:45:57 +000015313};
15314
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015315
ager@chromium.org236ad962008-09-25 09:45:57 +000015316Object* MapCache::Lookup(FixedArray* array) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015317 StringsKey key(array);
ager@chromium.org236ad962008-09-25 09:45:57 +000015318 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015319 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015320 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000015321}
15322
15323
lrn@chromium.org303ada72010-10-27 09:33:13 +000015324MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015325 StringsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015326 Object* obj;
15327 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
15328 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15329 }
ager@chromium.org236ad962008-09-25 09:45:57 +000015330
15331 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015332 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000015333 cache->set(EntryToIndex(entry), array);
15334 cache->set(EntryToIndex(entry) + 1, value);
15335 cache->ElementAdded();
15336 return cache;
15337}
15338
15339
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015340template<typename Shape, typename Key>
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015341MaybeObject* Dictionary<Shape, Key>::Allocate(Heap* heap,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000015342 int at_least_space_for,
15343 PretenureFlag pretenure) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000015344 Object* obj;
15345 { MaybeObject* maybe_obj =
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000015346 HashTable<Shape, Key>::Allocate(
15347 heap,
15348 at_least_space_for,
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015349 USE_DEFAULT_MINIMUM_CAPACITY,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000015350 pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015351 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015352 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000015353 // Initialize the next enumeration index.
15354 Dictionary<Shape, Key>::cast(obj)->
15355 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015356 return obj;
15357}
15358
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015359
ulan@chromium.org750145a2013-03-07 15:14:13 +000015360void NameDictionary::DoGenerateNewEnumerationIndices(
15361 Handle<NameDictionary> dictionary) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015362 CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
15363 dictionary->GenerateNewEnumerationIndices());
15364}
15365
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015366template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015367MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015368 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015369 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015370
15371 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015372 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015373 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015374 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015376 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015377 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000015378 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015379 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015380
15381 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015382 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015383 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15384 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015385 FixedArray* enumeration_order = FixedArray::cast(obj);
15386
15387 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015388 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015389 int pos = 0;
15390 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015391 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000015392 int index = DetailsAt(i).dictionary_index();
15393 enumeration_order->set(pos++, Smi::FromInt(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015394 }
15395 }
15396
15397 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000015398 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015399
15400 // Overwrite the enumeration_order with the enumeration indices.
15401 for (int i = 0; i < length; i++) {
15402 int index = Smi::cast(iteration_order->get(i))->value();
15403 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000015404 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015405 }
15406
15407 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015408 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015409 pos = 0;
15410 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015411 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015412 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
15413 PropertyDetails details = DetailsAt(i);
danno@chromium.orgf005df62013-04-30 16:36:45 +000015414 PropertyDetails new_details = PropertyDetails(
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015415 details.attributes(), details.type(), enum_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015416 DetailsAtPut(i, new_details);
15417 }
15418 }
15419
15420 // Set the next enumeration index.
15421 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
15422 return this;
15423}
15424
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015425template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015426MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000015427 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015428 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015429 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
15430 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015431 Object* result;
15432 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
15433 if (!maybe_result->ToObject(&result)) return maybe_result;
15434 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015435 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015436 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015437}
15438
15439
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015440template<typename Shape, typename Key>
15441Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000015442 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015443 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015444 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000015445 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000015446 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015447 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000015448 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015449 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015450 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015451 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015452}
15453
15454
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015455template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000015456MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
15457 return HashTable<Shape, Key>::Shrink(key);
15458}
15459
15460
15461template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015462MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000015463 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015464
15465 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015466 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015467 ValueAtPut(entry, value);
15468 return this;
15469 }
15470
15471 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015472 Object* obj;
15473 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15474 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15475 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015476
lrn@chromium.org303ada72010-10-27 09:33:13 +000015477 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015478 { MaybeObject* maybe_k = Shape::AsObject(this->GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015479 if (!maybe_k->ToObject(&k)) return maybe_k;
15480 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015481 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015482
15483 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
15484 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015485}
15486
15487
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015488template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015489MaybeObject* Dictionary<Shape, Key>::Add(Key key,
15490 Object* value,
15491 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015492 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000015493 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015494 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015495 Object* obj;
15496 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15497 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15498 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015499
15500 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
15501 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015502}
15503
15504
15505// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015506template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015507MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
15508 Object* value,
15509 PropertyDetails details,
15510 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015511 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015512 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015513 { MaybeObject* maybe_k = Shape::AsObject(this->GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015514 if (!maybe_k->ToObject(&k)) return maybe_k;
15515 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015516
15517 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015518 // Insert element at empty or deleted entry
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015519 if (!details.IsDeleted() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000015520 details.dictionary_index() == 0 &&
15521 Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015522 // Assign an enumeration index to the property and update
15523 // SetNextEnumerationIndex.
15524 int index = NextEnumerationIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015525 details = PropertyDetails(details.attributes(), details.type(), index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015526 SetNextEnumerationIndex(index + 1);
15527 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015528 SetEntry(entry, k, value, details);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015529 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() ||
15530 Dictionary<Shape, Key>::KeyAt(entry)->IsName()));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015531 HashTable<Shape, Key>::ElementAdded();
15532 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015533}
15534
15535
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015536void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015537 // If the dictionary requires slow elements an element has already
15538 // been added at a high index.
15539 if (requires_slow_elements()) return;
15540 // Check if this index is high enough that we should require slow
15541 // elements.
15542 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000015543 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015544 return;
15545 }
15546 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015547 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015548 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015549 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000015550 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015551 }
15552}
15553
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000015554Handle<SeededNumberDictionary> SeededNumberDictionary::AddNumberEntry(
15555 Handle<SeededNumberDictionary> dictionary,
15556 uint32_t key,
15557 Handle<Object> value,
15558 PropertyDetails details) {
15559 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
15560 dictionary->AddNumberEntry(key, *value, details),
15561 SeededNumberDictionary);
15562}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015563
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015564MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
15565 Object* value,
15566 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015567 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000015568 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015569 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015570}
15571
15572
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015573MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
15574 Object* value) {
15575 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015576 return Add(key, value, PropertyDetails(NONE, NORMAL, 0));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015577}
15578
15579
15580MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015581 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015582 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015583}
15584
15585
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015586MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
15587 Object* value) {
15588 return AtPut(key, value);
15589}
15590
15591
15592Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
15593 Handle<SeededNumberDictionary> dictionary,
15594 uint32_t index,
15595 Handle<Object> value,
15596 PropertyDetails details) {
15597 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
15598 dictionary->Set(index, *value, details),
15599 SeededNumberDictionary);
15600}
15601
15602
15603Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
15604 Handle<UnseededNumberDictionary> dictionary,
15605 uint32_t index,
15606 Handle<Object> value) {
15607 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
15608 dictionary->Set(index, *value),
15609 UnseededNumberDictionary);
15610}
15611
15612
15613MaybeObject* SeededNumberDictionary::Set(uint32_t key,
15614 Object* value,
15615 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015616 int entry = FindEntry(key);
15617 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015618 // Preserve enumeration index.
15619 details = PropertyDetails(details.attributes(),
15620 details.type(),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015621 DetailsAt(entry).dictionary_index());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015622 MaybeObject* maybe_object_key =
15623 SeededNumberDictionaryShape::AsObject(GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015624 Object* object_key;
15625 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000015626 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015627 return this;
15628}
15629
15630
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015631MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
15632 Object* value) {
15633 int entry = FindEntry(key);
15634 if (entry == kNotFound) return AddNumberEntry(key, value);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015635 MaybeObject* maybe_object_key =
15636 UnseededNumberDictionaryShape::AsObject(GetHeap(), key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015637 Object* object_key;
15638 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
15639 SetEntry(entry, object_key, value);
15640 return this;
15641}
15642
15643
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000015644
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015645template<typename Shape, typename Key>
15646int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
15647 PropertyAttributes filter) {
15648 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015649 int result = 0;
15650 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015651 Object* k = HashTable<Shape, Key>::KeyAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015652 if (HashTable<Shape, Key>::IsKey(k) &&
15653 ((filter & SYMBOLIC) == 0 || !k->IsSymbol())) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015654 PropertyDetails details = DetailsAt(i);
15655 if (details.IsDeleted()) continue;
15656 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015657 if ((attr & filter) == 0) result++;
15658 }
15659 }
15660 return result;
15661}
15662
15663
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015664template<typename Shape, typename Key>
15665int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015666 return NumberOfElementsFilterAttributes(
15667 static_cast<PropertyAttributes>(DONT_ENUM));
15668}
15669
15670
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015671template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015672void Dictionary<Shape, Key>::CopyKeysTo(
15673 FixedArray* storage,
15674 PropertyAttributes filter,
15675 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015676 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015677 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015678 int index = 0;
15679 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015680 Object* k = HashTable<Shape, Key>::KeyAt(i);
15681 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015682 PropertyDetails details = DetailsAt(i);
15683 if (details.IsDeleted()) continue;
15684 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015685 if ((attr & filter) == 0) storage->set(index++, k);
15686 }
15687 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015688 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
15689 storage->SortPairs(storage, index);
15690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015691 ASSERT(storage->length() >= index);
15692}
15693
15694
ulan@chromium.org750145a2013-03-07 15:14:13 +000015695FixedArray* NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015696 int length = storage->length();
15697 ASSERT(length >= NumberOfEnumElements());
15698 Heap* heap = GetHeap();
15699 Object* undefined_value = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015700 int capacity = Capacity();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015701 int properties = 0;
15702
15703 // Fill in the enumeration array by assigning enumerable keys at their
15704 // enumeration index. This will leave holes in the array if there are keys
15705 // that are deleted or not enumerable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015706 for (int i = 0; i < capacity; i++) {
15707 Object* k = KeyAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015708 if (IsKey(k) && !k->IsSymbol()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015709 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015710 if (details.IsDeleted() || details.IsDontEnum()) continue;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015711 properties++;
15712 storage->set(details.dictionary_index() - 1, k);
15713 if (properties == length) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015714 }
15715 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015716
15717 // There are holes in the enumeration array if less properties were assigned
15718 // than the length of the array. If so, crunch all the existing properties
15719 // together by shifting them to the left (maintaining the enumeration order),
15720 // and trimming of the right side of the array.
15721 if (properties < length) {
15722 if (properties == 0) return heap->empty_fixed_array();
15723 properties = 0;
15724 for (int i = 0; i < length; ++i) {
15725 Object* value = storage->get(i);
15726 if (value != undefined_value) {
15727 storage->set(properties, value);
15728 ++properties;
15729 }
15730 }
15731 RightTrimFixedArray<FROM_MUTATOR>(heap, storage, length - properties);
15732 }
15733 return storage;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015734}
15735
15736
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015737template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015738void Dictionary<Shape, Key>::CopyKeysTo(
15739 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000015740 int index,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000015741 PropertyAttributes filter,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015742 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015743 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
15744 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015745 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015746 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015747 Object* k = HashTable<Shape, Key>::KeyAt(i);
15748 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015749 PropertyDetails details = DetailsAt(i);
15750 if (details.IsDeleted()) continue;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000015751 PropertyAttributes attr = details.attributes();
15752 if ((attr & filter) == 0) storage->set(index++, k);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015753 }
15754 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015755 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
15756 storage->SortPairs(storage, index);
15757 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015758 ASSERT(storage->length() >= index);
15759}
15760
15761
15762// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015763template<typename Shape, typename Key>
15764Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
15765 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015766 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015767 Object* k = HashTable<Shape, Key>::KeyAt(i);
15768 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000015769 Object* e = ValueAt(i);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000015770 if (e->IsPropertyCell()) {
15771 e = PropertyCell::cast(e)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000015772 }
15773 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015774 }
15775 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015776 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015777 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015778}
15779
15780
ulan@chromium.org750145a2013-03-07 15:14:13 +000015781MaybeObject* NameDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015782 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015783 // Make sure we preserve dictionary representation if there are too many
15784 // descriptors.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015785 int number_of_elements = NumberOfElements();
machenbach@chromium.orgaf9cfcb2013-11-19 11:05:18 +000015786 if (number_of_elements > kMaxNumberOfDescriptors) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015787
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015788 if (number_of_elements != NextEnumerationIndex()) {
15789 MaybeObject* maybe_result = GenerateNewEnumerationIndices();
15790 if (maybe_result->IsFailure()) return maybe_result;
15791 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015792
15793 int instance_descriptor_length = 0;
15794 int number_of_fields = 0;
15795
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015796 Heap* heap = GetHeap();
15797
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015798 // Compute the length of the instance descriptor.
15799 int capacity = Capacity();
15800 for (int i = 0; i < capacity; i++) {
15801 Object* k = KeyAt(i);
15802 if (IsKey(k)) {
15803 Object* value = ValueAt(i);
15804 PropertyType type = DetailsAt(i).type();
15805 ASSERT(type != FIELD);
15806 instance_descriptor_length++;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000015807 if (type == NORMAL && !value->IsJSFunction()) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000015808 number_of_fields += 1;
15809 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015810 }
15811 }
15812
yangguo@chromium.org304cc332012-07-24 07:59:48 +000015813 int inobject_props = obj->map()->inobject_properties();
15814
15815 // Allocate new map.
15816 Map* new_map;
15817 MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
15818 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015819 new_map->set_dictionary_map(false);
yangguo@chromium.org304cc332012-07-24 07:59:48 +000015820
15821 if (instance_descriptor_length == 0) {
15822 ASSERT_LE(unused_property_fields, inobject_props);
15823 // Transform the object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000015824 new_map->set_unused_property_fields(inobject_props);
yangguo@chromium.org304cc332012-07-24 07:59:48 +000015825 obj->set_map(new_map);
15826 obj->set_properties(heap->empty_fixed_array());
15827 // Check that it really works.
15828 ASSERT(obj->HasFastProperties());
15829 return obj;
15830 }
15831
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015832 // Allocate the instance descriptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015833 DescriptorArray* descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015834 MaybeObject* maybe_descriptors =
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000015835 DescriptorArray::Allocate(GetIsolate(), instance_descriptor_length);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015836 if (!maybe_descriptors->To(&descriptors)) {
15837 return maybe_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +000015838 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015839
ulan@chromium.org56c14af2012-09-20 12:51:09 +000015840 DescriptorArray::WhitenessWitness witness(descriptors);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015841
ager@chromium.org32912102009-01-16 10:38:43 +000015842 int number_of_allocated_fields =
15843 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000015844 if (number_of_allocated_fields < 0) {
15845 // There is enough inobject space for all fields (including unused).
15846 number_of_allocated_fields = 0;
15847 unused_property_fields = inobject_props - number_of_fields;
15848 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015849
15850 // Allocate the fixed array for the fields.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015851 FixedArray* fields;
15852 MaybeObject* maybe_fields =
15853 heap->AllocateFixedArray(number_of_allocated_fields);
15854 if (!maybe_fields->To(&fields)) return maybe_fields;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015855
15856 // Fill in the instance descriptor and the fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015857 int current_offset = 0;
15858 for (int i = 0; i < capacity; i++) {
15859 Object* k = KeyAt(i);
15860 if (IsKey(k)) {
15861 Object* value = ValueAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015862 Name* key;
15863 if (k->IsSymbol()) {
15864 key = Symbol::cast(k);
15865 } else {
15866 // Ensure the key is a unique name before writing into the
15867 // instance descriptor.
15868 MaybeObject* maybe_key = heap->InternalizeString(String::cast(k));
15869 if (!maybe_key->To(&key)) return maybe_key;
15870 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015872 PropertyDetails details = DetailsAt(i);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015873 int enumeration_index = details.dictionary_index();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015874 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000015875
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000015876 if (value->IsJSFunction()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000015877 ConstantDescriptor d(key, value, details.attributes());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015878 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015879 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000015880 if (current_offset < inobject_props) {
15881 obj->InObjectPropertyAtPut(current_offset,
15882 value,
15883 UPDATE_WRITE_BARRIER);
15884 } else {
15885 int offset = current_offset - inobject_props;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015886 fields->set(offset, value);
ager@chromium.org32912102009-01-16 10:38:43 +000015887 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015888 FieldDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015889 current_offset++,
15890 details.attributes(),
danno@chromium.orgf005df62013-04-30 16:36:45 +000015891 // TODO(verwaest): value->OptimalRepresentation();
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015892 Representation::Tagged());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015893 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015894 } else if (type == CALLBACKS) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015895 CallbacksDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015896 value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015897 details.attributes());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015898 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015899 } else {
15900 UNREACHABLE();
15901 }
15902 }
15903 }
15904 ASSERT(current_offset == number_of_fields);
15905
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015906 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015907
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000015908 new_map->InitializeDescriptors(descriptors);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000015909 new_map->set_unused_property_fields(unused_property_fields);
15910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015911 // Transform the object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000015912 obj->set_map(new_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000015913
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015914 obj->set_properties(fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015915 ASSERT(obj->IsJSObject());
15916
ager@chromium.org32912102009-01-16 10:38:43 +000015917 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015918 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000015919
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015920 return obj;
15921}
15922
15923
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015924Handle<ObjectHashSet> ObjectHashSet::EnsureCapacity(
15925 Handle<ObjectHashSet> table,
15926 int n,
15927 Handle<Object> key,
15928 PretenureFlag pretenure) {
15929 Handle<HashTable<ObjectHashTableShape<1>, Object*> > table_base = table;
15930 CALL_HEAP_FUNCTION(table_base->GetIsolate(),
15931 table_base->EnsureCapacity(n, *key, pretenure),
15932 ObjectHashSet);
15933}
15934
15935
15936Handle<ObjectHashSet> ObjectHashSet::Shrink(Handle<ObjectHashSet> table,
15937 Handle<Object> key) {
15938 Handle<HashTable<ObjectHashTableShape<1>, Object*> > table_base = table;
15939 CALL_HEAP_FUNCTION(table_base->GetIsolate(),
15940 table_base->Shrink(*key),
15941 ObjectHashSet);
15942}
15943
15944
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015945bool ObjectHashSet::Contains(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015946 ASSERT(IsKey(key));
15947
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015948 // If the object does not have an identity hash, it was never used as a key.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015949 Object* hash = key->GetHash();
15950 if (hash->IsUndefined()) return false;
15951
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015952 return (FindEntry(key) != kNotFound);
15953}
15954
15955
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015956Handle<ObjectHashSet> ObjectHashSet::Add(Handle<ObjectHashSet> table,
15957 Handle<Object> key) {
15958 ASSERT(table->IsKey(*key));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015959
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015960 // Make sure the key object has an identity hash code.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015961 Handle<Object> object_hash = Object::GetOrCreateHash(key,
15962 table->GetIsolate());
15963
15964 int entry = table->FindEntry(*key);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015965
15966 // Check whether key is already present.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015967 if (entry != kNotFound) return table;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015968
15969 // Check whether the hash set should be extended and add entry.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015970 Handle<ObjectHashSet> new_table =
15971 ObjectHashSet::EnsureCapacity(table, 1, key);
15972 entry = new_table->FindInsertionEntry(Smi::cast(*object_hash)->value());
15973 new_table->set(EntryToIndex(entry), *key);
15974 new_table->ElementAdded();
15975 return new_table;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015976}
15977
15978
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015979Handle<ObjectHashSet> ObjectHashSet::Remove(Handle<ObjectHashSet> table,
15980 Handle<Object> key) {
15981 ASSERT(table->IsKey(*key));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015982
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015983 // If the object does not have an identity hash, it was never used as a key.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015984 if (key->GetHash()->IsUndefined()) return table;
15985
15986 int entry = table->FindEntry(*key);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015987
15988 // Check whether key is actually present.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015989 if (entry == kNotFound) return table;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015990
15991 // Remove entry and try to shrink this hash set.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000015992 table->set_the_hole(EntryToIndex(entry));
15993 table->ElementRemoved();
15994
15995 return ObjectHashSet::Shrink(table, key);
15996}
15997
15998
15999Handle<ObjectHashTable> ObjectHashTable::EnsureCapacity(
16000 Handle<ObjectHashTable> table,
16001 int n,
16002 Handle<Object> key,
16003 PretenureFlag pretenure) {
16004 Handle<HashTable<ObjectHashTableShape<2>, Object*> > table_base = table;
16005 CALL_HEAP_FUNCTION(table_base->GetIsolate(),
16006 table_base->EnsureCapacity(n, *key, pretenure),
16007 ObjectHashTable);
16008}
16009
16010
16011Handle<ObjectHashTable> ObjectHashTable::Shrink(
16012 Handle<ObjectHashTable> table, Handle<Object> key) {
16013 Handle<HashTable<ObjectHashTableShape<2>, Object*> > table_base = table;
16014 CALL_HEAP_FUNCTION(table_base->GetIsolate(),
16015 table_base->Shrink(*key),
16016 ObjectHashTable);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000016017}
16018
16019
16020Object* ObjectHashTable::Lookup(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016021 ASSERT(IsKey(key));
16022
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000016023 // If the object does not have an identity hash, it was never used as a key.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000016024 Object* hash = key->GetHash();
16025 if (hash->IsUndefined()) {
16026 return GetHeap()->the_hole_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000016027 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016028 int entry = FindEntry(key);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000016029 if (entry == kNotFound) return GetHeap()->the_hole_value();
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016030 return get(EntryToIndex(entry) + 1);
16031}
16032
16033
verwaest@chromium.org057bd502013-11-06 12:03:29 +000016034Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
16035 Handle<Object> key,
16036 Handle<Object> value) {
16037 ASSERT(table->IsKey(*key));
16038
16039 Isolate* isolate = table->GetIsolate();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016040
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016041 // Make sure the key object has an identity hash code.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000016042 Handle<Object> hash = Object::GetOrCreateHash(key, isolate);
16043
16044 int entry = table->FindEntry(*key);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016045
16046 // Check whether to perform removal operation.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000016047 if (value->IsTheHole()) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000016048 if (entry == kNotFound) return table;
16049 table->RemoveEntry(entry);
16050 return Shrink(table, key);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016051 }
16052
16053 // Key is already in table, just overwrite value.
16054 if (entry != kNotFound) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +000016055 table->set(EntryToIndex(entry) + 1, *value);
16056 return table;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016057 }
16058
16059 // Check whether the hash table should be extended.
verwaest@chromium.org057bd502013-11-06 12:03:29 +000016060 table = EnsureCapacity(table, 1, key);
16061 table->AddEntry(table->FindInsertionEntry(Handle<Smi>::cast(hash)->value()),
16062 *key,
16063 *value);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016064 return table;
16065}
16066
16067
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000016068void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016069 set(EntryToIndex(entry), key);
16070 set(EntryToIndex(entry) + 1, value);
16071 ElementAdded();
16072}
16073
16074
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000016075void ObjectHashTable::RemoveEntry(int entry) {
16076 set_the_hole(EntryToIndex(entry));
16077 set_the_hole(EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000016078 ElementRemoved();
16079}
16080
16081
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000016082Object* WeakHashTable::Lookup(Object* key) {
16083 ASSERT(IsKey(key));
16084 int entry = FindEntry(key);
16085 if (entry == kNotFound) return GetHeap()->the_hole_value();
16086 return get(EntryToValueIndex(entry));
16087}
16088
16089
16090MaybeObject* WeakHashTable::Put(Object* key, Object* value) {
16091 ASSERT(IsKey(key));
16092 int entry = FindEntry(key);
16093 // Key is already in table, just overwrite value.
16094 if (entry != kNotFound) {
16095 set(EntryToValueIndex(entry), value);
16096 return this;
16097 }
16098
16099 // Check whether the hash table should be extended.
16100 Object* obj;
16101 { MaybeObject* maybe_obj = EnsureCapacity(1, key, TENURED);
16102 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
16103 }
16104 WeakHashTable* table = WeakHashTable::cast(obj);
16105 table->AddEntry(table->FindInsertionEntry(Hash(key)), key, value);
16106 return table;
16107}
16108
16109
16110void WeakHashTable::AddEntry(int entry, Object* key, Object* value) {
16111 set(EntryToIndex(entry), key);
16112 set(EntryToValueIndex(entry), value);
16113 ElementAdded();
16114}
16115
16116
ulan@chromium.org750145a2013-03-07 15:14:13 +000016117DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
16118 DeclaredAccessorDescriptor* descriptor)
16119 : array_(descriptor->serialized_data()->GetDataStartAddress()),
16120 length_(descriptor->serialized_data()->length()),
16121 offset_(0) {
16122}
16123
16124
16125const DeclaredAccessorDescriptorData*
16126 DeclaredAccessorDescriptorIterator::Next() {
16127 ASSERT(offset_ < length_);
16128 uint8_t* ptr = &array_[offset_];
16129 ASSERT(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
16130 const DeclaredAccessorDescriptorData* data =
16131 reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
16132 offset_ += sizeof(*data);
16133 ASSERT(offset_ <= length_);
16134 return data;
16135}
16136
16137
16138Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
16139 Isolate* isolate,
16140 const DeclaredAccessorDescriptorData& descriptor,
16141 Handle<DeclaredAccessorDescriptor> previous) {
16142 int previous_length =
16143 previous.is_null() ? 0 : previous->serialized_data()->length();
16144 int length = sizeof(descriptor) + previous_length;
16145 Handle<ByteArray> serialized_descriptor =
16146 isolate->factory()->NewByteArray(length);
16147 Handle<DeclaredAccessorDescriptor> value =
16148 isolate->factory()->NewDeclaredAccessorDescriptor();
16149 value->set_serialized_data(*serialized_descriptor);
16150 // Copy in the data.
16151 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000016152 DisallowHeapAllocation no_allocation;
ulan@chromium.org750145a2013-03-07 15:14:13 +000016153 uint8_t* array = serialized_descriptor->GetDataStartAddress();
16154 if (previous_length != 0) {
16155 uint8_t* previous_array =
16156 previous->serialized_data()->GetDataStartAddress();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000016157 OS::MemCopy(array, previous_array, previous_length);
ulan@chromium.org750145a2013-03-07 15:14:13 +000016158 array += previous_length;
16159 }
16160 ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
16161 DeclaredAccessorDescriptorData* data =
16162 reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
16163 *data = descriptor;
16164 }
16165 return value;
16166}
16167
16168
ager@chromium.org65dad4b2009-04-23 08:48:43 +000016169#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016170// Check if there is a break point at this code position.
16171bool DebugInfo::HasBreakPoint(int code_position) {
16172 // Get the break point info object for this code position.
16173 Object* break_point_info = GetBreakPointInfo(code_position);
16174
16175 // If there is no break point info object or no break points in the break
16176 // point info object there is no break point at this code position.
16177 if (break_point_info->IsUndefined()) return false;
16178 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
16179}
16180
16181
16182// Get the break point info object for this code position.
16183Object* DebugInfo::GetBreakPointInfo(int code_position) {
16184 // Find the index of the break point info object for this code position.
16185 int index = GetBreakPointInfoIndex(code_position);
16186
16187 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016188 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016189 return BreakPointInfo::cast(break_points()->get(index));
16190}
16191
16192
16193// Clear a break point at the specified code position.
16194void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
16195 int code_position,
16196 Handle<Object> break_point_object) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000016197 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000016198 debug_info->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016199 if (break_point_info->IsUndefined()) return;
16200 BreakPointInfo::ClearBreakPoint(
16201 Handle<BreakPointInfo>::cast(break_point_info),
16202 break_point_object);
16203}
16204
16205
16206void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
16207 int code_position,
16208 int source_position,
16209 int statement_position,
16210 Handle<Object> break_point_object) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000016211 Isolate* isolate = debug_info->GetIsolate();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000016212 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
16213 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016214 if (!break_point_info->IsUndefined()) {
16215 BreakPointInfo::SetBreakPoint(
16216 Handle<BreakPointInfo>::cast(break_point_info),
16217 break_point_object);
16218 return;
16219 }
16220
16221 // Adding a new break point for a code position which did not have any
16222 // break points before. Try to find a free slot.
16223 int index = kNoBreakPointInfo;
16224 for (int i = 0; i < debug_info->break_points()->length(); i++) {
16225 if (debug_info->break_points()->get(i)->IsUndefined()) {
16226 index = i;
16227 break;
16228 }
16229 }
16230 if (index == kNoBreakPointInfo) {
16231 // No free slot - extend break point info array.
16232 Handle<FixedArray> old_break_points =
16233 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016234 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016235 isolate->factory()->NewFixedArray(
16236 old_break_points->length() +
16237 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000016238
16239 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016240 for (int i = 0; i < old_break_points->length(); i++) {
16241 new_break_points->set(i, old_break_points->get(i));
16242 }
16243 index = old_break_points->length();
16244 }
16245 ASSERT(index != kNoBreakPointInfo);
16246
16247 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016248 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
16249 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016250 new_break_point_info->set_code_position(Smi::FromInt(code_position));
16251 new_break_point_info->set_source_position(Smi::FromInt(source_position));
16252 new_break_point_info->
16253 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016254 new_break_point_info->set_break_point_objects(
16255 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016256 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
16257 debug_info->break_points()->set(index, *new_break_point_info);
16258}
16259
16260
16261// Get the break point objects for a code position.
16262Object* DebugInfo::GetBreakPointObjects(int code_position) {
16263 Object* break_point_info = GetBreakPointInfo(code_position);
16264 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016265 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016266 }
16267 return BreakPointInfo::cast(break_point_info)->break_point_objects();
16268}
16269
16270
16271// Get the total number of break points.
16272int DebugInfo::GetBreakPointCount() {
16273 if (break_points()->IsUndefined()) return 0;
16274 int count = 0;
16275 for (int i = 0; i < break_points()->length(); i++) {
16276 if (!break_points()->get(i)->IsUndefined()) {
16277 BreakPointInfo* break_point_info =
16278 BreakPointInfo::cast(break_points()->get(i));
16279 count += break_point_info->GetBreakPointCount();
16280 }
16281 }
16282 return count;
16283}
16284
16285
16286Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
16287 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000016288 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016289 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016290 for (int i = 0; i < debug_info->break_points()->length(); i++) {
16291 if (!debug_info->break_points()->get(i)->IsUndefined()) {
16292 Handle<BreakPointInfo> break_point_info =
16293 Handle<BreakPointInfo>(BreakPointInfo::cast(
16294 debug_info->break_points()->get(i)));
16295 if (BreakPointInfo::HasBreakPointObject(break_point_info,
16296 break_point_object)) {
16297 return *break_point_info;
16298 }
16299 }
16300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016301 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016302}
16303
16304
16305// Find the index of the break point info object for the specified code
16306// position.
16307int DebugInfo::GetBreakPointInfoIndex(int code_position) {
16308 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
16309 for (int i = 0; i < break_points()->length(); i++) {
16310 if (!break_points()->get(i)->IsUndefined()) {
16311 BreakPointInfo* break_point_info =
16312 BreakPointInfo::cast(break_points()->get(i));
16313 if (break_point_info->code_position()->value() == code_position) {
16314 return i;
16315 }
16316 }
16317 }
16318 return kNoBreakPointInfo;
16319}
16320
16321
16322// Remove the specified break point object.
16323void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
16324 Handle<Object> break_point_object) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000016325 Isolate* isolate = break_point_info->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016326 // If there are no break points just ignore.
16327 if (break_point_info->break_point_objects()->IsUndefined()) return;
16328 // If there is a single break point clear it if it is the same.
16329 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16330 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016331 break_point_info->set_break_point_objects(
16332 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016333 }
16334 return;
16335 }
16336 // If there are multiple break points shrink the array
16337 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
16338 Handle<FixedArray> old_array =
16339 Handle<FixedArray>(
16340 FixedArray::cast(break_point_info->break_point_objects()));
16341 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016342 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016343 int found_count = 0;
16344 for (int i = 0; i < old_array->length(); i++) {
16345 if (old_array->get(i) == *break_point_object) {
16346 ASSERT(found_count == 0);
16347 found_count++;
16348 } else {
16349 new_array->set(i - found_count, old_array->get(i));
16350 }
16351 }
16352 // If the break point was found in the list change it.
16353 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
16354}
16355
16356
16357// Add the specified break point object.
16358void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
16359 Handle<Object> break_point_object) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000016360 Isolate* isolate = break_point_info->GetIsolate();
16361
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016362 // If there was no break point objects before just set it.
16363 if (break_point_info->break_point_objects()->IsUndefined()) {
16364 break_point_info->set_break_point_objects(*break_point_object);
16365 return;
16366 }
16367 // If the break point object is the same as before just ignore.
16368 if (break_point_info->break_point_objects() == *break_point_object) return;
16369 // If there was one break point object before replace with array.
16370 if (!break_point_info->break_point_objects()->IsFixedArray()) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000016371 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016372 array->set(0, break_point_info->break_point_objects());
16373 array->set(1, *break_point_object);
16374 break_point_info->set_break_point_objects(*array);
16375 return;
16376 }
16377 // If there was more than one break point before extend array.
16378 Handle<FixedArray> old_array =
16379 Handle<FixedArray>(
16380 FixedArray::cast(break_point_info->break_point_objects()));
16381 Handle<FixedArray> new_array =
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000016382 isolate->factory()->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016383 for (int i = 0; i < old_array->length(); i++) {
16384 // If the break point was there before just ignore.
16385 if (old_array->get(i) == *break_point_object) return;
16386 new_array->set(i, old_array->get(i));
16387 }
16388 // Add the new break point.
16389 new_array->set(old_array->length(), *break_point_object);
16390 break_point_info->set_break_point_objects(*new_array);
16391}
16392
16393
16394bool BreakPointInfo::HasBreakPointObject(
16395 Handle<BreakPointInfo> break_point_info,
16396 Handle<Object> break_point_object) {
16397 // No break point.
16398 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000016399 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016400 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16401 return break_point_info->break_point_objects() == *break_point_object;
16402 }
16403 // Multiple break points.
16404 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
16405 for (int i = 0; i < array->length(); i++) {
16406 if (array->get(i) == *break_point_object) {
16407 return true;
16408 }
16409 }
16410 return false;
16411}
16412
16413
16414// Get the number of break points.
16415int BreakPointInfo::GetBreakPointCount() {
16416 // No break point.
16417 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000016418 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016419 if (!break_point_objects()->IsFixedArray()) return 1;
16420 // Multiple break points.
16421 return FixedArray::cast(break_point_objects())->length();
16422}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000016423#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016424
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000016425
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000016426Object* JSDate::GetField(Object* object, Smi* index) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000016427 return JSDate::cast(object)->DoGetField(
16428 static_cast<FieldIndex>(index->value()));
16429}
16430
16431
16432Object* JSDate::DoGetField(FieldIndex index) {
16433 ASSERT(index != kDateValue);
16434
16435 DateCache* date_cache = GetIsolate()->date_cache();
16436
16437 if (index < kFirstUncachedField) {
16438 Object* stamp = cache_stamp();
16439 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
16440 // Since the stamp is not NaN, the value is also not NaN.
16441 int64_t local_time_ms =
16442 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
16443 SetLocalFields(local_time_ms, date_cache);
16444 }
16445 switch (index) {
16446 case kYear: return year();
16447 case kMonth: return month();
16448 case kDay: return day();
16449 case kWeekday: return weekday();
16450 case kHour: return hour();
16451 case kMinute: return min();
16452 case kSecond: return sec();
16453 default: UNREACHABLE();
16454 }
16455 }
16456
16457 if (index >= kFirstUTCField) {
16458 return GetUTCField(index, value()->Number(), date_cache);
16459 }
16460
16461 double time = value()->Number();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000016462 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000016463
16464 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
16465 int days = DateCache::DaysFromTime(local_time_ms);
16466
16467 if (index == kDays) return Smi::FromInt(days);
16468
16469 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16470 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
16471 ASSERT(index == kTimeInDay);
16472 return Smi::FromInt(time_in_day_ms);
16473}
16474
16475
16476Object* JSDate::GetUTCField(FieldIndex index,
16477 double value,
16478 DateCache* date_cache) {
16479 ASSERT(index >= kFirstUTCField);
16480
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000016481 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000016482
16483 int64_t time_ms = static_cast<int64_t>(value);
16484
16485 if (index == kTimezoneOffset) {
16486 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
16487 }
16488
16489 int days = DateCache::DaysFromTime(time_ms);
16490
16491 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
16492
16493 if (index <= kDayUTC) {
16494 int year, month, day;
16495 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16496 if (index == kYearUTC) return Smi::FromInt(year);
16497 if (index == kMonthUTC) return Smi::FromInt(month);
16498 ASSERT(index == kDayUTC);
16499 return Smi::FromInt(day);
16500 }
16501
16502 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
16503 switch (index) {
16504 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
16505 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
16506 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
16507 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
16508 case kDaysUTC: return Smi::FromInt(days);
16509 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
16510 default: UNREACHABLE();
16511 }
16512
16513 UNREACHABLE();
16514 return NULL;
16515}
16516
16517
16518void JSDate::SetValue(Object* value, bool is_value_nan) {
16519 set_value(value);
16520 if (is_value_nan) {
16521 HeapNumber* nan = GetIsolate()->heap()->nan_value();
16522 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
16523 set_year(nan, SKIP_WRITE_BARRIER);
16524 set_month(nan, SKIP_WRITE_BARRIER);
16525 set_day(nan, SKIP_WRITE_BARRIER);
16526 set_hour(nan, SKIP_WRITE_BARRIER);
16527 set_min(nan, SKIP_WRITE_BARRIER);
16528 set_sec(nan, SKIP_WRITE_BARRIER);
16529 set_weekday(nan, SKIP_WRITE_BARRIER);
16530 } else {
16531 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
16532 }
16533}
16534
16535
16536void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
16537 int days = DateCache::DaysFromTime(local_time_ms);
16538 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16539 int year, month, day;
16540 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16541 int weekday = date_cache->Weekday(days);
16542 int hour = time_in_day_ms / (60 * 60 * 1000);
16543 int min = (time_in_day_ms / (60 * 1000)) % 60;
16544 int sec = (time_in_day_ms / 1000) % 60;
16545 set_cache_stamp(date_cache->stamp());
16546 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
16547 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
16548 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
16549 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
16550 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
16551 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
16552 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
16553}
16554
danno@chromium.org1fd77d52013-06-07 16:01:45 +000016555
16556void JSArrayBuffer::Neuter() {
16557 ASSERT(is_external());
16558 set_backing_store(NULL);
16559 set_byte_length(Smi::FromInt(0));
16560}
16561
16562
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000016563void JSArrayBufferView::NeuterView() {
danno@chromium.org1fd77d52013-06-07 16:01:45 +000016564 set_byte_offset(Smi::FromInt(0));
16565 set_byte_length(Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000016566}
16567
16568
16569void JSDataView::Neuter() {
16570 NeuterView();
16571}
16572
16573
16574void JSTypedArray::Neuter() {
16575 NeuterView();
danno@chromium.org1fd77d52013-06-07 16:01:45 +000016576 set_length(Smi::FromInt(0));
16577 set_elements(GetHeap()->EmptyExternalArrayForMap(map()));
16578}
16579
danno@chromium.org41728482013-06-12 22:31:22 +000016580
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000016581Type* PropertyCell::type() {
danno@chromium.org41728482013-06-12 22:31:22 +000016582 return static_cast<Type*>(type_raw());
16583}
16584
16585
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000016586void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016587 ASSERT(IsPropertyCell());
danno@chromium.org41728482013-06-12 22:31:22 +000016588 set_type_raw(type, ignored);
16589}
16590
16591
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +000016592Handle<Type> PropertyCell::UpdatedType(Handle<PropertyCell> cell,
16593 Handle<Object> value) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016594 Isolate* isolate = cell->GetIsolate();
16595 Handle<Type> old_type(cell->type(), isolate);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000016596 // TODO(2803): Do not track ConsString as constant because they cannot be
16597 // embedded into code.
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +000016598 Handle<Type> new_type(value->IsConsString() || value->IsTheHole()
16599 ? Type::Any()
16600 : Type::Constant(value, isolate), isolate);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016601
16602 if (new_type->Is(old_type)) {
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +000016603 return old_type;
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016604 }
16605
16606 cell->dependent_code()->DeoptimizeDependentCodeGroup(
16607 isolate, DependentCode::kPropertyCellChangedGroup);
16608
16609 if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) {
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +000016610 return new_type;
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016611 }
16612
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +000016613 return handle(Type::Any(), isolate);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016614}
16615
16616
machenbach@chromium.org528ce022013-09-23 14:09:36 +000016617void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
bmeurer@chromium.org71f9fca2013-10-22 08:00:09 +000016618 Handle<Object> value) {
16619 cell->set_value(*value);
16620 if (!Type::Any()->Is(cell->type())) {
bmeurer@chromium.orgdb783292013-10-23 06:51:00 +000016621 Handle<Type> new_type = UpdatedType(cell, value);
16622 cell->set_type(*new_type);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016623 }
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016624}
16625
16626
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000016627void PropertyCell::AddDependentCompilationInfo(CompilationInfo* info) {
16628 Handle<DependentCode> dep(dependent_code());
16629 Handle<DependentCode> codes =
16630 DependentCode::Insert(dep, DependentCode::kPropertyCellChangedGroup,
16631 info->object_wrapper());
16632 if (*codes != dependent_code()) set_dependent_code(*codes);
16633 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
16634 Handle<HeapObject>(this), info->zone());
16635}
16636
16637
16638void PropertyCell::AddDependentCode(Handle<Code> code) {
16639 Handle<DependentCode> codes = DependentCode::Insert(
16640 Handle<DependentCode>(dependent_code()),
16641 DependentCode::kPropertyCellChangedGroup, code);
16642 if (*codes != dependent_code()) set_dependent_code(*codes);
16643}
16644
16645
danno@chromium.org59400602013-08-13 17:09:37 +000016646const char* GetBailoutReason(BailoutReason reason) {
16647 ASSERT(reason < kLastErrorMessage);
16648#define ERROR_MESSAGES_TEXTS(C, T) T,
16649 static const char* error_messages_[] = {
16650 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
16651 };
16652#undef ERROR_MESSAGES_TEXTS
16653 return error_messages_[reason];
16654}
16655
16656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016657} } // namespace v8::internal