blob: 96a3442f5e44888bcf19007e57018c8b9205ce44 [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
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000346MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
347 Object* structure,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000348 Name* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000349 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000351 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000353 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000355 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000356 Foreign::cast(structure)->foreign_address());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000357 MaybeObject* value = (callback->getter)(isolate, receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000359 return value;
360 }
361
362 // api style callbacks.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000363 if (structure->IsAccessorInfo()) {
364 if (!AccessorInfo::cast(structure)->IsCompatibleReceiver(receiver)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000365 Handle<Object> name_handle(name, isolate);
366 Handle<Object> receiver_handle(receiver, isolate);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000367 Handle<Object> args[2] = { name_handle, receiver_handle };
368 Handle<Object> error =
369 isolate->factory()->NewTypeError("incompatible_method_receiver",
370 HandleVector(args,
371 ARRAY_SIZE(args)));
372 return isolate->Throw(*error);
373 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000374 // TODO(rossberg): Handling symbols in the API requires changing the API,
375 // so we do not support it for now.
376 if (name->IsSymbol()) return isolate->heap()->undefined_value();
377 if (structure->IsDeclaredAccessorInfo()) {
378 return GetDeclaredAccessorProperty(receiver,
379 DeclaredAccessorInfo::cast(structure),
380 isolate);
381 }
382 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 Object* fun_obj = data->getter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +0000384 v8::AccessorGetterCallback call_fun =
385 v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000386 if (call_fun == NULL) return isolate->heap()->undefined_value();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000387 HandleScope scope(isolate);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000388 JSObject* self = JSObject::cast(receiver);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000389 Handle<String> key(String::cast(name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +0000391 PropertyCallbackArguments args(isolate, data->data(), self, this);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000392 v8::Handle<v8::Value> result =
393 args.Call(call_fun, v8::Utils::ToLocal(key));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
395 if (result.IsEmpty()) {
396 return isolate->heap()->undefined_value();
397 }
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000398 Object* return_value = *v8::Utils::OpenHandle(*result);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000399 return_value->VerifyApiCallResultType();
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000400 return return_value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
402
403 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000404 if (structure->IsAccessorPair()) {
405 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000406 if (getter->IsSpecFunction()) {
407 // TODO(rossberg): nicer would be to cast to some JSCallable here...
408 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409 }
410 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412 }
413
414 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000415 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000416}
417
418
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000419MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000420 Name* name_raw) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000421 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000422 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000423 Handle<Object> receiver(receiver_raw, isolate);
424 Handle<Object> name(name_raw, isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000425
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000426 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
427 if (name->IsSymbol()) return isolate->heap()->undefined_value();
428
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000429 Handle<Object> args[] = { receiver, name };
430 Handle<Object> result = CallTrap(
431 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000432 if (isolate->has_pending_exception()) return Failure::Exception();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000433
434 return *result;
435}
436
437
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000438Handle<Object> Object::GetProperty(Handle<Object> object,
439 Handle<Name> name) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000440 // TODO(rossberg): The index test should not be here but in the GetProperty
441 // method (or somewhere else entirely). Needs more global clean-up.
442 uint32_t index;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000443 Isolate* isolate = name->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +0000444 if (name->AsArrayIndex(&index))
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000445 return GetElement(isolate, object, index);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000446 CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object);
447}
448
449
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000450Handle<Object> Object::GetElement(Isolate* isolate,
451 Handle<Object> object,
452 uint32_t index) {
453 CALL_HEAP_FUNCTION(isolate, object->GetElement(isolate, index), Object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000454}
455
456
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000457MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
458 uint32_t index) {
459 String* name;
460 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
461 if (!maybe->To<String>(&name)) return maybe;
462 return GetPropertyWithHandler(receiver, name);
463}
464
465
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +0000466Handle<Object> JSProxy::SetElementWithHandler(Handle<JSProxy> proxy,
467 Handle<JSReceiver> receiver,
468 uint32_t index,
469 Handle<Object> value,
470 StrictModeFlag strict_mode) {
471 Isolate* isolate = proxy->GetIsolate();
472 Handle<String> name = isolate->factory()->Uint32ToString(index);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000473 return SetPropertyWithHandler(
474 proxy, receiver, name, value, NONE, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000475}
476
477
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000478bool JSProxy::HasElementWithHandler(Handle<JSProxy> proxy, uint32_t index) {
479 Isolate* isolate = proxy->GetIsolate();
480 Handle<String> name = isolate->factory()->Uint32ToString(index);
481 return HasPropertyWithHandler(proxy, name);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000482}
483
484
lrn@chromium.org303ada72010-10-27 09:33:13 +0000485MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000486 JSReceiver* getter) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000487 Isolate* isolate = getter->GetIsolate();
488 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000489 Handle<JSReceiver> fun(getter);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000490 Handle<Object> self(receiver, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000491#ifdef ENABLE_DEBUGGER_SUPPORT
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000492 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000493 // Handle stepping into a getter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000494 // TODO(rossberg): should this apply to getters that are function proxies?
495 if (debug->StepInActive() && fun->IsJSFunction()) {
496 debug->HandleStepIn(
497 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000498 }
499#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000500
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000501 bool has_pending_exception;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +0000502 Handle<Object> result = Execution::Call(
503 isolate, fun, self, 0, NULL, &has_pending_exception, true);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000504 // Check for pending exception and return the result.
505 if (has_pending_exception) return Failure::Exception();
506 return *result;
507}
508
509
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000510// TODO(yangguo): this should eventually replace the non-handlified version.
511Handle<Object> JSObject::GetPropertyWithCallback(Handle<JSObject> object,
512 Handle<Object> receiver,
513 Handle<Object> structure,
514 Handle<Name> name) {
515 CALL_HEAP_FUNCTION(object->GetIsolate(),
516 object->GetPropertyWithCallback(*receiver,
517 *structure,
518 *name),
519 Object);
520}
521
522
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000523// Only deal with CALLBACKS and INTERCEPTOR
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000524Handle<Object> JSObject::GetPropertyWithFailedAccessCheck(
525 Handle<JSObject> object,
526 Handle<Object> receiver,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000527 LookupResult* result,
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000528 Handle<Name> name,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000529 PropertyAttributes* attributes) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000530 Isolate* isolate = name->GetIsolate();
ager@chromium.org5c838252010-02-19 08:53:10 +0000531 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532 switch (result->type()) {
533 case CALLBACKS: {
534 // Only allow API accessors.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000535 Handle<Object> callback_obj(result->GetCallbackObject(), isolate);
536 if (callback_obj->IsAccessorInfo()) {
537 if (!AccessorInfo::cast(*callback_obj)->all_can_read()) break;
538 *attributes = result->GetAttributes();
539 // Fall through to GetPropertyWithCallback.
540 } else if (callback_obj->IsAccessorPair()) {
541 if (!AccessorPair::cast(*callback_obj)->all_can_read()) break;
542 // Fall through to GetPropertyWithCallback.
543 } else {
544 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 }
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000546 Handle<JSObject> holder(result->holder(), isolate);
547 return GetPropertyWithCallback(holder, receiver, callback_obj, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000548 }
549 case NORMAL:
550 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000551 case CONSTANT: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 // Search ALL_CAN_READ accessors in prototype chain.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000553 LookupResult r(isolate);
554 result->holder()->LookupRealNamedPropertyInPrototypes(*name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000555 if (r.IsProperty()) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000556 return GetPropertyWithFailedAccessCheck(
557 object, receiver, &r, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000558 }
559 break;
560 }
561 case INTERCEPTOR: {
562 // If the object has an interceptor, try real named properties.
563 // No access check in GetPropertyAttributeWithInterceptor.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000564 LookupResult r(isolate);
565 result->holder()->LookupRealNamedProperty(*name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000566 if (r.IsProperty()) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000567 return GetPropertyWithFailedAccessCheck(
568 object, receiver, &r, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000570 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000572 default:
573 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000574 }
575 }
576
ager@chromium.org8bb60582008-12-11 12:02:20 +0000577 // No accessible property found.
578 *attributes = ABSENT;
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000579 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_GET);
580 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
581 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000582}
583
584
ager@chromium.org870a0b62008-11-04 11:43:05 +0000585PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
586 Object* receiver,
587 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000588 Name* name,
ager@chromium.org870a0b62008-11-04 11:43:05 +0000589 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000590 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000591 switch (result->type()) {
592 case CALLBACKS: {
593 // Only allow API accessors.
594 Object* obj = result->GetCallbackObject();
595 if (obj->IsAccessorInfo()) {
596 AccessorInfo* info = AccessorInfo::cast(obj);
597 if (info->all_can_read()) {
598 return result->GetAttributes();
599 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +0000600 } else if (obj->IsAccessorPair()) {
601 AccessorPair* pair = AccessorPair::cast(obj);
602 if (pair->all_can_read()) {
603 return result->GetAttributes();
604 }
ager@chromium.org870a0b62008-11-04 11:43:05 +0000605 }
606 break;
607 }
608
609 case NORMAL:
610 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000611 case CONSTANT: {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000612 if (!continue_search) break;
613 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000614 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000615 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000616 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000617 return GetPropertyAttributeWithFailedAccessCheck(receiver,
618 &r,
619 name,
620 continue_search);
621 }
622 break;
623 }
624
625 case INTERCEPTOR: {
626 // If the object has an interceptor, try real named properties.
627 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000628 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000629 if (continue_search) {
630 result->holder()->LookupRealNamedProperty(name, &r);
631 } else {
632 result->holder()->LocalLookupRealNamedProperty(name, &r);
633 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000634 if (!r.IsFound()) break;
635 return GetPropertyAttributeWithFailedAccessCheck(receiver,
636 &r,
637 name,
638 continue_search);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000639 }
640
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000641 case HANDLER:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000642 case TRANSITION:
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000643 case NONEXISTENT:
ager@chromium.org5c838252010-02-19 08:53:10 +0000644 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000645 }
646 }
647
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000648 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000649 return ABSENT;
650}
651
652
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000653Object* JSObject::GetNormalizedProperty(LookupResult* result) {
654 ASSERT(!HasFastProperties());
655 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
656 if (IsGlobalObject()) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000657 value = PropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000658 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +0000659 ASSERT(!value->IsPropertyCell() && !value->IsCell());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000660 return value;
661}
662
663
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000664void JSObject::SetNormalizedProperty(Handle<JSObject> object,
665 LookupResult* result,
666 Handle<Object> value) {
667 ASSERT(!object->HasFastProperties());
668 NameDictionary* property_dictionary = object->property_dictionary();
669 if (object->IsGlobalObject()) {
670 Handle<PropertyCell> cell(PropertyCell::cast(
671 property_dictionary->ValueAt(result->GetDictionaryEntry())));
672 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000673 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000674 property_dictionary->ValueAtPut(result->GetDictionaryEntry(), *value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000675 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000676}
677
678
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000679// TODO(mstarzinger): Temporary wrapper until handlified.
680static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict,
681 Handle<Name> name,
682 Handle<Object> value,
683 PropertyDetails details) {
684 CALL_HEAP_FUNCTION(dict->GetIsolate(),
685 dict->Add(*name, *value, details),
686 NameDictionary);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000687}
688
689
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000690void JSObject::SetNormalizedProperty(Handle<JSObject> object,
691 Handle<Name> name,
692 Handle<Object> value,
693 PropertyDetails details) {
694 ASSERT(!object->HasFastProperties());
695 Handle<NameDictionary> property_dictionary(object->property_dictionary());
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000696
697 if (!name->IsUniqueName()) {
698 name = object->GetIsolate()->factory()->InternalizedStringFromString(
699 Handle<String>::cast(name));
700 }
701
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000702 int entry = property_dictionary->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000703 if (entry == NameDictionary::kNotFound) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000704 Handle<Object> store_value = value;
705 if (object->IsGlobalObject()) {
706 store_value = object->GetIsolate()->factory()->NewPropertyCell(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000707 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +0000708
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000709 property_dictionary =
710 NameDictionaryAdd(property_dictionary, name, store_value, details);
711 object->set_properties(*property_dictionary);
712 return;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000713 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000714
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000715 PropertyDetails original_details = property_dictionary->DetailsAt(entry);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000716 int enumeration_index;
717 // Preserve the enumeration index unless the property was deleted.
718 if (original_details.IsDeleted()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000719 enumeration_index = property_dictionary->NextEnumerationIndex();
720 property_dictionary->SetNextEnumerationIndex(enumeration_index + 1);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000721 } else {
722 enumeration_index = original_details.dictionary_index();
723 ASSERT(enumeration_index > 0);
724 }
725
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000726 details = PropertyDetails(
727 details.attributes(), details.type(), enumeration_index);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000728
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000729 if (object->IsGlobalObject()) {
730 Handle<PropertyCell> cell(
731 PropertyCell::cast(property_dictionary->ValueAt(entry)));
732 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000733 // Please note we have to update the property details.
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000734 property_dictionary->DetailsAtPut(entry, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000735 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000736 property_dictionary->SetEntry(entry, *name, *value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000737 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000738}
739
740
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000741// TODO(mstarzinger): Temporary wrapper until target is handlified.
742Handle<NameDictionary> NameDictionaryShrink(Handle<NameDictionary> dict,
743 Handle<Name> name) {
744 CALL_HEAP_FUNCTION(dict->GetIsolate(), dict->Shrink(*name), NameDictionary);
745}
746
747
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000748Handle<Object> JSObject::DeleteNormalizedProperty(Handle<JSObject> object,
749 Handle<Name> name,
750 DeleteMode mode) {
751 ASSERT(!object->HasFastProperties());
752 Isolate* isolate = object->GetIsolate();
753 Handle<NameDictionary> dictionary(object->property_dictionary());
754 int entry = dictionary->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000755 if (entry != NameDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000756 // If we have a global object set the cell to the hole.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000757 if (object->IsGlobalObject()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000758 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000759 if (details.IsDontDelete()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000760 if (mode != FORCE_DELETION) return isolate->factory()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000761 // When forced to delete global properties, we have to make a
762 // map change to invalidate any ICs that think they can load
763 // from the DontDelete cell without checking if it contains
764 // the hole value.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000765 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
erik.corry@gmail.com88767242012-08-08 14:43:45 +0000766 ASSERT(new_map->is_dictionary_map());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000767 object->set_map(*new_map);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000768 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000769 Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000770 Handle<Object> value = isolate->factory()->the_hole_value();
771 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000772 dictionary->DetailsAtPut(entry, details.AsDeleted());
773 } else {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000774 Handle<Object> deleted(dictionary->DeleteProperty(entry, mode), isolate);
775 if (*deleted == isolate->heap()->true_value()) {
776 Handle<NameDictionary> new_properties =
777 NameDictionaryShrink(dictionary, name);
778 object->set_properties(*new_properties);
ager@chromium.org04921a82011-06-27 13:21:41 +0000779 }
780 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000781 }
782 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +0000783 return isolate->factory()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000784}
785
786
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000787bool JSObject::IsDirty() {
788 Object* cons_obj = map()->constructor();
789 if (!cons_obj->IsJSFunction())
790 return true;
791 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000792 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000793 return true;
794 // If the object is fully fast case and has the same map it was
795 // created with then no changes can have been made to it.
796 return map() != fun->initial_map()
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000797 || !HasFastObjectElements()
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000798 || !HasFastProperties();
799}
800
801
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000802Handle<Object> Object::GetProperty(Handle<Object> object,
803 Handle<Object> receiver,
804 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000805 Handle<Name> key,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000806 PropertyAttributes* attributes) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000807 Isolate* isolate = result->isolate();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000808 CALL_HEAP_FUNCTION(
809 isolate,
810 object->GetProperty(*receiver, result, *key, attributes),
811 Object);
812}
813
814
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000815MaybeObject* Object::GetPropertyOrFail(Handle<Object> object,
816 Handle<Object> receiver,
817 LookupResult* result,
818 Handle<Name> key,
819 PropertyAttributes* attributes) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000820 Isolate* isolate = result->isolate();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000821 CALL_HEAP_FUNCTION_PASS_EXCEPTION(
822 isolate,
823 object->GetProperty(*receiver, result, *key, attributes));
824}
825
826
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000827// TODO(yangguo): handlify this and get rid of.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000828MaybeObject* Object::GetProperty(Object* receiver,
829 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000830 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000831 PropertyAttributes* attributes) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000832 Isolate* isolate = name->GetIsolate();
833 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +0000835#ifdef DEBUG
836 // TODO(mstarzinger): Only because of the AssertNoContextChange, drop as soon
837 // as this method has been fully handlified.
838 HandleScope scope(isolate);
839#endif
840
841 // Make sure that the top context does not change when doing
842 // callbacks or interceptor calls.
843 AssertNoContextChange ncc(isolate);
844
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000846 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847 // objects more than once in case of interceptors, because the
848 // holder will always be the interceptor holder and the search may
849 // only continue with a current object just after the interceptor
850 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000851 // Proxy handlers do not use the proxy's prototype, so we can skip this.
852 if (!result->IsHandler()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000853 Object* last = result->IsProperty()
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000854 ? result->holder()
855 : Object::cast(heap->null_value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000856 ASSERT(this != this->GetPrototype(isolate));
857 for (Object* current = this;
858 true;
859 current = current->GetPrototype(isolate)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000860 if (current->IsAccessCheckNeeded()) {
861 // Check if we're allowed to read from the current object. Note
862 // that even though we may not actually end up loading the named
863 // property from the current object, we still check that we have
864 // access to it.
865 JSObject* checked = JSObject::cast(current);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000866 if (!isolate->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
867 HandleScope scope(isolate);
868 Handle<Object> value = JSObject::GetPropertyWithFailedAccessCheck(
869 handle(checked, isolate),
870 handle(receiver, isolate),
871 result,
872 handle(name, isolate),
873 attributes);
874 RETURN_IF_EMPTY_HANDLE(isolate, value);
875 return *value;
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000876 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000877 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000878 // Stop traversing the chain once we reach the last object in the
879 // chain; either the holder of the result or null in case of an
880 // absent property.
881 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000883 }
884
kasper.lund44510672008-07-25 07:37:58 +0000885 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000887 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888 }
889 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000891 switch (result->type()) {
892 case NORMAL:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000893 value = result->holder()->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 return value->IsTheHole() ? heap->undefined_value() : value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000896 case FIELD: {
897 MaybeObject* maybe_result = result->holder()->FastPropertyAt(
898 result->representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000899 result->GetFieldIndex().field_index());
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000900 if (!maybe_result->To(&value)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000901 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000902 return value->IsTheHole() ? heap->undefined_value() : value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000903 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +0000904 case CONSTANT:
905 return result->GetConstant();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 case CALLBACKS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000907 return result->holder()->GetPropertyWithCallback(
908 receiver, result->GetCallbackObject(), name);
909 case HANDLER:
910 return result->proxy()->GetPropertyWithHandler(receiver, name);
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +0000911 case INTERCEPTOR: {
912 HandleScope scope(isolate);
913 Handle<Object> value = JSObject::GetPropertyWithInterceptor(
914 handle(result->holder(), isolate),
915 handle(receiver, isolate),
916 handle(name, isolate),
917 attributes);
918 RETURN_IF_EMPTY_HANDLE(isolate, value);
919 return *value;
920 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000921 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000922 case NONEXISTENT:
923 UNREACHABLE();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000924 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000926 UNREACHABLE();
927 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928}
929
930
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +0000931MaybeObject* Object::GetElementWithReceiver(Isolate* isolate,
932 Object* receiver,
933 uint32_t index) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000934 Heap* heap = isolate->heap();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000935 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000936
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000937 // Iterate up the prototype chain until an element is found or the null
938 // prototype is encountered.
939 for (holder = this;
940 holder != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000941 holder = holder->GetPrototype(isolate)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000942 if (!holder->IsJSObject()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000943 Context* native_context = isolate->context()->native_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000944 if (holder->IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000945 holder = native_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000946 } else if (holder->IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000947 holder = native_context->string_function()->instance_prototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000948 } else if (holder->IsSymbol()) {
949 holder = native_context->symbol_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000950 } else if (holder->IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000951 holder = native_context->boolean_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000952 } else if (holder->IsJSProxy()) {
953 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
954 } else {
955 // Undefined and null have no indexed properties.
956 ASSERT(holder->IsUndefined() || holder->IsNull());
957 return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000958 }
959 }
960
961 // Inline the case for JSObjects. Doing so significantly improves the
962 // performance of fetching elements where checking the prototype chain is
963 // necessary.
964 JSObject* js_object = JSObject::cast(holder);
965
966 // Check access rights if needed.
967 if (js_object->IsAccessCheckNeeded()) {
968 Isolate* isolate = heap->isolate();
969 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
970 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
danno@chromium.org169691d2013-07-15 08:01:13 +0000971 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000972 return heap->undefined_value();
973 }
974 }
975
976 if (js_object->HasIndexedInterceptor()) {
977 return js_object->GetElementWithInterceptor(receiver, index);
978 }
979
980 if (js_object->elements() != heap->empty_fixed_array()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000981 MaybeObject* result = js_object->GetElementsAccessor()->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000982 receiver, js_object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000983 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000984 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000985 }
986
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000987 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000988}
989
990
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000991Object* Object::GetPrototype(Isolate* isolate) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992 if (IsSmi()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000993 Context* context = isolate->context()->native_context();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000994 return context->number_function()->instance_prototype();
995 }
996
997 HeapObject* heap_object = HeapObject::cast(this);
998
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000999 // The object is either a number, a string, a boolean,
1000 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001001 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001002 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001003 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001004 Context* context = isolate->context()->native_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001006 if (heap_object->IsHeapNumber()) {
1007 return context->number_function()->instance_prototype();
1008 }
1009 if (heap_object->IsString()) {
1010 return context->string_function()->instance_prototype();
1011 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001012 if (heap_object->IsSymbol()) {
1013 return context->symbol_function()->instance_prototype();
1014 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001015 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016 return context->boolean_function()->instance_prototype();
1017 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001018 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 }
1020}
1021
1022
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001023MaybeObject* Object::GetHash(CreationFlag flag) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001024 // The object is either a number, a name, an odd-ball,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001025 // a real JS object, or a Harmony proxy.
1026 if (IsNumber()) {
1027 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
1028 return Smi::FromInt(hash & Smi::kMaxValue);
1029 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001030 if (IsName()) {
1031 uint32_t hash = Name::cast(this)->Hash();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001032 return Smi::FromInt(hash);
1033 }
1034 if (IsOddball()) {
1035 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
1036 return Smi::FromInt(hash);
1037 }
1038 if (IsJSReceiver()) {
1039 return JSReceiver::cast(this)->GetIdentityHash(flag);
1040 }
1041
1042 UNREACHABLE();
1043 return Smi::FromInt(0);
1044}
1045
1046
1047bool Object::SameValue(Object* other) {
1048 if (other == this) return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001049
ulan@chromium.org750145a2013-03-07 15:14:13 +00001050 // The object is either a number, a name, an odd-ball,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001051 // a real JS object, or a Harmony proxy.
1052 if (IsNumber() && other->IsNumber()) {
1053 double this_value = Number();
1054 double other_value = other->Number();
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00001055 bool equal = this_value == other_value;
1056 // SameValue(NaN, NaN) is true.
1057 if (!equal) return std::isnan(this_value) && std::isnan(other_value);
1058 // SameValue(0.0, -0.0) is false.
1059 return (this_value != 0) || ((1 / this_value) == (1 / other_value));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001060 }
1061 if (IsString() && other->IsString()) {
1062 return String::cast(this)->Equals(String::cast(other));
1063 }
1064 return false;
1065}
1066
1067
whesse@chromium.org023421e2010-12-21 12:19:12 +00001068void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069 HeapStringAllocator allocator;
1070 StringStream accumulator(&allocator);
1071 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001072 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001073}
1074
1075
1076void Object::ShortPrint(StringStream* accumulator) {
1077 if (IsSmi()) {
1078 Smi::cast(this)->SmiPrint(accumulator);
1079 } else if (IsFailure()) {
1080 Failure::cast(this)->FailurePrint(accumulator);
1081 } else {
1082 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
1083 }
1084}
1085
1086
whesse@chromium.org023421e2010-12-21 12:19:12 +00001087void Smi::SmiPrint(FILE* out) {
1088 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001089}
1090
1091
1092void Smi::SmiPrint(StringStream* accumulator) {
1093 accumulator->Add("%d", value());
1094}
1095
1096
1097void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001098 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099}
1100
1101
whesse@chromium.org023421e2010-12-21 12:19:12 +00001102void Failure::FailurePrint(FILE* out) {
1103 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104}
1105
1106
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1108// English? Returns false for non-ASCII or words that don't start with
1109// a capital letter. The a/an rule follows pronunciation in English.
1110// We don't use the BBC's overcorrect "an historic occasion" though if
1111// you speak a dialect you may well say "an 'istoric occasion".
1112static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001113 if (str->length() == 0) return false; // A nothing.
1114 int c0 = str->Get(0);
1115 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001116 if (c0 == 'U') {
1117 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001118 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119 }
1120 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001121 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001122 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1123 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1124 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001125 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126 }
1127 return false;
1128}
1129
1130
lrn@chromium.org303ada72010-10-27 09:33:13 +00001131MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001132#ifdef DEBUG
1133 // Do not attempt to flatten in debug mode when allocation is not
1134 // allowed. This is to avoid an assertion failure when allocating.
1135 // Flattening strings is the only case where we always allow
1136 // allocation because no GC is performed if the allocation fails.
rossberg@chromium.org79e79022013-06-03 15:43:46 +00001137 if (!AllowHeapAllocation::IsAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138#endif
1139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001141 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 case kConsStringTag: {
1143 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001144 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001145 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146 }
1147 // There's little point in putting the flat string in new space if the
1148 // cons string is in old space. It can never get GCed until there is
1149 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001151 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001152 Object* object;
1153 String* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001154 if (IsOneByteRepresentation()) {
1155 { MaybeObject* maybe_object =
1156 heap->AllocateRawOneByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001157 if (!maybe_object->ToObject(&object)) return maybe_object;
1158 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001159 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001160 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001161 int first_length = first->length();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001162 uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001163 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001164 String* second = cs->second();
1165 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001166 dest + first_length,
1167 0,
1168 len - first_length);
1169 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001170 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001172 if (!maybe_object->ToObject(&object)) return maybe_object;
1173 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001174 result = String::cast(object);
1175 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001176 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001177 int first_length = first->length();
1178 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001179 String* second = cs->second();
1180 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001181 dest + first_length,
1182 0,
1183 len - first_length);
1184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 cs->set_first(result);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001186 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001187 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 }
1189 default:
1190 return this;
1191 }
1192}
1193
1194
ager@chromium.org6f10e412009-02-13 10:11:16 +00001195bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00001196 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001197 // prohibited by the API.
1198 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001199#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +00001200 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001201 // Assert that the resource and the string are equivalent.
1202 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001203 ScopedVector<uc16> smart_chars(this->length());
1204 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1205 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001206 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001207 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001208 }
1209#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001210 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001211 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001212 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001213 return false;
1214 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001215 bool is_ascii = this->IsOneByteRepresentation();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001216 bool is_internalized = this->IsInternalizedString();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001217
1218 // Morph the object to an external string by adjusting the map and
1219 // reinitializing the fields.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001220 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001221 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001222 is_internalized
1223 ? (is_ascii
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001224 ? heap->external_internalized_string_with_one_byte_data_map()
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001225 : heap->external_internalized_string_map())
1226 : (is_ascii
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001227 ? heap->external_string_with_one_byte_data_map()
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001228 : heap->external_string_map()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001229 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001230 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001231 is_internalized
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001232 ? (is_ascii
1233 ? heap->
1234 short_external_internalized_string_with_one_byte_data_map()
1235 : heap->short_external_internalized_string_map())
1236 : (is_ascii
1237 ? heap->short_external_string_with_one_byte_data_map()
1238 : heap->short_external_string_map()));
ager@chromium.org6f10e412009-02-13 10:11:16 +00001239 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001240 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1241 self->set_resource(resource);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001242 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001243
1244 // Fill the remainder of the string with dead wood.
1245 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001246 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001247 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001248 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1249 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001250 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001251 return true;
1252}
1253
1254
1255bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
1256#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +00001257 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001258 // Assert that the resource and the string are equivalent.
1259 ASSERT(static_cast<size_t>(this->length()) == resource->length());
ulan@chromium.orgdfe53072013-06-06 14:14:51 +00001260 if (this->IsTwoByteRepresentation()) {
1261 ScopedVector<uint16_t> smart_chars(this->length());
1262 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1263 ASSERT(String::IsOneByte(smart_chars.start(), this->length()));
1264 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001265 ScopedVector<char> smart_chars(this->length());
1266 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1267 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001268 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001269 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001270 }
1271#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001272 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001273 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001274 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001275 return false;
1276 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001277 bool is_internalized = this->IsInternalizedString();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001278
1279 // Morph the object to an external string by adjusting the map and
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001280 // reinitializing the fields. Use short version if space is limited.
1281 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001282 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001283 is_internalized ? heap->external_ascii_internalized_string_map()
1284 : heap->external_ascii_string_map());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001285 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001286 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001287 is_internalized ? heap->short_external_ascii_internalized_string_map()
1288 : heap->short_external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001289 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001290 ExternalAsciiString* self = ExternalAsciiString::cast(this);
1291 self->set_resource(resource);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001292 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001293
1294 // Fill the remainder of the string with dead wood.
1295 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001296 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001297 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001298 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1299 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001301 return true;
1302}
1303
1304
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001306 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001307 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001308 accumulator->Add("<Very long string[%u]>", len);
1309 return;
1310 }
1311
1312 if (!LooksValid()) {
1313 accumulator->Add("<Invalid String>");
1314 return;
1315 }
1316
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001317 ConsStringIteratorOp op;
1318 StringCharacterStream stream(this, &op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
1320 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +00001321 if (len > kMaxShortPrintLength) {
1322 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001323 truncated = true;
1324 }
1325 bool ascii = true;
1326 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001327 uint16_t c = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328
1329 if (c < 32 || c >= 127) {
1330 ascii = false;
1331 }
1332 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001333 stream.Reset(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001335 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001337 accumulator->Put(static_cast<char>(stream.GetNext()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 }
1339 accumulator->Put('>');
1340 } else {
1341 // Backslash indicates that the string contains control
1342 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001343 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001345 uint16_t c = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 if (c == '\n') {
1347 accumulator->Add("\\n");
1348 } else if (c == '\r') {
1349 accumulator->Add("\\r");
1350 } else if (c == '\\') {
1351 accumulator->Add("\\\\");
1352 } else if (c < 32 || c > 126) {
1353 accumulator->Add("\\x%02x", c);
1354 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001355 accumulator->Put(static_cast<char>(c));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 }
1357 }
1358 if (truncated) {
1359 accumulator->Put('.');
1360 accumulator->Put('.');
1361 accumulator->Put('.');
1362 }
1363 accumulator->Put('>');
1364 }
1365 return;
1366}
1367
1368
1369void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1370 switch (map()->instance_type()) {
1371 case JS_ARRAY_TYPE: {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001372 double length = JSArray::cast(this)->length()->IsUndefined()
1373 ? 0
1374 : JSArray::cast(this)->length()->Number();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001375 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376 break;
1377 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001378 case JS_WEAK_MAP_TYPE: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001379 accumulator->Add("<JS WeakMap>");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001380 break;
1381 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001382 case JS_WEAK_SET_TYPE: {
1383 accumulator->Add("<JS WeakSet>");
1384 break;
1385 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001386 case JS_REGEXP_TYPE: {
1387 accumulator->Add("<JS RegExp>");
1388 break;
1389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001390 case JS_FUNCTION_TYPE: {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001391 JSFunction* function = JSFunction::cast(this);
1392 Object* fun_name = function->shared()->DebugName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 bool printed = false;
1394 if (fun_name->IsString()) {
1395 String* str = String::cast(fun_name);
1396 if (str->length() > 0) {
1397 accumulator->Add("<JS Function ");
1398 accumulator->Put(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001399 printed = true;
1400 }
1401 }
1402 if (!printed) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001403 accumulator->Add("<JS Function");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001405 accumulator->Add(" (SharedFunctionInfo %p)",
1406 reinterpret_cast<void*>(function->shared()));
1407 accumulator->Put('>');
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001408 break;
1409 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001410 case JS_GENERATOR_OBJECT_TYPE: {
1411 accumulator->Add("<JS Generator>");
1412 break;
1413 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001414 case JS_MODULE_TYPE: {
1415 accumulator->Add("<JS Module>");
1416 break;
1417 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001419 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001421 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001422 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001423 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424 bool printed = false;
1425 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001426 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1428 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001429 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001431 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001432 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1433 } else {
1434 Object* constructor_name =
1435 JSFunction::cast(constructor)->shared()->name();
1436 if (constructor_name->IsString()) {
1437 String* str = String::cast(constructor_name);
1438 if (str->length() > 0) {
1439 bool vowel = AnWord(str);
1440 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001441 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 vowel ? "n" : "");
1443 accumulator->Put(str);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001444 accumulator->Add(" with %smap %p",
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001445 map_of_this->is_deprecated() ? "deprecated " : "",
1446 map_of_this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447 printed = true;
1448 }
1449 }
1450 }
1451 }
1452 if (!printed) {
1453 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1454 }
1455 }
1456 if (IsJSValue()) {
1457 accumulator->Add(" value = ");
1458 JSValue::cast(this)->value()->ShortPrint(accumulator);
1459 }
1460 accumulator->Put('>');
1461 break;
1462 }
1463 }
1464}
1465
1466
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001467void JSObject::PrintElementsTransition(
1468 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1469 ElementsKind to_kind, FixedArrayBase* to_elements) {
1470 if (from_kind != to_kind) {
1471 PrintF(file, "elements transition [");
1472 PrintElementsKind(file, from_kind);
1473 PrintF(file, " -> ");
1474 PrintElementsKind(file, to_kind);
1475 PrintF(file, "] in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001476 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001477 PrintF(file, " for ");
1478 ShortPrint(file);
1479 PrintF(file, " from ");
1480 from_elements->ShortPrint(file);
1481 PrintF(file, " to ");
1482 to_elements->ShortPrint(file);
1483 PrintF(file, "\n");
1484 }
1485}
1486
1487
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001488void Map::PrintGeneralization(FILE* file,
rossberg@chromium.org92597162013-08-23 13:28:00 +00001489 const char* reason,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001490 int modify_index,
1491 int split,
1492 int descriptors,
rossberg@chromium.org92597162013-08-23 13:28:00 +00001493 bool constant_to_field,
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001494 Representation old_representation,
1495 Representation new_representation) {
1496 PrintF(file, "[generalizing ");
1497 constructor_name()->PrintOn(file);
1498 PrintF(file, "] ");
1499 String::cast(instance_descriptors()->GetKey(modify_index))->PrintOn(file);
rossberg@chromium.org92597162013-08-23 13:28:00 +00001500 if (constant_to_field) {
1501 PrintF(file, ":c->f");
1502 } else {
1503 PrintF(file, ":%s->%s",
1504 old_representation.Mnemonic(),
1505 new_representation.Mnemonic());
1506 }
1507 PrintF(file, " (");
1508 if (strlen(reason) > 0) {
1509 PrintF(file, "%s", reason);
1510 } else {
1511 PrintF(file, "+%i maps", descriptors - split);
1512 }
1513 PrintF(file, ") [");
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001514 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
1515 PrintF(file, "]\n");
1516}
1517
1518
1519void JSObject::PrintInstanceMigration(FILE* file,
1520 Map* original_map,
1521 Map* new_map) {
1522 PrintF(file, "[migrating ");
1523 map()->constructor_name()->PrintOn(file);
1524 PrintF(file, "] ");
1525 DescriptorArray* o = original_map->instance_descriptors();
1526 DescriptorArray* n = new_map->instance_descriptors();
1527 for (int i = 0; i < original_map->NumberOfOwnDescriptors(); i++) {
1528 Representation o_r = o->GetDetails(i).representation();
1529 Representation n_r = n->GetDetails(i).representation();
1530 if (!o_r.Equals(n_r)) {
1531 String::cast(o->GetKey(i))->PrintOn(file);
1532 PrintF(file, ":%s->%s ", o_r.Mnemonic(), n_r.Mnemonic());
1533 } else if (o->GetDetails(i).type() == CONSTANT &&
1534 n->GetDetails(i).type() == FIELD) {
1535 Name* name = o->GetKey(i);
1536 if (name->IsString()) {
1537 String::cast(name)->PrintOn(file);
1538 } else {
1539 PrintF(file, "???");
1540 }
1541 PrintF(file, " ");
1542 }
1543 }
1544 PrintF(file, "\n");
1545}
1546
1547
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001549 Heap* heap = GetHeap();
1550 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 accumulator->Add("!!!INVALID POINTER!!!");
1552 return;
1553 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001554 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 accumulator->Add("!!!INVALID MAP!!!");
1556 return;
1557 }
1558
1559 accumulator->Add("%p ", this);
1560
1561 if (IsString()) {
1562 String::cast(this)->StringShortPrint(accumulator);
1563 return;
1564 }
1565 if (IsJSObject()) {
1566 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1567 return;
1568 }
1569 switch (map()->instance_type()) {
1570 case MAP_TYPE:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001571 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 break;
1573 case FIXED_ARRAY_TYPE:
1574 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1575 break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001576 case FIXED_DOUBLE_ARRAY_TYPE:
1577 accumulator->Add("<FixedDoubleArray[%u]>",
1578 FixedDoubleArray::cast(this)->length());
1579 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 case BYTE_ARRAY_TYPE:
1581 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1582 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001583 case FREE_SPACE_TYPE:
1584 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1585 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001586 case EXTERNAL_PIXEL_ARRAY_TYPE:
1587 accumulator->Add("<ExternalPixelArray[%u]>",
1588 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001589 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001590 case EXTERNAL_BYTE_ARRAY_TYPE:
1591 accumulator->Add("<ExternalByteArray[%u]>",
1592 ExternalByteArray::cast(this)->length());
1593 break;
1594 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1595 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1596 ExternalUnsignedByteArray::cast(this)->length());
1597 break;
1598 case EXTERNAL_SHORT_ARRAY_TYPE:
1599 accumulator->Add("<ExternalShortArray[%u]>",
1600 ExternalShortArray::cast(this)->length());
1601 break;
1602 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1603 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1604 ExternalUnsignedShortArray::cast(this)->length());
1605 break;
1606 case EXTERNAL_INT_ARRAY_TYPE:
1607 accumulator->Add("<ExternalIntArray[%u]>",
1608 ExternalIntArray::cast(this)->length());
1609 break;
1610 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1611 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1612 ExternalUnsignedIntArray::cast(this)->length());
1613 break;
1614 case EXTERNAL_FLOAT_ARRAY_TYPE:
1615 accumulator->Add("<ExternalFloatArray[%u]>",
1616 ExternalFloatArray::cast(this)->length());
1617 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001618 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1619 accumulator->Add("<ExternalDoubleArray[%u]>",
1620 ExternalDoubleArray::cast(this)->length());
1621 break;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001622 case SHARED_FUNCTION_INFO_TYPE: {
1623 SharedFunctionInfo* shared = SharedFunctionInfo::cast(this);
1624 SmartArrayPointer<char> debug_name =
1625 shared->DebugName()->ToCString();
1626 if (debug_name[0] != 0) {
1627 accumulator->Add("<SharedFunctionInfo %s>", *debug_name);
1628 } else {
1629 accumulator->Add("<SharedFunctionInfo>");
1630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 break;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00001632 }
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001633 case JS_MESSAGE_OBJECT_TYPE:
1634 accumulator->Add("<JSMessageObject>");
1635 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001636#define MAKE_STRUCT_CASE(NAME, Name, name) \
1637 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001638 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001640 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641 break;
1642 STRUCT_LIST(MAKE_STRUCT_CASE)
1643#undef MAKE_STRUCT_CASE
1644 case CODE_TYPE:
1645 accumulator->Add("<Code>");
1646 break;
1647 case ODDBALL_TYPE: {
1648 if (IsUndefined())
1649 accumulator->Add("<undefined>");
1650 else if (IsTheHole())
1651 accumulator->Add("<the hole>");
1652 else if (IsNull())
1653 accumulator->Add("<null>");
1654 else if (IsTrue())
1655 accumulator->Add("<true>");
1656 else if (IsFalse())
1657 accumulator->Add("<false>");
1658 else
1659 accumulator->Add("<Odd Oddball>");
1660 break;
1661 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001662 case SYMBOL_TYPE: {
1663 Symbol* symbol = Symbol::cast(this);
1664 accumulator->Add("<Symbol: %d", symbol->Hash());
1665 if (!symbol->name()->IsUndefined()) {
1666 accumulator->Add(" ");
1667 String::cast(symbol->name())->StringShortPrint(accumulator);
1668 }
1669 accumulator->Add(">");
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001670 break;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001671 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672 case HEAP_NUMBER_TYPE:
1673 accumulator->Add("<Number: ");
1674 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1675 accumulator->Put('>');
1676 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001677 case JS_PROXY_TYPE:
1678 accumulator->Add("<JSProxy>");
1679 break;
1680 case JS_FUNCTION_PROXY_TYPE:
1681 accumulator->Add("<JSFunctionProxy>");
1682 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001683 case FOREIGN_TYPE:
1684 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 break;
danno@chromium.org41728482013-06-12 22:31:22 +00001686 case CELL_TYPE:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001687 accumulator->Add("Cell for ");
danno@chromium.org41728482013-06-12 22:31:22 +00001688 Cell::cast(this)->value()->ShortPrint(accumulator);
1689 break;
1690 case PROPERTY_CELL_TYPE:
1691 accumulator->Add("PropertyCell for ");
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001692 PropertyCell::cast(this)->value()->ShortPrint(accumulator);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001693 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694 default:
1695 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1696 break;
1697 }
1698}
1699
1700
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701void HeapObject::Iterate(ObjectVisitor* v) {
1702 // Handle header
1703 IteratePointer(v, kMapOffset);
1704 // Handle object body
1705 Map* m = map();
1706 IterateBody(m->instance_type(), SizeFromMap(m), v);
1707}
1708
1709
1710void HeapObject::IterateBody(InstanceType type, int object_size,
1711 ObjectVisitor* v) {
1712 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1713 // During GC, the map pointer field is encoded.
1714 if (type < FIRST_NONSTRING_TYPE) {
1715 switch (type & kStringRepresentationMask) {
1716 case kSeqStringTag:
1717 break;
1718 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001719 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001720 break;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001721 case kSlicedStringTag:
1722 SlicedString::BodyDescriptor::IterateBody(this, v);
1723 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001724 case kExternalStringTag:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001725 if ((type & kStringEncodingMask) == kOneByteStringTag) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001726 reinterpret_cast<ExternalAsciiString*>(this)->
1727 ExternalAsciiStringIterateBody(v);
1728 } else {
1729 reinterpret_cast<ExternalTwoByteString*>(this)->
1730 ExternalTwoByteStringIterateBody(v);
1731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001732 break;
1733 }
1734 return;
1735 }
1736
1737 switch (type) {
1738 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001739 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740 break;
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00001741 case CONSTANT_POOL_ARRAY_TYPE:
1742 reinterpret_cast<ConstantPoolArray*>(this)->ConstantPoolIterateBody(v);
1743 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001744 case FIXED_DOUBLE_ARRAY_TYPE:
1745 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001746 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001747 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001748 case JS_GENERATOR_OBJECT_TYPE:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001749 case JS_MODULE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750 case JS_VALUE_TYPE:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001751 case JS_DATE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001752 case JS_ARRAY_TYPE:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001753 case JS_ARRAY_BUFFER_TYPE:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001754 case JS_TYPED_ARRAY_TYPE:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001755 case JS_DATA_VIEW_TYPE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001756 case JS_SET_TYPE:
1757 case JS_MAP_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001758 case JS_WEAK_MAP_TYPE:
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001759 case JS_WEAK_SET_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001760 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001761 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001762 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001764 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001765 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001767 case JS_FUNCTION_TYPE:
1768 reinterpret_cast<JSFunction*>(this)
1769 ->JSFunctionIterateBody(object_size, v);
1770 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001772 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001773 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001774 case JS_PROXY_TYPE:
1775 JSProxy::BodyDescriptor::IterateBody(this, v);
1776 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001777 case JS_FUNCTION_PROXY_TYPE:
1778 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1779 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001780 case FOREIGN_TYPE:
1781 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001782 break;
1783 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001784 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 break;
1786 case CODE_TYPE:
1787 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1788 break;
danno@chromium.org41728482013-06-12 22:31:22 +00001789 case CELL_TYPE:
1790 Cell::BodyDescriptor::IterateBody(this, v);
1791 break;
1792 case PROPERTY_CELL_TYPE:
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001793 PropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001794 break;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001795 case SYMBOL_TYPE:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001796 Symbol::BodyDescriptor::IterateBody(this, v);
1797 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001798 case HEAP_NUMBER_TYPE:
1799 case FILLER_TYPE:
1800 case BYTE_ARRAY_TYPE:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001801 case FREE_SPACE_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001802 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001803 case EXTERNAL_BYTE_ARRAY_TYPE:
1804 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1805 case EXTERNAL_SHORT_ARRAY_TYPE:
1806 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1807 case EXTERNAL_INT_ARRAY_TYPE:
1808 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1809 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001810 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001812 case SHARED_FUNCTION_INFO_TYPE: {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00001813 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001815 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001816
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817#define MAKE_STRUCT_CASE(NAME, Name, name) \
1818 case NAME##_TYPE:
1819 STRUCT_LIST(MAKE_STRUCT_CASE)
1820#undef MAKE_STRUCT_CASE
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001821 if (type == ALLOCATION_SITE_TYPE) {
1822 AllocationSite::BodyDescriptor::IterateBody(this, v);
1823 } else {
1824 StructBodyDescriptor::IterateBody(this, object_size, v);
1825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 break;
1827 default:
1828 PrintF("Unknown type: %d\n", type);
1829 UNREACHABLE();
1830 }
1831}
1832
1833
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001834bool HeapNumber::HeapNumberBooleanValue() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001836#if __BYTE_ORDER == __LITTLE_ENDIAN
1837 union IeeeDoubleLittleEndianArchType u;
1838#elif __BYTE_ORDER == __BIG_ENDIAN
1839 union IeeeDoubleBigEndianArchType u;
1840#endif
1841 u.d = value();
1842 if (u.bits.exp == 2047) {
1843 // Detect NaN for IEEE double precision floating point.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001844 if ((u.bits.man_low | u.bits.man_high) != 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001846 if (u.bits.exp == 0) {
1847 // Detect +0, and -0 for IEEE double precision floating point.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001848 if ((u.bits.man_low | u.bits.man_high) == 0) return false;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001849 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001850 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851}
1852
1853
whesse@chromium.org023421e2010-12-21 12:19:12 +00001854void HeapNumber::HeapNumberPrint(FILE* out) {
1855 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856}
1857
1858
1859void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1860 // The Windows version of vsnprintf can allocate when printing a %g string
1861 // into a buffer that may not be big enough. We don't want random memory
1862 // allocation when producing post-crash stack traces, so we print into a
1863 // buffer that is plenty big enough for any floating point number, then
1864 // print that using vsnprintf (which may truncate but never allocate if
1865 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001866 EmbeddedVector<char, 100> buffer;
1867 OS::SNPrintF(buffer, "%.16g", Number());
1868 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869}
1870
1871
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001872String* JSReceiver::class_name() {
1873 if (IsJSFunction() && IsJSFunctionProxy()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001874 return GetHeap()->function_class_string();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876 if (map()->constructor()->IsJSFunction()) {
1877 JSFunction* constructor = JSFunction::cast(map()->constructor());
1878 return String::cast(constructor->shared()->instance_class_name());
1879 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001880 // If the constructor is not present, return "Object".
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001881 return GetHeap()->Object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001882}
1883
1884
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001885String* Map::constructor_name() {
1886 if (constructor()->IsJSFunction()) {
1887 JSFunction* constructor = JSFunction::cast(this->constructor());
ager@chromium.orga1645e22009-09-09 19:27:10 +00001888 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001889 if (name->length() > 0) return name;
1890 String* inferred_name = constructor->shared()->inferred_name();
1891 if (inferred_name->length() > 0) return inferred_name;
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001892 Object* proto = prototype();
vegorov@chromium.org42841962010-10-18 11:18:59 +00001893 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001894 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001895 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001896 // If the constructor is not present, return "Object".
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001897 return GetHeap()->Object_string();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001898}
1899
1900
verwaest@chromium.org32cb9b22013-08-21 11:18:12 +00001901String* JSReceiver::constructor_name() {
1902 return map()->constructor_name();
1903}
1904
1905
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001906// TODO(mstarzinger): Temporary wrapper until handlified.
1907static Handle<Object> NewStorageFor(Isolate* isolate,
1908 Handle<Object> object,
1909 Representation representation) {
1910 Heap* heap = isolate->heap();
1911 CALL_HEAP_FUNCTION(isolate,
1912 object->AllocateNewStorageFor(heap, representation),
1913 Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001914}
1915
1916
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001917void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object,
1918 Handle<Map> new_map,
1919 Handle<Name> name,
1920 Handle<Object> value,
1921 int field_index,
1922 Representation representation) {
1923 Isolate* isolate = object->GetIsolate();
1924
1925 // This method is used to transition to a field. If we are transitioning to a
1926 // double field, allocate new storage.
1927 Handle<Object> storage = NewStorageFor(isolate, value, representation);
1928
1929 if (object->map()->unused_property_fields() == 0) {
1930 int new_unused = new_map->unused_property_fields();
1931 Handle<FixedArray> properties(object->properties());
1932 Handle<FixedArray> values = isolate->factory()->CopySizeFixedArray(
1933 properties, properties->length() + new_unused + 1);
1934 object->set_properties(*values);
1935 }
1936
1937 object->set_map(*new_map);
1938 object->FastPropertyAtPut(field_index, *storage);
1939}
1940
1941
1942static MaybeObject* CopyAddFieldDescriptor(Map* map,
1943 Name* name,
1944 int index,
1945 PropertyAttributes attributes,
1946 Representation representation,
1947 TransitionFlag flag) {
1948 Map* new_map;
1949 FieldDescriptor new_field_desc(name, index, attributes, representation);
1950 MaybeObject* maybe_map = map->CopyAddDescriptor(&new_field_desc, flag);
1951 if (!maybe_map->To(&new_map)) return maybe_map;
1952 int unused_property_fields = map->unused_property_fields() - 1;
1953 if (unused_property_fields < 0) {
1954 unused_property_fields += JSObject::kFieldsAdded;
1955 }
1956 new_map->set_unused_property_fields(unused_property_fields);
1957 return new_map;
1958}
1959
1960
1961static Handle<Map> CopyAddFieldDescriptor(Handle<Map> map,
1962 Handle<Name> name,
1963 int index,
1964 PropertyAttributes attributes,
1965 Representation representation,
1966 TransitionFlag flag) {
1967 CALL_HEAP_FUNCTION(map->GetIsolate(),
1968 CopyAddFieldDescriptor(
1969 *map, *name, index, attributes, representation, flag),
1970 Map);
1971}
1972
1973
1974void JSObject::AddFastProperty(Handle<JSObject> object,
1975 Handle<Name> name,
1976 Handle<Object> value,
1977 PropertyAttributes attributes,
1978 StoreFromKeyed store_mode,
1979 ValueType value_type,
1980 TransitionFlag flag) {
1981 ASSERT(!object->IsJSGlobalProxy());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00001982 ASSERT(DescriptorArray::kNotFound ==
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001983 object->map()->instance_descriptors()->Search(
1984 *name, object->map()->NumberOfOwnDescriptors()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001985
ulan@chromium.org750145a2013-03-07 15:14:13 +00001986 // Normalize the object if the name is an actual name (not the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001987 // hidden strings) and is not a real identifier.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001988 // Normalize the object if it will have too many fast properties.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001989 Isolate* isolate = object->GetIsolate();
1990 if (!name->IsCacheable(isolate) ||
1991 object->TooManyFastProperties(store_mode)) {
1992 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
1993 AddSlowProperty(object, name, value, attributes);
1994 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001995 }
1996
1997 // Compute the new index for new field.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001998 int index = object->map()->NextFreePropertyIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999
2000 // Allocate new instance descriptors with (name, index) added
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002001 if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED;
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002002 Representation representation = value->OptimalRepresentation(value_type);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002003 Handle<Map> new_map = CopyAddFieldDescriptor(
2004 handle(object->map()), name, index, attributes, representation, flag);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002005
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002006 AddFastPropertyUsingMap(object, new_map, name, value, index, representation);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002007}
2008
2009
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002010static MaybeObject* CopyAddConstantDescriptor(Map* map,
2011 Name* name,
2012 Object* value,
2013 PropertyAttributes attributes,
2014 TransitionFlag flag) {
2015 ConstantDescriptor new_constant_desc(name, value, attributes);
2016 return map->CopyAddDescriptor(&new_constant_desc, flag);
2017}
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002018
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002019
2020static Handle<Map> CopyAddConstantDescriptor(Handle<Map> map,
2021 Handle<Name> name,
2022 Handle<Object> value,
2023 PropertyAttributes attributes,
2024 TransitionFlag flag) {
2025 CALL_HEAP_FUNCTION(map->GetIsolate(),
2026 CopyAddConstantDescriptor(
2027 *map, *name, *value, attributes, flag),
2028 Map);
2029}
2030
2031
2032void JSObject::AddConstantProperty(Handle<JSObject> object,
2033 Handle<Name> name,
2034 Handle<Object> constant,
2035 PropertyAttributes attributes,
2036 TransitionFlag initial_flag) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002037 TransitionFlag flag =
rossberg@chromium.org92597162013-08-23 13:28:00 +00002038 // Do not add transitions to global objects.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002039 (object->IsGlobalObject() ||
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002040 // Don't add transitions to special properties with non-trivial
2041 // attributes.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002042 attributes != NONE)
2043 ? OMIT_TRANSITION
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002044 : initial_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002046 // Allocate new instance descriptors with (name, constant) added.
2047 Handle<Map> new_map = CopyAddConstantDescriptor(
2048 handle(object->map()), name, constant, attributes, flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002050 object->set_map(*new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002051}
2052
2053
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002054void JSObject::AddSlowProperty(Handle<JSObject> object,
2055 Handle<Name> name,
2056 Handle<Object> value,
2057 PropertyAttributes attributes) {
2058 ASSERT(!object->HasFastProperties());
2059 Isolate* isolate = object->GetIsolate();
2060 Handle<NameDictionary> dict(object->property_dictionary());
2061 if (object->IsGlobalObject()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002062 // In case name is an orphaned property reuse the cell.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002063 int entry = dict->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002064 if (entry != NameDictionary::kNotFound) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002065 Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(entry)));
2066 PropertyCell::SetValueInferType(cell, value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002067 // Assign an enumeration index to the property and update
2068 // SetNextEnumerationIndex.
2069 int index = dict->NextEnumerationIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002070 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002071 dict->SetNextEnumerationIndex(index + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002072 dict->SetEntry(entry, *name, *cell, details);
2073 return;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002074 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002075 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
2076 PropertyCell::SetValueInferType(cell, value);
2077 value = cell;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002079 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002080 Handle<NameDictionary> result = NameDictionaryAdd(dict, name, value, details);
2081 if (*dict != *result) object->set_properties(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002082}
2083
2084
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002085Handle<Object> JSObject::AddProperty(Handle<JSObject> object,
2086 Handle<Name> name,
2087 Handle<Object> value,
2088 PropertyAttributes attributes,
2089 StrictModeFlag strict_mode,
2090 JSReceiver::StoreFromKeyed store_mode,
2091 ExtensibilityCheck extensibility_check,
2092 ValueType value_type,
2093 StoreMode mode,
2094 TransitionFlag transition_flag) {
2095 ASSERT(!object->IsJSGlobalProxy());
2096 Isolate* isolate = object->GetIsolate();
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00002097
2098 if (!name->IsUniqueName()) {
2099 name = isolate->factory()->InternalizedStringFromString(
2100 Handle<String>::cast(name));
2101 }
2102
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00002103 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002104 !object->map()->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002105 if (strict_mode == kNonStrictMode) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002106 return value;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002107 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002108 Handle<Object> args[1] = { name };
2109 Handle<Object> error = isolate->factory()->NewTypeError(
2110 "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
2111 isolate->Throw(*error);
2112 return Handle<Object>();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002113 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002114 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002115
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002116 if (object->HasFastProperties()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002117 // Ensure the descriptor array does not get too big.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002118 if (object->map()->NumberOfOwnDescriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002119 DescriptorArray::kMaxNumberOfDescriptors) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002120 // TODO(verwaest): Support other constants.
2121 // if (mode == ALLOW_AS_CONSTANT &&
2122 // !value->IsTheHole() &&
2123 // !value->IsConsString()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00002124 if (value->IsJSFunction()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002125 AddConstantProperty(object, name, value, attributes, transition_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002126 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002127 AddFastProperty(object, name, value, attributes, store_mode,
2128 value_type, transition_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002129 }
2130 } else {
2131 // Normalize the object to prevent very large instance descriptors.
2132 // This eliminates unwanted N^2 allocation and lookup behavior.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002133 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
2134 AddSlowProperty(object, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002135 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002136 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002137 AddSlowProperty(object, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002138 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002139
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002140 if (FLAG_harmony_observation && object->map()->is_observed()) {
2141 Handle<Object> old_value = isolate->factory()->the_hole_value();
2142 EnqueueChangeRecord(object, "new", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002143 }
2144
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002145 return value;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002146}
2147
2148
2149void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
2150 const char* type_str,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002151 Handle<Name> name,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002152 Handle<Object> old_value) {
2153 Isolate* isolate = object->GetIsolate();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002154 HandleScope scope(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002155 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002156 if (object->IsJSGlobalObject()) {
2157 object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
2158 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002159 Handle<Object> args[] = { type, object, name, old_value };
2160 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002161 Execution::Call(isolate,
2162 Handle<JSFunction>(isolate->observers_notify_change()),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002163 isolate->factory()->undefined_value(),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002164 old_value->IsTheHole() ? 3 : 4, args,
2165 &threw);
2166 ASSERT(!threw);
2167}
2168
2169
2170void JSObject::DeliverChangeRecords(Isolate* isolate) {
2171 ASSERT(isolate->observer_delivery_pending());
2172 bool threw = false;
2173 Execution::Call(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002174 isolate,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00002175 isolate->observers_deliver_changes(),
2176 isolate->factory()->undefined_value(),
2177 0,
2178 NULL,
2179 &threw);
2180 ASSERT(!threw);
2181 isolate->set_observer_delivery_pending(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002182}
2183
2184
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002185Handle<Object> JSObject::SetPropertyPostInterceptor(
2186 Handle<JSObject> object,
2187 Handle<Name> name,
2188 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002189 PropertyAttributes attributes,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002190 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002191 // Check local property, ignore interceptor.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002192 LookupResult result(object->GetIsolate());
2193 object->LocalLookupRealNamedProperty(*name, &result);
2194 if (!result.IsFound()) {
2195 object->map()->LookupTransition(*object, *name, &result);
2196 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002197 if (result.IsFound()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002198 // An existing property or a map transition was found. Use set property to
2199 // handle all these cases.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002200 return SetPropertyForResult(object, &result, name, value, attributes,
2201 strict_mode, MAY_BE_STORE_FROM_KEYED);
ager@chromium.org5c838252010-02-19 08:53:10 +00002202 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002203 bool done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002204 Handle<Object> result_object = SetPropertyViaPrototypes(
2205 object, name, value, attributes, strict_mode, &done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002206 if (done) return result_object;
ager@chromium.org5c838252010-02-19 08:53:10 +00002207 // Add a new real property.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002208 return AddProperty(object, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002209}
2210
2211
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002212static void ReplaceSlowProperty(Handle<JSObject> object,
2213 Handle<Name> name,
2214 Handle<Object> value,
2215 PropertyAttributes attributes) {
2216 NameDictionary* dictionary = object->property_dictionary();
2217 int old_index = dictionary->FindEntry(*name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002218 int new_enumeration_index = 0; // 0 means "Use the next available index."
2219 if (old_index != -1) {
2220 // All calls to ReplaceSlowProperty have had all transitions removed.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002221 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002223
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002224 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002225 JSObject::SetNormalizedProperty(object, name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002226}
2227
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002228
danno@chromium.orgf005df62013-04-30 16:36:45 +00002229const char* Representation::Mnemonic() const {
2230 switch (kind_) {
2231 case kNone: return "v";
2232 case kTagged: return "t";
2233 case kSmi: return "s";
2234 case kDouble: return "d";
2235 case kInteger32: return "i";
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002236 case kHeapObject: return "h";
danno@chromium.orgf005df62013-04-30 16:36:45 +00002237 case kExternal: return "x";
2238 default:
2239 UNREACHABLE();
2240 return NULL;
2241 }
2242}
2243
2244
2245enum RightTrimMode { FROM_GC, FROM_MUTATOR };
2246
2247
2248static void ZapEndOfFixedArray(Address new_end, int to_trim) {
2249 // If we are doing a big trim in old space then we zap the space.
2250 Object** zap = reinterpret_cast<Object**>(new_end);
2251 zap++; // Header of filler must be at least one word so skip that.
2252 for (int i = 1; i < to_trim; i++) {
2253 *zap++ = Smi::FromInt(0);
2254 }
2255}
2256
2257
2258template<RightTrimMode trim_mode>
2259static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002260 ASSERT(elms->map() != heap->fixed_cow_array_map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002261 // For now this trick is only applied to fixed arrays in new and paged space.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00002262 ASSERT(!heap->lo_space()->Contains(elms));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002263
2264 const int len = elms->length();
2265
2266 ASSERT(to_trim < len);
2267
2268 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
2269
2270 if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002271 ZapEndOfFixedArray(new_end, to_trim);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002272 }
2273
2274 int size_delta = to_trim * kPointerSize;
2275
2276 // Technically in new space this write might be omitted (except for
2277 // debug mode which iterates through the heap), but to play safer
2278 // we still do it.
2279 heap->CreateFillerObjectAt(new_end, size_delta);
2280
2281 elms->set_length(len - to_trim);
2282
2283 // Maintain marking consistency for IncrementalMarking.
2284 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
2285 if (trim_mode == FROM_GC) {
2286 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
2287 } else {
2288 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
2289 }
2290 }
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00002291
2292 // The array may not be moved during GC,
2293 // and size has to be adjusted nevertheless.
2294 HeapProfiler* profiler = heap->isolate()->heap_profiler();
2295 if (profiler->is_tracking_allocations()) {
2296 profiler->UpdateObjectSizeEvent(elms->address(), elms->Size());
2297 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002298}
2299
2300
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002301bool Map::InstancesNeedRewriting(Map* target,
2302 int target_number_of_fields,
danno@chromium.orgf005df62013-04-30 16:36:45 +00002303 int target_inobject,
2304 int target_unused) {
2305 // If fields were added (or removed), rewrite the instance.
2306 int number_of_fields = NumberOfFields();
2307 ASSERT(target_number_of_fields >= number_of_fields);
2308 if (target_number_of_fields != number_of_fields) return true;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002309
2310 if (FLAG_track_double_fields) {
2311 // If smi descriptors were replaced by double descriptors, rewrite.
2312 DescriptorArray* old_desc = instance_descriptors();
2313 DescriptorArray* new_desc = target->instance_descriptors();
2314 int limit = NumberOfOwnDescriptors();
2315 for (int i = 0; i < limit; i++) {
2316 if (new_desc->GetDetails(i).representation().IsDouble() &&
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002317 !old_desc->GetDetails(i).representation().IsDouble()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002318 return true;
2319 }
2320 }
2321 }
2322
danno@chromium.orgf005df62013-04-30 16:36:45 +00002323 // If no fields were added, and no inobject properties were removed, setting
2324 // the map is sufficient.
2325 if (target_inobject == inobject_properties()) return false;
2326 // In-object slack tracking may have reduced the object size of the new map.
2327 // In that case, succeed if all existing fields were inobject, and they still
2328 // fit within the new inobject size.
2329 ASSERT(target_inobject < inobject_properties());
2330 if (target_number_of_fields <= target_inobject) {
2331 ASSERT(target_number_of_fields + target_unused == target_inobject);
2332 return false;
2333 }
2334 // Otherwise, properties will need to be moved to the backing store.
2335 return true;
2336}
2337
2338
2339// To migrate an instance to a map:
2340// - First check whether the instance needs to be rewritten. If not, simply
2341// change the map.
2342// - Otherwise, allocate a fixed array large enough to hold all fields, in
2343// addition to unused space.
2344// - Copy all existing properties in, in the following order: backing store
2345// properties, unused fields, inobject properties.
2346// - If all allocation succeeded, commit the state atomically:
2347// * Copy inobject properties from the backing store back into the object.
2348// * Trim the difference in instance size of the object. This also cleanly
2349// frees inobject properties that moved to the backing store.
2350// * If there are properties left in the backing store, trim of the space used
2351// to temporarily store the inobject properties.
2352// * If there are properties left in the backing store, install the backing
2353// store.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002354void JSObject::MigrateToMap(Handle<JSObject> object, Handle<Map> new_map) {
2355 Isolate* isolate = object->GetIsolate();
2356 Handle<Map> old_map(object->map());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002357 int number_of_fields = new_map->NumberOfFields();
2358 int inobject = new_map->inobject_properties();
2359 int unused = new_map->unused_property_fields();
2360
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002361 // Nothing to do if no functions were converted to fields and no smis were
2362 // converted to doubles.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002363 if (!old_map->InstancesNeedRewriting(
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002364 *new_map, number_of_fields, inobject, unused)) {
2365 object->set_map(*new_map);
2366 return;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002367 }
2368
2369 int total_size = number_of_fields + unused;
2370 int external = total_size - inobject;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002371 Handle<FixedArray> array = isolate->factory()->NewFixedArray(total_size);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002372
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002373 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
2374 Handle<DescriptorArray> new_descriptors(new_map->instance_descriptors());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002375 int descriptors = new_map->NumberOfOwnDescriptors();
2376
2377 for (int i = 0; i < descriptors; i++) {
2378 PropertyDetails details = new_descriptors->GetDetails(i);
2379 if (details.type() != FIELD) continue;
2380 PropertyDetails old_details = old_descriptors->GetDetails(i);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002381 if (old_details.type() == CALLBACKS) {
2382 ASSERT(details.representation().IsTagged());
2383 continue;
2384 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002385 ASSERT(old_details.type() == CONSTANT ||
danno@chromium.orgf005df62013-04-30 16:36:45 +00002386 old_details.type() == FIELD);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002387 Object* raw_value = old_details.type() == CONSTANT
danno@chromium.orgf005df62013-04-30 16:36:45 +00002388 ? old_descriptors->GetValue(i)
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002389 : object->RawFastPropertyAt(old_descriptors->GetFieldIndex(i));
2390 Handle<Object> value(raw_value, isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002391 if (FLAG_track_double_fields &&
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002392 !old_details.representation().IsDouble() &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002393 details.representation().IsDouble()) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002394 if (old_details.representation().IsNone()) {
2395 value = handle(Smi::FromInt(0), isolate);
2396 }
2397 value = NewStorageFor(isolate, value, details.representation());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002398 }
2399 ASSERT(!(FLAG_track_double_fields &&
2400 details.representation().IsDouble() &&
2401 value->IsSmi()));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002402 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2403 if (target_index < 0) target_index += total_size;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002404 array->set(target_index, *value);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002405 }
2406
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002407 // From here on we cannot fail and we shouldn't GC anymore.
2408 DisallowHeapAllocation no_allocation;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002409
2410 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2411 // avoid overwriting |one_pointer_filler_map|.
2412 int limit = Min(inobject, number_of_fields);
2413 for (int i = 0; i < limit; i++) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002414 object->FastPropertyAtPut(i, array->get(external + i));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002415 }
2416
2417 // Create filler object past the new instance size.
2418 int new_instance_size = new_map->instance_size();
2419 int instance_size_delta = old_map->instance_size() - new_instance_size;
2420 ASSERT(instance_size_delta >= 0);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002421 Address address = object->address() + new_instance_size;
2422 isolate->heap()->CreateFillerObjectAt(address, instance_size_delta);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002423
2424 // If there are properties in the new backing store, trim it to the correct
2425 // size and install the backing store into the object.
2426 if (external > 0) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002427 RightTrimFixedArray<FROM_MUTATOR>(isolate->heap(), *array, inobject);
2428 object->set_properties(*array);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002429 }
2430
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00002431 object->set_map(*new_map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002432}
2433
2434
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002435void JSObject::GeneralizeFieldRepresentation(Handle<JSObject> object,
2436 int modify_index,
2437 Representation new_representation,
2438 StoreMode store_mode) {
2439 Handle<Map> new_map = Map::GeneralizeRepresentation(
2440 handle(object->map()), modify_index, new_representation, store_mode);
2441 if (object->map() == *new_map) return;
2442 return MigrateToMap(object, new_map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002443}
2444
2445
2446int Map::NumberOfFields() {
2447 DescriptorArray* descriptors = instance_descriptors();
2448 int result = 0;
2449 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2450 if (descriptors->GetDetails(i).type() == FIELD) result++;
2451 }
2452 return result;
2453}
2454
2455
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002456Handle<Map> Map::CopyGeneralizeAllRepresentations(Handle<Map> map,
2457 int modify_index,
2458 StoreMode store_mode,
2459 PropertyAttributes attributes,
2460 const char* reason) {
2461 Handle<Map> new_map = Copy(map);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002462
rossberg@chromium.org92597162013-08-23 13:28:00 +00002463 DescriptorArray* descriptors = new_map->instance_descriptors();
2464 descriptors->InitializeRepresentations(Representation::Tagged());
2465
2466 // Unless the instance is being migrated, ensure that modify_index is a field.
2467 PropertyDetails details = descriptors->GetDetails(modify_index);
2468 if (store_mode == FORCE_FIELD && details.type() != FIELD) {
2469 FieldDescriptor d(descriptors->GetKey(modify_index),
2470 new_map->NumberOfFields(),
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002471 attributes,
rossberg@chromium.org92597162013-08-23 13:28:00 +00002472 Representation::Tagged());
2473 d.SetSortedKeyIndex(details.pointer());
2474 descriptors->Set(modify_index, &d);
2475 int unused_property_fields = new_map->unused_property_fields() - 1;
2476 if (unused_property_fields < 0) {
2477 unused_property_fields += JSObject::kFieldsAdded;
2478 }
2479 new_map->set_unused_property_fields(unused_property_fields);
2480 }
2481
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002482 if (FLAG_trace_generalization) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002483 map->PrintGeneralization(stdout, reason, modify_index,
rossberg@chromium.org92597162013-08-23 13:28:00 +00002484 new_map->NumberOfOwnDescriptors(),
2485 new_map->NumberOfOwnDescriptors(),
2486 details.type() == CONSTANT && store_mode == FORCE_FIELD,
2487 Representation::Tagged(), Representation::Tagged());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002488 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002489 return new_map;
2490}
2491
2492
2493void Map::DeprecateTransitionTree() {
2494 if (!FLAG_track_fields) return;
2495 if (is_deprecated()) return;
2496 if (HasTransitionArray()) {
2497 TransitionArray* transitions = this->transitions();
2498 for (int i = 0; i < transitions->number_of_transitions(); i++) {
2499 transitions->GetTarget(i)->DeprecateTransitionTree();
2500 }
2501 }
2502 deprecate();
2503 dependent_code()->DeoptimizeDependentCodeGroup(
2504 GetIsolate(), DependentCode::kTransitionGroup);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00002505 NotifyLeafMapLayoutChange();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002506}
2507
2508
2509// Invalidates a transition target at |key|, and installs |new_descriptors| over
2510// the current instance_descriptors to ensure proper sharing of descriptor
2511// arrays.
2512void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
2513 if (HasTransitionArray()) {
2514 TransitionArray* transitions = this->transitions();
2515 int transition = transitions->Search(key);
2516 if (transition != TransitionArray::kNotFound) {
2517 transitions->GetTarget(transition)->DeprecateTransitionTree();
2518 }
2519 }
2520
2521 // Don't overwrite the empty descriptor array.
2522 if (NumberOfOwnDescriptors() == 0) return;
2523
2524 DescriptorArray* to_replace = instance_descriptors();
2525 Map* current = this;
2526 while (current->instance_descriptors() == to_replace) {
2527 current->SetEnumLength(Map::kInvalidEnumCache);
2528 current->set_instance_descriptors(new_descriptors);
2529 Object* next = current->GetBackPointer();
2530 if (next->IsUndefined()) break;
2531 current = Map::cast(next);
2532 }
2533
2534 set_owns_descriptors(false);
2535}
2536
2537
2538Map* Map::FindRootMap() {
2539 Map* result = this;
2540 while (true) {
2541 Object* back = result->GetBackPointer();
2542 if (back->IsUndefined()) return result;
2543 result = Map::cast(back);
2544 }
2545}
2546
2547
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002548// Returns NULL if the updated map is incompatible.
danno@chromium.orgf005df62013-04-30 16:36:45 +00002549Map* Map::FindUpdatedMap(int verbatim,
2550 int length,
2551 DescriptorArray* descriptors) {
2552 // This can only be called on roots of transition trees.
2553 ASSERT(GetBackPointer()->IsUndefined());
2554
2555 Map* current = this;
2556
2557 for (int i = verbatim; i < length; i++) {
2558 if (!current->HasTransitionArray()) break;
2559 Name* name = descriptors->GetKey(i);
2560 TransitionArray* transitions = current->transitions();
2561 int transition = transitions->Search(name);
2562 if (transition == TransitionArray::kNotFound) break;
2563 current = transitions->GetTarget(transition);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002564 PropertyDetails details = descriptors->GetDetails(i);
2565 PropertyDetails target_details =
2566 current->instance_descriptors()->GetDetails(i);
2567 if (details.attributes() != target_details.attributes()) return NULL;
2568 if (details.type() == CALLBACKS) {
2569 if (target_details.type() != CALLBACKS) return NULL;
2570 if (descriptors->GetValue(i) !=
2571 current->instance_descriptors()->GetValue(i)) {
2572 return NULL;
2573 }
2574 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002575 }
2576
2577 return current;
2578}
2579
2580
2581Map* Map::FindLastMatchMap(int verbatim,
2582 int length,
2583 DescriptorArray* descriptors) {
2584 // This can only be called on roots of transition trees.
2585 ASSERT(GetBackPointer()->IsUndefined());
2586
2587 Map* current = this;
2588
2589 for (int i = verbatim; i < length; i++) {
2590 if (!current->HasTransitionArray()) break;
2591 Name* name = descriptors->GetKey(i);
2592 TransitionArray* transitions = current->transitions();
2593 int transition = transitions->Search(name);
2594 if (transition == TransitionArray::kNotFound) break;
2595
2596 Map* next = transitions->GetTarget(transition);
2597 DescriptorArray* next_descriptors = next->instance_descriptors();
2598
2599 if (next_descriptors->GetValue(i) != descriptors->GetValue(i)) break;
2600
2601 PropertyDetails details = descriptors->GetDetails(i);
2602 PropertyDetails next_details = next_descriptors->GetDetails(i);
2603 if (details.type() != next_details.type()) break;
2604 if (details.attributes() != next_details.attributes()) break;
2605 if (!details.representation().Equals(next_details.representation())) break;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002606
2607 current = next;
2608 }
2609 return current;
2610}
2611
2612
2613// Generalize the representation of the descriptor at |modify_index|.
2614// This method rewrites the transition tree to reflect the new change. To avoid
2615// high degrees over polymorphism, and to stabilize quickly, on every rewrite
2616// the new type is deduced by merging the current type with any potential new
2617// (partial) version of the type in the transition tree.
2618// To do this, on each rewrite:
2619// - Search the root of the transition tree using FindRootMap.
2620// - Find |updated|, the newest matching version of this map using
2621// FindUpdatedMap. This uses the keys in the own map's descriptor array to
2622// walk the transition tree.
2623// - Merge/generalize the descriptor array of the current map and |updated|.
2624// - Generalize the |modify_index| descriptor using |new_representation|.
2625// - Walk the tree again starting from the root towards |updated|. Stop at
2626// |split_map|, the first map who's descriptor array does not match the merged
2627// descriptor array.
2628// - If |updated| == |split_map|, |updated| is in the expected state. Return it.
2629// - Otherwise, invalidate the outdated transition target from |updated|, and
2630// replace its transition tree with a new branch for the updated descriptors.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002631Handle<Map> Map::GeneralizeRepresentation(Handle<Map> old_map,
2632 int modify_index,
2633 Representation new_representation,
2634 StoreMode store_mode) {
2635 Handle<DescriptorArray> old_descriptors(old_map->instance_descriptors());
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002636 PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
2637 Representation old_representation = old_details.representation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00002638
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002639 // It's fine to transition from None to anything but double without any
2640 // modification to the object, because the default uninitialized value for
2641 // representation None can be overwritten by both smi and tagged values.
2642 // Doubles, however, would require a box allocation.
2643 if (old_representation.IsNone() &&
2644 !new_representation.IsNone() &&
2645 !new_representation.IsDouble()) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00002646 old_descriptors->SetRepresentation(modify_index, new_representation);
danno@chromium.org1fd77d52013-06-07 16:01:45 +00002647 return old_map;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002648 }
2649
2650 int descriptors = old_map->NumberOfOwnDescriptors();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002651 Handle<Map> root_map(old_map->FindRootMap());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002652
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002653 // Check the state of the root map.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002654 if (!old_map->EquivalentToForTransition(*root_map)) {
2655 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2656 old_details.attributes(), "not equivalent");
danno@chromium.orgf005df62013-04-30 16:36:45 +00002657 }
2658
2659 int verbatim = root_map->NumberOfOwnDescriptors();
2660
rossberg@chromium.org92597162013-08-23 13:28:00 +00002661 if (store_mode != ALLOW_AS_CONSTANT && modify_index < verbatim) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002662 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00002663 old_details.attributes(), "root modification");
rossberg@chromium.org92597162013-08-23 13:28:00 +00002664 }
2665
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002666 Map* raw_updated = root_map->FindUpdatedMap(
2667 verbatim, descriptors, *old_descriptors);
2668 if (raw_updated == NULL) {
2669 return CopyGeneralizeAllRepresentations(old_map, modify_index, store_mode,
2670 old_details.attributes(), "incompatible");
rossberg@chromium.org92597162013-08-23 13:28:00 +00002671 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002672
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002673 Handle<Map> updated(raw_updated);
2674 Handle<DescriptorArray> updated_descriptors(updated->instance_descriptors());
danno@chromium.orgf005df62013-04-30 16:36:45 +00002675
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002676 int valid = updated->NumberOfOwnDescriptors();
rossberg@chromium.org92597162013-08-23 13:28:00 +00002677
2678 // Directly change the map if the target map is more general. Ensure that the
2679 // target type of the modify_index is a FIELD, unless we are migrating.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002680 if (updated_descriptors->IsMoreGeneralThan(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002681 verbatim, valid, descriptors, *old_descriptors) &&
rossberg@chromium.org92597162013-08-23 13:28:00 +00002682 (store_mode == ALLOW_AS_CONSTANT ||
2683 updated_descriptors->GetDetails(modify_index).type() == FIELD)) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002684 Representation updated_representation =
2685 updated_descriptors->GetDetails(modify_index).representation();
rossberg@chromium.org92597162013-08-23 13:28:00 +00002686 if (new_representation.fits_into(updated_representation)) return updated;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002687 }
2688
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002689 Handle<DescriptorArray> new_descriptors = DescriptorArray::Merge(
2690 updated_descriptors, verbatim, valid, descriptors, modify_index,
2691 store_mode, old_descriptors);
rossberg@chromium.org92597162013-08-23 13:28:00 +00002692 ASSERT(store_mode == ALLOW_AS_CONSTANT ||
2693 new_descriptors->GetDetails(modify_index).type() == FIELD);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002694
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002695 old_representation =
danno@chromium.orgf005df62013-04-30 16:36:45 +00002696 new_descriptors->GetDetails(modify_index).representation();
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00002697 Representation updated_representation =
2698 new_representation.generalize(old_representation);
2699 if (!updated_representation.Equals(old_representation)) {
2700 new_descriptors->SetRepresentation(modify_index, updated_representation);
2701 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002702
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002703 Handle<Map> split_map(root_map->FindLastMatchMap(
2704 verbatim, descriptors, *new_descriptors));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002705
2706 int split_descriptors = split_map->NumberOfOwnDescriptors();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002707 // This is shadowed by |updated_descriptors| being more general than
2708 // |old_descriptors|.
2709 ASSERT(descriptors != split_descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002710
2711 int descriptor = split_descriptors;
2712 split_map->DeprecateTarget(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002713 old_descriptors->GetKey(descriptor), *new_descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002714
rossberg@chromium.org92597162013-08-23 13:28:00 +00002715 if (FLAG_trace_generalization) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002716 old_map->PrintGeneralization(
rossberg@chromium.org92597162013-08-23 13:28:00 +00002717 stdout, "", modify_index, descriptor, descriptors,
2718 old_descriptors->GetDetails(modify_index).type() == CONSTANT &&
2719 store_mode == FORCE_FIELD,
2720 old_representation, updated_representation);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002721 }
2722
danno@chromium.orgf005df62013-04-30 16:36:45 +00002723 // Add missing transitions.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002724 Handle<Map> new_map = split_map;
danno@chromium.orgf005df62013-04-30 16:36:45 +00002725 for (; descriptor < descriptors; descriptor++) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002726 new_map = Map::CopyInstallDescriptors(new_map, descriptor, new_descriptors);
danno@chromium.org59400602013-08-13 17:09:37 +00002727 new_map->set_migration_target(true);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002728 }
2729
2730 new_map->set_owns_descriptors(true);
2731 return new_map;
2732}
2733
ager@chromium.org7c537e22008-10-16 08:43:32 +00002734
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002735Map* Map::CurrentMapForDeprecated() {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002736 DisallowHeapAllocation no_allocation;
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002737 if (!is_deprecated()) return this;
2738
2739 DescriptorArray* old_descriptors = instance_descriptors();
2740
2741 int descriptors = NumberOfOwnDescriptors();
2742 Map* root_map = FindRootMap();
2743
2744 // Check the state of the root map.
2745 if (!EquivalentToForTransition(root_map)) return NULL;
2746 int verbatim = root_map->NumberOfOwnDescriptors();
2747
2748 Map* updated = root_map->FindUpdatedMap(
2749 verbatim, descriptors, old_descriptors);
2750 if (updated == NULL) return NULL;
2751
2752 DescriptorArray* updated_descriptors = updated->instance_descriptors();
2753 int valid = updated->NumberOfOwnDescriptors();
2754 if (!updated_descriptors->IsMoreGeneralThan(
2755 verbatim, valid, descriptors, old_descriptors)) {
2756 return NULL;
2757 }
2758
2759 return updated;
2760}
2761
2762
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002763Handle<Object> JSObject::SetPropertyWithInterceptor(
2764 Handle<JSObject> object,
2765 Handle<Name> name,
2766 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002767 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002768 StrictModeFlag strict_mode) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002769 // TODO(rossberg): Support symbols in the API.
2770 if (name->IsSymbol()) return value;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002771 Isolate* isolate = object->GetIsolate();
2772 Handle<String> name_string = Handle<String>::cast(name);
2773 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002774 if (!interceptor->setter()->IsUndefined()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002775 LOG(isolate,
2776 ApiNamedPropertyAccess("interceptor-named-set", *object, *name));
2777 PropertyCallbackArguments args(
2778 isolate, interceptor->data(), *object, *object);
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002779 v8::NamedPropertySetterCallback setter =
2780 v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002781 Handle<Object> value_unhole = value->IsTheHole()
2782 ? Handle<Object>(isolate->factory()->undefined_value()) : value;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002783 v8::Handle<v8::Value> result = args.Call(setter,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002784 v8::Utils::ToLocal(name_string),
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002785 v8::Utils::ToLocal(value_unhole));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002786 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2787 if (!result.IsEmpty()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002788 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002789 Handle<Object> result =
2790 SetPropertyPostInterceptor(object, name, value, attributes, strict_mode);
2791 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2792 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002793}
2794
2795
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002796Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002797 Handle<Name> name,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002798 Handle<Object> value,
2799 PropertyAttributes attributes,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002800 StrictModeFlag strict_mode,
2801 StoreFromKeyed store_mode) {
2802 LookupResult result(object->GetIsolate());
2803 object->LocalLookup(*name, &result, true);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002804 if (!result.IsFound()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002805 object->map()->LookupTransition(JSObject::cast(*object), *name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002806 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002807 return SetProperty(object, &result, name, value, attributes, strict_mode,
2808 store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809}
2810
2811
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002812Handle<Object> JSObject::SetPropertyWithCallback(Handle<JSObject> object,
2813 Handle<Object> structure,
2814 Handle<Name> name,
2815 Handle<Object> value,
2816 Handle<JSObject> holder,
2817 StrictModeFlag strict_mode) {
2818 Isolate* isolate = object->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002819
2820 // We should never get here to initialize a const with the hole
2821 // value since a const declaration would conflict with the setter.
2822 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002823
2824 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002825 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002826 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002827 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002829 reinterpret_cast<AccessorDescriptor*>(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002830 Handle<Foreign>::cast(structure)->foreign_address());
2831 CALL_AND_RETRY_OR_DIE(isolate,
2832 (callback->setter)(
2833 isolate, *object, *value, callback->data),
2834 break,
2835 return Handle<Object>());
2836 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2837 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838 }
2839
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002840 if (structure->IsExecutableAccessorInfo()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002841 // api style callbacks
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002842 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
2843 if (!data->IsCompatibleReceiver(*object)) {
2844 Handle<Object> args[2] = { name, object };
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002845 Handle<Object> error =
2846 isolate->factory()->NewTypeError("incompatible_method_receiver",
2847 HandleVector(args,
2848 ARRAY_SIZE(args)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002849 isolate->Throw(*error);
2850 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002851 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00002852 // TODO(rossberg): Support symbols in the API.
2853 if (name->IsSymbol()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002854 Object* call_obj = data->setter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +00002855 v8::AccessorSetterCallback call_fun =
2856 v8::ToCData<v8::AccessorSetterCallback>(call_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002857 if (call_fun == NULL) return value;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002858 Handle<String> key = Handle<String>::cast(name);
2859 LOG(isolate, ApiNamedPropertyAccess("store", *object, *name));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002860 PropertyCallbackArguments args(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002861 isolate, data->data(), *object, JSObject::cast(*holder));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002862 args.Call(call_fun,
2863 v8::Utils::ToLocal(key),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002864 v8::Utils::ToLocal(value));
2865 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
2866 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002867 }
2868
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002869 if (structure->IsAccessorPair()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002870 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002871 if (setter->IsSpecFunction()) {
2872 // TODO(rossberg): nicer would be to cast to some JSCallable here...
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002873 return SetPropertyWithDefinedSetter(
2874 object, Handle<JSReceiver>::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002875 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002876 if (strict_mode == kNonStrictMode) {
2877 return value;
2878 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002879 Handle<Object> args[2] = { name, holder };
2880 Handle<Object> error =
2881 isolate->factory()->NewTypeError("no_setter_in_callback",
2882 HandleVector(args, 2));
2883 isolate->Throw(*error);
2884 return Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002885 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002886 }
2887
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002888 // TODO(dcarney): Handle correctly.
2889 if (structure->IsDeclaredAccessorInfo()) {
2890 return value;
2891 }
2892
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002893 UNREACHABLE();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002894 return Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895}
2896
2897
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002898Handle<Object> JSReceiver::SetPropertyWithDefinedSetter(
2899 Handle<JSReceiver> object,
2900 Handle<JSReceiver> setter,
2901 Handle<Object> value) {
2902 Isolate* isolate = object->GetIsolate();
2903
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002904#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002905 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002906 // Handle stepping into a setter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002907 // TODO(rossberg): should this apply to getters that are function proxies?
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002908 if (debug->StepInActive() && setter->IsJSFunction()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002909 debug->HandleStepIn(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002910 Handle<JSFunction>::cast(setter), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002911 }
2912#endif
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002913
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002914 bool has_pending_exception;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002915 Handle<Object> argv[] = { value };
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00002916 Execution::Call(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002917 isolate, setter, object, ARRAY_SIZE(argv), argv, &has_pending_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002918 // Check for pending exception and return the result.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002919 if (has_pending_exception) return Handle<Object>();
2920 return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002921}
2922
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002923
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002924MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2925 uint32_t index,
2926 Object* value,
2927 bool* found,
2928 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002930 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002931 pt != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002932 pt = pt->GetPrototype(GetIsolate())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002933 if (pt->IsJSProxy()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002934 Isolate* isolate = GetIsolate();
2935 HandleScope scope(isolate);
2936 Handle<JSProxy> proxy(JSProxy::cast(pt));
2937 Handle<JSObject> self(this, isolate);
2938 Handle<String> name = isolate->factory()->Uint32ToString(index);
2939 Handle<Object> value_handle(value, isolate);
2940 Handle<Object> result = JSProxy::SetPropertyViaPrototypesWithHandler(
2941 proxy, self, name, value_handle, NONE, strict_mode, found);
2942 RETURN_IF_EMPTY_HANDLE(isolate, result);
2943 return *result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002944 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002945 if (!JSObject::cast(pt)->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002946 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002947 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002948 SeededNumberDictionary* dictionary =
2949 JSObject::cast(pt)->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002950 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002951 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002952 PropertyDetails details = dictionary->DetailsAt(entry);
2953 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002954 *found = true;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002955 Isolate* isolate = GetIsolate();
2956 HandleScope scope(isolate);
2957 Handle<JSObject> self(this, isolate);
2958 Handle<Object> structure(dictionary->ValueAt(entry), isolate);
2959 Handle<Object> value_handle(value, isolate);
2960 Handle<JSObject> holder(JSObject::cast(pt));
2961 Handle<Object> result = SetElementWithCallback(
2962 self, structure, index, value_handle, holder, strict_mode);
2963 RETURN_IF_EMPTY_HANDLE(isolate, result);
2964 return *result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002965 }
2966 }
2967 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002968 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002969 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002970}
2971
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002972
2973Handle<Object> JSObject::SetPropertyViaPrototypes(Handle<JSObject> object,
2974 Handle<Name> name,
2975 Handle<Object> value,
2976 PropertyAttributes attributes,
2977 StrictModeFlag strict_mode,
2978 bool* done) {
2979 Isolate* isolate = object->GetIsolate();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002980
2981 *done = false;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002982 // We could not find a local property so let's check whether there is an
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002983 // accessor that wants to handle the property, or whether the property is
2984 // read-only on the prototype chain.
2985 LookupResult result(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002986 object->LookupRealNamedPropertyInPrototypes(*name, &result);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002987 if (result.IsFound()) {
2988 switch (result.type()) {
2989 case NORMAL:
2990 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00002991 case CONSTANT:
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002992 *done = result.IsReadOnly();
2993 break;
2994 case INTERCEPTOR: {
2995 PropertyAttributes attr =
2996 result.holder()->GetPropertyAttributeWithInterceptor(
machenbach@chromium.org528ce022013-09-23 14:09:36 +00002997 *object, *name, true);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002998 *done = !!(attr & READ_ONLY);
2999 break;
3000 }
3001 case CALLBACKS: {
3002 if (!FLAG_es5_readonly && result.IsReadOnly()) break;
3003 *done = true;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003004 Handle<Object> callback_object(result.GetCallbackObject(), isolate);
3005 return SetPropertyWithCallback(object, callback_object, name, value,
3006 handle(result.holder()), strict_mode);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003007 }
3008 case HANDLER: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003009 Handle<JSProxy> proxy(result.proxy());
3010 return JSProxy::SetPropertyViaPrototypesWithHandler(
3011 proxy, object, name, value, attributes, strict_mode, done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003012 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003013 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003014 case NONEXISTENT:
3015 UNREACHABLE();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003016 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003017 }
3018 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003019
3020 // If we get here with *done true, we have encountered a read-only property.
3021 if (!FLAG_es5_readonly) *done = false;
3022 if (*done) {
3023 if (strict_mode == kNonStrictMode) return value;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003024 Handle<Object> args[] = { name, object };
3025 Handle<Object> error = isolate->factory()->NewTypeError(
3026 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
3027 isolate->Throw(*error);
3028 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003029 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003030 return isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003031}
3032
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003033
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003034void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
3035 Handle<DescriptorArray> descriptors(map->instance_descriptors());
3036 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
3037 int number_of_descriptors = descriptors->number_of_descriptors();
3038 Isolate* isolate = map->GetIsolate();
3039 Handle<DescriptorArray> new_descriptors =
3040 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack);
3041 DescriptorArray::WhitenessWitness witness(*new_descriptors);
3042
3043 for (int i = 0; i < number_of_descriptors; ++i) {
3044 new_descriptors->CopyFrom(i, *descriptors, i, witness);
3045 }
3046
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003047 map->set_instance_descriptors(*new_descriptors);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003048}
3049
3050
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003051template<class T>
3052static int AppendUniqueCallbacks(NeanderArray* callbacks,
3053 Handle<typename T::Array> array,
3054 int valid_descriptors) {
3055 int nof_callbacks = callbacks->length();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003056
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003057 Isolate* isolate = array->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00003058 // Ensure the keys are unique names before writing them into the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003059 // instance descriptor. Since it may cause a GC, it has to be done before we
danno@chromium.org129d3982012-07-25 15:01:47 +00003060 // temporarily put the heap in an invalid state while appending descriptors.
3061 for (int i = 0; i < nof_callbacks; ++i) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003062 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks->get(i)));
3063 if (entry->name()->IsUniqueName()) continue;
3064 Handle<String> key =
3065 isolate->factory()->InternalizedStringFromString(
3066 Handle<String>(String::cast(entry->name())));
3067 entry->set_name(*key);
danno@chromium.org129d3982012-07-25 15:01:47 +00003068 }
3069
danno@chromium.org129d3982012-07-25 15:01:47 +00003070 // Fill in new callback descriptors. Process the callbacks from
3071 // back to front so that the last callback with a given name takes
3072 // precedence over previously added callbacks with that name.
3073 for (int i = nof_callbacks - 1; i >= 0; i--) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003074 AccessorInfo* entry = AccessorInfo::cast(callbacks->get(i));
ulan@chromium.org750145a2013-03-07 15:14:13 +00003075 Name* key = Name::cast(entry->name());
danno@chromium.org129d3982012-07-25 15:01:47 +00003076 // Check if a descriptor with this name already exists before writing.
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003077 if (!T::Contains(key, entry, valid_descriptors, array)) {
3078 T::Insert(key, entry, valid_descriptors, array);
3079 valid_descriptors++;
danno@chromium.org129d3982012-07-25 15:01:47 +00003080 }
3081 }
3082
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003083 return valid_descriptors;
3084}
3085
3086struct DescriptorArrayAppender {
3087 typedef DescriptorArray Array;
3088 static bool Contains(Name* key,
3089 AccessorInfo* entry,
3090 int valid_descriptors,
3091 Handle<DescriptorArray> array) {
3092 return array->Search(key, valid_descriptors) != DescriptorArray::kNotFound;
3093 }
3094 static void Insert(Name* key,
3095 AccessorInfo* entry,
3096 int valid_descriptors,
3097 Handle<DescriptorArray> array) {
3098 CallbacksDescriptor desc(key, entry, entry->property_attributes());
3099 array->Append(&desc);
3100 }
3101};
3102
3103
3104struct FixedArrayAppender {
3105 typedef FixedArray Array;
3106 static bool Contains(Name* key,
3107 AccessorInfo* entry,
3108 int valid_descriptors,
3109 Handle<FixedArray> array) {
3110 for (int i = 0; i < valid_descriptors; i++) {
3111 if (key == AccessorInfo::cast(array->get(i))->name()) return true;
3112 }
3113 return false;
3114 }
3115 static void Insert(Name* key,
3116 AccessorInfo* entry,
3117 int valid_descriptors,
3118 Handle<FixedArray> array) {
3119 array->set(valid_descriptors, entry);
3120 }
3121};
3122
3123
3124void Map::AppendCallbackDescriptors(Handle<Map> map,
3125 Handle<Object> descriptors) {
3126 int nof = map->NumberOfOwnDescriptors();
3127 Handle<DescriptorArray> array(map->instance_descriptors());
3128 NeanderArray callbacks(descriptors);
3129 ASSERT(array->NumberOfSlackDescriptors() >= callbacks.length());
3130 nof = AppendUniqueCallbacks<DescriptorArrayAppender>(&callbacks, array, nof);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00003131 map->SetNumberOfOwnDescriptors(nof);
danno@chromium.org129d3982012-07-25 15:01:47 +00003132}
3133
3134
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003135int AccessorInfo::AppendUnique(Handle<Object> descriptors,
3136 Handle<FixedArray> array,
3137 int valid_descriptors) {
3138 NeanderArray callbacks(descriptors);
3139 ASSERT(array->length() >= callbacks.length() + valid_descriptors);
3140 return AppendUniqueCallbacks<FixedArrayAppender>(&callbacks,
3141 array,
3142 valid_descriptors);
3143}
3144
3145
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003146static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
3147 ASSERT(!map.is_null());
3148 for (int i = 0; i < maps->length(); ++i) {
3149 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
3150 }
3151 return false;
3152}
3153
3154
3155template <class T>
3156static Handle<T> MaybeNull(T* p) {
3157 if (p == NULL) return Handle<T>::null();
3158 return Handle<T>(p);
3159}
3160
3161
3162Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003163 ElementsKind kind = elements_kind();
3164 Handle<Map> transitioned_map = Handle<Map>::null();
3165 Handle<Map> current_map(this);
3166 bool packed = IsFastPackedElementsKind(kind);
3167 if (IsTransitionableFastElementsKind(kind)) {
3168 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
3169 kind = GetNextMoreGeneralFastElementsKind(kind, false);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003170 Handle<Map> maybe_transitioned_map =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003171 MaybeNull(current_map->LookupElementsTransitionMap(kind));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003172 if (maybe_transitioned_map.is_null()) break;
3173 if (ContainsMap(candidates, maybe_transitioned_map) &&
3174 (packed || !IsFastPackedElementsKind(kind))) {
3175 transitioned_map = maybe_transitioned_map;
3176 if (!IsFastPackedElementsKind(kind)) packed = false;
3177 }
3178 current_map = maybe_transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003179 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003180 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003181 return transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003182}
3183
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003184
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003185static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
3186 Map* current_map = map;
3187 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
verwaest@chromium.org50915592012-06-18 12:15:44 +00003188 int to_index = IsFastElementsKind(to_kind)
3189 ? GetSequenceIndexFromFastElementsKind(to_kind)
3190 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
3191
3192 ASSERT(index <= to_index);
3193
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003194 for (; index < to_index; ++index) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003195 if (!current_map->HasElementsTransition()) return current_map;
3196 current_map = current_map->elements_transition_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003197 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003198 if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003199 Map* next_map = current_map->elements_transition_map();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003200 if (next_map->elements_kind() == to_kind) return next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00003201 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003202 ASSERT(IsFastElementsKind(to_kind)
3203 ? current_map->elements_kind() == to_kind
3204 : current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003205 return current_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003206}
3207
3208
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003209Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003210 Map* to_map = FindClosestElementsTransition(this, to_kind);
3211 if (to_map->elements_kind() == to_kind) return to_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003212 return NULL;
3213}
3214
3215
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00003216bool Map::IsMapInArrayPrototypeChain() {
3217 Isolate* isolate = GetIsolate();
3218 if (isolate->initial_array_prototype()->map() == this) {
3219 return true;
3220 }
3221
3222 if (isolate->initial_object_prototype()->map() == this) {
3223 return true;
3224 }
3225
3226 return false;
3227}
3228
3229
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003230static MaybeObject* AddMissingElementsTransitions(Map* map,
3231 ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003232 ASSERT(IsFastElementsKind(map->elements_kind()));
3233 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
3234 int to_index = IsFastElementsKind(to_kind)
3235 ? GetSequenceIndexFromFastElementsKind(to_kind)
3236 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
3237
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003238 ASSERT(index <= to_index);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003239
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003240 Map* current_map = map;
3241
verwaest@chromium.org50915592012-06-18 12:15:44 +00003242 for (; index < to_index; ++index) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003243 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
3244 MaybeObject* maybe_next_map =
3245 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
3246 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003247 }
3248
verwaest@chromium.org50915592012-06-18 12:15:44 +00003249 // In case we are exiting the fast elements kind system, just add the map in
3250 // the end.
3251 if (!IsFastElementsKind(to_kind)) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003252 MaybeObject* maybe_next_map =
3253 current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
3254 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00003255 }
3256
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003257 ASSERT(current_map->elements_kind() == to_kind);
3258 return current_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003259}
3260
3261
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003262Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3263 ElementsKind to_kind) {
3264 Isolate* isolate = object->GetIsolate();
3265 CALL_HEAP_FUNCTION(isolate,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003266 object->GetElementsTransitionMap(isolate, to_kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003267 Map);
3268}
3269
3270
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003271MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003272 Map* start_map = map();
3273 ElementsKind from_kind = start_map->elements_kind();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003274
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003275 if (from_kind == to_kind) {
3276 return start_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003277 }
3278
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003279 bool allow_store_transition =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003280 // Only remember the map transition if there is not an already existing
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003281 // non-matching element transition.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003282 !start_map->IsUndefined() && !start_map->is_shared() &&
verwaest@chromium.org50915592012-06-18 12:15:44 +00003283 IsFastElementsKind(from_kind);
3284
3285 // Only store fast element maps in ascending generality.
3286 if (IsFastElementsKind(to_kind)) {
3287 allow_store_transition &=
3288 IsTransitionableFastElementsKind(from_kind) &&
3289 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
3290 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003291
3292 if (!allow_store_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003293 return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003294 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003295
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003296 return start_map->AsElementsKind(to_kind);
3297}
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003298
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003299
3300MaybeObject* Map::AsElementsKind(ElementsKind kind) {
3301 Map* closest_map = FindClosestElementsTransition(this, kind);
3302
3303 if (closest_map->elements_kind() == kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003304 return closest_map;
3305 }
3306
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003307 return AddMissingElementsTransitions(closest_map, kind);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003308}
3309
3310
ulan@chromium.org750145a2013-03-07 15:14:13 +00003311void JSObject::LocalLookupRealNamedProperty(Name* name, LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003312 if (IsJSGlobalProxy()) {
3313 Object* proto = GetPrototype();
3314 if (proto->IsNull()) return result->NotFound();
3315 ASSERT(proto->IsJSGlobalObject());
3316 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
3317 }
3318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003319 if (HasFastProperties()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003320 map()->LookupDescriptor(this, name, result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003321 // A property or a map transition was found. We return all of these result
3322 // types because LocalLookupRealNamedProperty is used when setting
3323 // properties where map transitions are handled.
3324 ASSERT(!result->IsFound() ||
3325 (result->holder() == this && result->IsFastPropertyType()));
3326 // Disallow caching for uninitialized constants. These can only
3327 // occur as fields.
3328 if (result->IsField() &&
3329 result->IsReadOnly() &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003330 RawFastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003331 result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003332 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003333 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003334 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003335
3336 int entry = property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003337 if (entry != NameDictionary::kNotFound) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003338 Object* value = property_dictionary()->ValueAt(entry);
3339 if (IsGlobalObject()) {
3340 PropertyDetails d = property_dictionary()->DetailsAt(entry);
3341 if (d.IsDeleted()) {
3342 result->NotFound();
3343 return;
3344 }
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00003345 value = PropertyCell::cast(value)->value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003346 }
3347 // Make sure to disallow caching for uninitialized constants
3348 // found in the dictionary-mode objects.
3349 if (value->IsTheHole()) result->DisallowCaching();
3350 result->DictionaryResult(this, entry);
3351 return;
3352 }
3353
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354 result->NotFound();
3355}
3356
3357
ulan@chromium.org750145a2013-03-07 15:14:13 +00003358void JSObject::LookupRealNamedProperty(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003359 LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003360 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003361
3362 LookupRealNamedPropertyInPrototypes(name, result);
3363}
3364
3365
ulan@chromium.org750145a2013-03-07 15:14:13 +00003366void JSObject::LookupRealNamedPropertyInPrototypes(Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 LookupResult* result) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003368 Isolate* isolate = GetIsolate();
3369 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003371 pt != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003372 pt = pt->GetPrototype(isolate)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003373 if (pt->IsJSProxy()) {
3374 return result->HandlerResult(JSProxy::cast(pt));
3375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003376 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003377 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR));
3378 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 }
3380 result->NotFound();
3381}
3382
3383
3384// We only need to deal with CALLBACKS and INTERCEPTORS
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003385Handle<Object> JSObject::SetPropertyWithFailedAccessCheck(
3386 Handle<JSObject> object,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003387 LookupResult* result,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003388 Handle<Name> name,
3389 Handle<Object> value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003390 bool check_prototype,
3391 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003392 if (check_prototype && !result->IsProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003393 object->LookupRealNamedPropertyInPrototypes(*name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 }
3395
3396 if (result->IsProperty()) {
3397 if (!result->IsReadOnly()) {
3398 switch (result->type()) {
3399 case CALLBACKS: {
3400 Object* obj = result->GetCallbackObject();
3401 if (obj->IsAccessorInfo()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003402 Handle<AccessorInfo> info(AccessorInfo::cast(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003403 if (info->all_can_write()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003404 return SetPropertyWithCallback(object,
3405 info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003406 name,
3407 value,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003408 handle(result->holder()),
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003409 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003411 } else if (obj->IsAccessorPair()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003412 Handle<AccessorPair> pair(AccessorPair::cast(obj));
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003413 if (pair->all_can_read()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003414 return SetPropertyWithCallback(object,
3415 pair,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003416 name,
3417 value,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003418 handle(result->holder()),
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003419 strict_mode);
3420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003421 }
3422 break;
3423 }
3424 case INTERCEPTOR: {
3425 // Try lookup real named properties. Note that only property can be
3426 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003427 LookupResult r(object->GetIsolate());
3428 object->LookupRealNamedProperty(*name, &r);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429 if (r.IsProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003430 return SetPropertyWithFailedAccessCheck(object,
3431 &r,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003432 name,
3433 value,
3434 check_prototype,
3435 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003436 }
3437 break;
3438 }
3439 default: {
3440 break;
3441 }
3442 }
3443 }
3444 }
3445
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003446 Isolate* isolate = object->GetIsolate();
3447 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
3448 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
3449 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450}
3451
3452
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003453Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
3454 LookupResult* result,
3455 Handle<Name> key,
3456 Handle<Object> value,
3457 PropertyAttributes attributes,
3458 StrictModeFlag strict_mode,
3459 StoreFromKeyed store_mode) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003460 if (result->IsHandler()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003461 return JSProxy::SetPropertyWithHandler(handle(result->proxy()),
3462 object, key, value, attributes, strict_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003463 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003464 return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object),
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003465 result, key, value, attributes, strict_mode, store_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003466 }
3467}
3468
3469
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003470bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) {
3471 Isolate* isolate = proxy->GetIsolate();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003472
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003473 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3474 if (name->IsSymbol()) return false;
3475
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003476 Handle<Object> args[] = { name };
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003477 Handle<Object> result = proxy->CallTrap(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003478 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003479 if (isolate->has_pending_exception()) return false;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003480
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003481 return result->BooleanValue();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003482}
3483
3484
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003485Handle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
3486 Handle<JSReceiver> receiver,
3487 Handle<Name> name,
3488 Handle<Object> value,
3489 PropertyAttributes attributes,
3490 StrictModeFlag strict_mode) {
3491 Isolate* isolate = proxy->GetIsolate();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003492
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003493 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003494 if (name->IsSymbol()) return value;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003495
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003496 Handle<Object> args[] = { receiver, name, value };
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003497 proxy->CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
3498 if (isolate->has_pending_exception()) return Handle<Object>();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003499
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003500 return value;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003501}
3502
3503
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003504Handle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
3505 Handle<JSProxy> proxy,
3506 Handle<JSReceiver> receiver,
3507 Handle<Name> name,
3508 Handle<Object> value,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003509 PropertyAttributes attributes,
3510 StrictModeFlag strict_mode,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003511 bool* done) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003512 Isolate* isolate = proxy->GetIsolate();
3513 Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
mmassi@chromium.org7028c052012-06-13 11:51:58 +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()) {
3517 *done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003518 return isolate->factory()->the_hole_value();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003519 }
3520
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003521 *done = true; // except where redefined...
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003522 Handle<Object> args[] = { name };
3523 Handle<Object> result = proxy->CallTrap(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003524 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003525 if (isolate->has_pending_exception()) return Handle<Object>();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003526
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003527 if (result->IsUndefined()) {
3528 *done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003529 return isolate->factory()->the_hole_value();
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003530 }
3531
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003532 // Emulate [[GetProperty]] semantics for proxies.
3533 bool has_pending_exception;
3534 Handle<Object> argv[] = { result };
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003535 Handle<Object> desc = Execution::Call(
3536 isolate, isolate->to_complete_property_descriptor(), result,
3537 ARRAY_SIZE(argv), argv, &has_pending_exception);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003538 if (has_pending_exception) return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003539
3540 // [[GetProperty]] requires to check that all properties are configurable.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003541 Handle<String> configurable_name =
3542 isolate->factory()->InternalizeOneByteString(
3543 STATIC_ASCII_VECTOR("configurable_"));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003544 Handle<Object> configurable(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003545 v8::internal::GetProperty(isolate, desc, configurable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003546 ASSERT(!isolate->has_pending_exception());
3547 ASSERT(configurable->IsTrue() || configurable->IsFalse());
3548 if (configurable->IsFalse()) {
3549 Handle<String> trap =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003550 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003551 STATIC_ASCII_VECTOR("getPropertyDescriptor"));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003552 Handle<Object> args[] = { handler, trap, name };
3553 Handle<Object> error = isolate->factory()->NewTypeError(
3554 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003555 isolate->Throw(*error);
3556 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003557 }
3558 ASSERT(configurable->IsTrue());
3559
3560 // Check for DataDescriptor.
3561 Handle<String> hasWritable_name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003562 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003563 STATIC_ASCII_VECTOR("hasWritable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003564 Handle<Object> hasWritable(
3565 v8::internal::GetProperty(isolate, desc, hasWritable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003566 ASSERT(!isolate->has_pending_exception());
3567 ASSERT(hasWritable->IsTrue() || hasWritable->IsFalse());
3568 if (hasWritable->IsTrue()) {
3569 Handle<String> writable_name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003570 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003571 STATIC_ASCII_VECTOR("writable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003572 Handle<Object> writable(
3573 v8::internal::GetProperty(isolate, desc, writable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003574 ASSERT(!isolate->has_pending_exception());
3575 ASSERT(writable->IsTrue() || writable->IsFalse());
3576 *done = writable->IsFalse();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003577 if (!*done) return isolate->factory()->the_hole_value();
3578 if (strict_mode == kNonStrictMode) return value;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003579 Handle<Object> args[] = { name, receiver };
3580 Handle<Object> error = isolate->factory()->NewTypeError(
3581 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003582 isolate->Throw(*error);
3583 return Handle<Object>();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003584 }
3585
3586 // We have an AccessorDescriptor.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003587 Handle<String> set_name = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003588 STATIC_ASCII_VECTOR("set_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003589 Handle<Object> setter(v8::internal::GetProperty(isolate, desc, set_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003590 ASSERT(!isolate->has_pending_exception());
3591 if (!setter->IsUndefined()) {
3592 // TODO(rossberg): nicer would be to cast to some JSCallable here...
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003593 return SetPropertyWithDefinedSetter(
3594 receiver, Handle<JSReceiver>::cast(setter), value);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003595 }
3596
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003597 if (strict_mode == kNonStrictMode) return value;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003598 Handle<Object> args2[] = { name, proxy };
3599 Handle<Object> error = isolate->factory()->NewTypeError(
3600 "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003601 isolate->Throw(*error);
3602 return Handle<Object>();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003603}
3604
3605
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003606Handle<Object> JSProxy::DeletePropertyWithHandler(
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003607 Handle<JSProxy> proxy, Handle<Name> name, DeleteMode mode) {
3608 Isolate* isolate = proxy->GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003609
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003610 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003611 if (name->IsSymbol()) return isolate->factory()->false_value();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003613 Handle<Object> args[] = { name };
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003614 Handle<Object> result = proxy->CallTrap(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003615 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
3616 if (isolate->has_pending_exception()) return Handle<Object>();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003617
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003618 bool result_bool = result->BooleanValue();
3619 if (mode == STRICT_DELETION && !result_bool) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003620 Handle<Object> handler(proxy->handler(), isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003621 Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003622 STATIC_ASCII_VECTOR("delete"));
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003623 Handle<Object> args[] = { handler, trap_name };
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003624 Handle<Object> error = isolate->factory()->NewTypeError(
3625 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
3626 isolate->Throw(*error);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003627 return Handle<Object>();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003628 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003629 return isolate->factory()->ToBoolean(result_bool);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003630}
3631
3632
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003633Handle<Object> JSProxy::DeleteElementWithHandler(
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003634 Handle<JSProxy> proxy, uint32_t index, DeleteMode mode) {
3635 Isolate* isolate = proxy->GetIsolate();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003636 Handle<String> name = isolate->factory()->Uint32ToString(index);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003637 return JSProxy::DeletePropertyWithHandler(proxy, name, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003638}
3639
3640
3641MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
3642 JSReceiver* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003643 Name* name_raw) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003644 Isolate* isolate = GetIsolate();
3645 HandleScope scope(isolate);
3646 Handle<JSProxy> proxy(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003647 Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003648 Handle<JSReceiver> receiver(receiver_raw);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003649 Handle<Object> name(name_raw, isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003650
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003651 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3652 if (name->IsSymbol()) return ABSENT;
3653
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003654 Handle<Object> args[] = { name };
3655 Handle<Object> result = CallTrap(
3656 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003657 if (isolate->has_pending_exception()) return NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003658
3659 if (result->IsUndefined()) return ABSENT;
3660
3661 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003662 Handle<Object> argv[] = { result };
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003663 Handle<Object> desc = Execution::Call(
3664 isolate, isolate->to_complete_property_descriptor(), result,
3665 ARRAY_SIZE(argv), argv, &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003666 if (has_pending_exception) return NONE;
3667
3668 // Convert result to PropertyAttributes.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003669 Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003670 STATIC_ASCII_VECTOR("enumerable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003671 Handle<Object> enumerable(v8::internal::GetProperty(isolate, desc, enum_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003672 if (isolate->has_pending_exception()) return NONE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003673 Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003674 STATIC_ASCII_VECTOR("configurable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003675 Handle<Object> configurable(v8::internal::GetProperty(isolate, desc, conf_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003676 if (isolate->has_pending_exception()) return NONE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003677 Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003678 STATIC_ASCII_VECTOR("writable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003679 Handle<Object> writable(v8::internal::GetProperty(isolate, desc, writ_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003680 if (isolate->has_pending_exception()) return NONE;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00003681 if (!writable->BooleanValue()) {
3682 Handle<String> set_n = isolate->factory()->InternalizeOneByteString(
3683 STATIC_ASCII_VECTOR("set_"));
3684 Handle<Object> setter(v8::internal::GetProperty(isolate, desc, set_n));
3685 if (isolate->has_pending_exception()) return NONE;
3686 writable = isolate->factory()->ToBoolean(!setter->IsUndefined());
3687 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003688
3689 if (configurable->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003690 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003691 STATIC_ASCII_VECTOR("getPropertyDescriptor"));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003692 Handle<Object> args[] = { handler, trap, name };
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003693 Handle<Object> error = isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003694 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003695 isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003696 return NONE;
3697 }
3698
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003699 int attributes = NONE;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003700 if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3701 if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3702 if (!writable->BooleanValue()) attributes |= READ_ONLY;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003703 return static_cast<PropertyAttributes>(attributes);
3704}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003705
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003706
3707MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003708 JSReceiver* receiver_raw,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003709 uint32_t index) {
3710 Isolate* isolate = GetIsolate();
3711 HandleScope scope(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003712 Handle<JSProxy> proxy(this);
3713 Handle<JSReceiver> receiver(receiver_raw);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003714 Handle<String> name = isolate->factory()->Uint32ToString(index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003715 return proxy->GetPropertyAttributeWithHandler(*receiver, *name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003716}
3717
3718
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003719void JSProxy::Fix(Handle<JSProxy> proxy) {
3720 Isolate* isolate = proxy->GetIsolate();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003721
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003722 // Save identity hash.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003723 Handle<Object> hash = JSProxy::GetIdentityHash(proxy, OMIT_CREATION);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003724
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003725 if (proxy->IsJSFunctionProxy()) {
3726 isolate->factory()->BecomeJSFunction(proxy);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003727 // Code will be set on the JavaScript side.
3728 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003729 isolate->factory()->BecomeJSObject(proxy);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003730 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003731 ASSERT(proxy->IsJSObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003732
3733 // Inherit identity, if it was present.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00003734 if (hash->IsSmi()) {
3735 JSObject::SetIdentityHash(Handle<JSObject>::cast(proxy), Smi::cast(*hash));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003736 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003737}
3738
3739
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003740MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
3741 Handle<Object> derived,
3742 int argc,
3743 Handle<Object> argv[]) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003744 Isolate* isolate = GetIsolate();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003745 Handle<Object> handler(this->handler(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003746
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003747 Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003748 Handle<Object> trap(v8::internal::GetProperty(isolate, handler, trap_name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003749 if (isolate->has_pending_exception()) return trap;
3750
3751 if (trap->IsUndefined()) {
3752 if (derived.is_null()) {
3753 Handle<Object> args[] = { handler, trap_name };
3754 Handle<Object> error = isolate->factory()->NewTypeError(
3755 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
3756 isolate->Throw(*error);
3757 return Handle<Object>();
3758 }
3759 trap = Handle<Object>(derived);
3760 }
3761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003762 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003763 return Execution::Call(isolate, trap, handler, argc, argv, &threw);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003764}
3765
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003766
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003767// TODO(mstarzinger): Temporary wrapper until handlified.
3768static Handle<Map> MapAsElementsKind(Handle<Map> map, ElementsKind kind) {
3769 CALL_HEAP_FUNCTION(map->GetIsolate(), map->AsElementsKind(kind), Map);
3770}
3771
3772
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003773void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003774 ASSERT(object->map()->inobject_properties() == map->inobject_properties());
3775 ElementsKind obj_kind = object->map()->elements_kind();
3776 ElementsKind map_kind = map->elements_kind();
3777 if (map_kind != obj_kind) {
3778 ElementsKind to_kind = map_kind;
3779 if (IsMoreGeneralElementsKindTransition(map_kind, obj_kind) ||
3780 IsDictionaryElementsKind(obj_kind)) {
3781 to_kind = obj_kind;
3782 }
3783 if (IsDictionaryElementsKind(to_kind)) {
3784 NormalizeElements(object);
3785 } else {
3786 TransitionElementsKind(object, to_kind);
3787 }
3788 map = MapAsElementsKind(map, to_kind);
3789 }
3790 int total_size =
3791 map->NumberOfOwnDescriptors() + map->unused_property_fields();
3792 int out_of_object = total_size - map->inobject_properties();
3793 if (out_of_object != object->properties()->length()) {
3794 Isolate* isolate = object->GetIsolate();
3795 Handle<FixedArray> new_properties = isolate->factory()->CopySizeFixedArray(
3796 handle(object->properties()), out_of_object);
3797 object->set_properties(*new_properties);
3798 }
3799 object->set_map(*map);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003800}
3801
3802
danno@chromium.orgf005df62013-04-30 16:36:45 +00003803void JSObject::MigrateInstance(Handle<JSObject> object) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003804 // Converting any field to the most specific type will cause the
3805 // GeneralizeFieldRepresentation algorithm to create the most general existing
3806 // transition that matches the object. This achieves what is needed.
3807 Handle<Map> original_map(object->map());
3808 GeneralizeFieldRepresentation(
3809 object, 0, Representation::None(), ALLOW_AS_CONSTANT);
3810 if (FLAG_trace_migration) {
3811 object->PrintInstanceMigration(stdout, *original_map, object->map());
3812 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003813}
3814
3815
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003816Handle<Object> JSObject::TryMigrateInstance(Handle<JSObject> object) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003817 Map* new_map = object->map()->CurrentMapForDeprecated();
3818 if (new_map == NULL) return Handle<Object>();
3819 Handle<Map> original_map(object->map());
3820 JSObject::MigrateToMap(object, handle(new_map));
3821 if (FLAG_trace_migration) {
3822 object->PrintInstanceMigration(stdout, *original_map, object->map());
3823 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003824 return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003825}
3826
3827
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003828Handle<Object> JSObject::SetPropertyUsingTransition(
3829 Handle<JSObject> object,
3830 LookupResult* lookup,
3831 Handle<Name> name,
3832 Handle<Object> value,
3833 PropertyAttributes attributes) {
3834 Handle<Map> transition_map(lookup->GetTransitionTarget());
rossberg@chromium.org92597162013-08-23 13:28:00 +00003835 int descriptor = transition_map->LastAdded();
3836
3837 DescriptorArray* descriptors = transition_map->instance_descriptors();
3838 PropertyDetails details = descriptors->GetDetails(descriptor);
3839
3840 if (details.type() == CALLBACKS || attributes != details.attributes()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003841 // AddProperty will either normalize the object, or create a new fast copy
3842 // of the map. If we get a fast copy of the map, all field representations
3843 // will be tagged since the transition is omitted.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003844 return JSObject::AddProperty(
3845 object, name, value, attributes, kNonStrictMode,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003846 JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
3847 JSReceiver::OMIT_EXTENSIBILITY_CHECK,
3848 JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION);
rossberg@chromium.org92597162013-08-23 13:28:00 +00003849 }
3850
3851 // Keep the target CONSTANT if the same value is stored.
3852 // TODO(verwaest): Also support keeping the placeholder
3853 // (value->IsUninitialized) as constant.
3854 if (details.type() == CONSTANT &&
3855 descriptors->GetValue(descriptor) == *value) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003856 object->set_map(*transition_map);
3857 return value;
rossberg@chromium.org92597162013-08-23 13:28:00 +00003858 }
3859
3860 Representation representation = details.representation();
3861
3862 if (!value->FitsRepresentation(representation) ||
3863 details.type() == CONSTANT) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003864 transition_map = Map::GeneralizeRepresentation(transition_map,
rossberg@chromium.org92597162013-08-23 13:28:00 +00003865 descriptor, value->OptimalRepresentation(), FORCE_FIELD);
rossberg@chromium.org92597162013-08-23 13:28:00 +00003866 Object* back = transition_map->GetBackPointer();
3867 if (back->IsMap()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003868 MigrateToMap(object, handle(Map::cast(back)));
rossberg@chromium.org92597162013-08-23 13:28:00 +00003869 }
3870 descriptors = transition_map->instance_descriptors();
3871 representation = descriptors->GetDetails(descriptor).representation();
3872 }
3873
3874 int field_index = descriptors->GetFieldIndex(descriptor);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003875 AddFastPropertyUsingMap(
3876 object, transition_map, name, value, field_index, representation);
3877 return value;
rossberg@chromium.org92597162013-08-23 13:28:00 +00003878}
3879
3880
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003881static void SetPropertyToField(LookupResult* lookup,
3882 Handle<Name> name,
3883 Handle<Object> value) {
rossberg@chromium.org92597162013-08-23 13:28:00 +00003884 Representation representation = lookup->representation();
3885 if (!value->FitsRepresentation(representation) ||
3886 lookup->type() == CONSTANT) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003887 JSObject::GeneralizeFieldRepresentation(handle(lookup->holder()),
3888 lookup->GetDescriptorIndex(),
3889 value->OptimalRepresentation(),
3890 FORCE_FIELD);
rossberg@chromium.org92597162013-08-23 13:28:00 +00003891 DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
3892 int descriptor = lookup->GetDescriptorIndex();
3893 representation = desc->GetDetails(descriptor).representation();
3894 }
3895
3896 if (FLAG_track_double_fields && representation.IsDouble()) {
3897 HeapNumber* storage = HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
3898 lookup->GetFieldIndex().field_index()));
3899 storage->set_value(value->Number());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003900 return;
rossberg@chromium.org92597162013-08-23 13:28:00 +00003901 }
3902
3903 lookup->holder()->FastPropertyAtPut(
3904 lookup->GetFieldIndex().field_index(), *value);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003905}
3906
3907
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003908static void ConvertAndSetLocalProperty(LookupResult* lookup,
3909 Handle<Name> name,
3910 Handle<Object> value,
3911 PropertyAttributes attributes) {
3912 Handle<JSObject> object(lookup->holder());
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003913 if (object->TooManyFastProperties()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003914 JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003915 }
3916
3917 if (!object->HasFastProperties()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003918 ReplaceSlowProperty(object, name, value, attributes);
3919 return;
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003920 }
3921
3922 int descriptor_index = lookup->GetDescriptorIndex();
3923 if (lookup->GetAttributes() == attributes) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003924 JSObject::GeneralizeFieldRepresentation(
3925 object, descriptor_index, Representation::Tagged(), FORCE_FIELD);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003926 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003927 Handle<Map> old_map(object->map());
3928 Handle<Map> new_map = Map::CopyGeneralizeAllRepresentations(old_map,
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003929 descriptor_index, FORCE_FIELD, attributes, "attributes mismatch");
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003930 JSObject::MigrateToMap(object, new_map);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003931 }
3932
3933 DescriptorArray* descriptors = object->map()->instance_descriptors();
3934 int index = descriptors->GetDetails(descriptor_index).field_index();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003935 object->FastPropertyAtPut(index, *value);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00003936}
3937
3938
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003939static void SetPropertyToFieldWithAttributes(LookupResult* lookup,
3940 Handle<Name> name,
3941 Handle<Object> value,
3942 PropertyAttributes attributes) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003943 if (lookup->GetAttributes() == attributes) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003944 if (value->IsUninitialized()) return;
3945 SetPropertyToField(lookup, name, value);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003946 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003947 ConvertAndSetLocalProperty(lookup, name, value, attributes);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00003948 }
3949}
3950
3951
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003952Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
3953 LookupResult* lookup,
3954 Handle<Name> name,
3955 Handle<Object> value,
3956 PropertyAttributes attributes,
3957 StrictModeFlag strict_mode,
3958 StoreFromKeyed store_mode) {
3959 Isolate* isolate = object->GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003960
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 // Make sure that the top context does not change when doing callbacks or
3962 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00003963 AssertNoContextChange ncc(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003964
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003965 // Optimization for 2-byte strings often used as keys in a decompression
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003966 // dictionary. We internalize these short keys to avoid constantly
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003967 // reallocating them.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003968 if (name->IsString() && !name->IsInternalizedString() &&
3969 Handle<String>::cast(name)->length() <= 2) {
3970 name = isolate->factory()->InternalizeString(Handle<String>::cast(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003972
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00003973 // Check access rights if needed.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003974 if (object->IsAccessCheckNeeded()) {
3975 if (!isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
3976 return SetPropertyWithFailedAccessCheck(object, lookup, name, value,
3977 true, strict_mode);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00003978 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003979 }
3980
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003981 if (object->IsJSGlobalProxy()) {
3982 Handle<Object> proto(object->GetPrototype(), isolate);
3983 if (proto->IsNull()) return value;
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00003984 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003985 return SetPropertyForResult(Handle<JSObject>::cast(proto),
3986 lookup, name, value, attributes, strict_mode, store_mode);
hpayer@chromium.org2f877ac2013-09-18 15:29:06 +00003987 }
3988
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003989 ASSERT(!lookup->IsFound() || lookup->holder() == *object ||
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003990 lookup->holder()->map()->is_hidden_prototype());
3991
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003992 if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003993 bool done = false;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00003994 Handle<Object> result_object = SetPropertyViaPrototypes(
3995 object, name, value, attributes, strict_mode, &done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003996 if (done) return result_object;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003997 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003998
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003999 if (!lookup->IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004000 // Neither properties nor transitions found.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004001 return AddProperty(
4002 object, name, value, attributes, strict_mode, store_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004003 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004004
4005 if (lookup->IsProperty() && lookup->IsReadOnly()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004006 if (strict_mode == kStrictMode) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004007 Handle<Object> args[] = { name, object };
4008 Handle<Object> error = isolate->factory()->NewTypeError(
4009 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
4010 isolate->Throw(*error);
4011 return Handle<Object>();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004012 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004013 return value;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004014 }
4015 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004016
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004017 Handle<Object> old_value = isolate->factory()->the_hole_value();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00004018 if (FLAG_harmony_observation &&
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004019 object->map()->is_observed() && lookup->IsDataProperty()) {
4020 old_value = Object::GetProperty(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004021 }
4022
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004023 // This is a real property that is not read-only, or it is a
4024 // transition or null descriptor and there are no setters in the prototypes.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004025 Handle<Object> result = value;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004026 switch (lookup->type()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004027 case NORMAL:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004028 SetNormalizedProperty(handle(lookup->holder()), lookup, value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004029 break;
rossberg@chromium.org92597162013-08-23 13:28:00 +00004030 case FIELD:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004031 SetPropertyToField(lookup, name, value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004032 break;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004033 case CONSTANT:
4034 // Only replace the constant if necessary.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004035 if (*value == lookup->GetConstant()) return value;
4036 SetPropertyToField(lookup, name, value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004037 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004038 case CALLBACKS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004039 Handle<Object> callback_object(lookup->GetCallbackObject(), isolate);
4040 return SetPropertyWithCallback(object, callback_object, name, value,
4041 handle(lookup->holder()), strict_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004042 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004043 case INTERCEPTOR:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004044 result = SetPropertyWithInterceptor(handle(lookup->holder()), name, value,
4045 attributes, strict_mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004046 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004047 case TRANSITION:
4048 result = SetPropertyUsingTransition(handle(lookup->holder()), lookup,
4049 name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004050 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004051 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004052 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004053 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004055
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004056 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004057
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004058 if (FLAG_harmony_observation && object->map()->is_observed()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004059 if (lookup->IsTransition()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004060 EnqueueChangeRecord(object, "new", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004061 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004062 LookupResult new_lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004063 object->LocalLookup(*name, &new_lookup, true);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004064 if (new_lookup.IsDataProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004065 Handle<Object> new_value = Object::GetProperty(object, name);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004066 if (!new_value->SameValue(*old_value)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004067 EnqueueChangeRecord(object, "updated", name, old_value);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004068 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004069 }
4070 }
4071 }
4072
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004073 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074}
4075
4076
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004077MaybeObject* JSObject::SetLocalPropertyIgnoreAttributesTrampoline(
4078 Name* key,
4079 Object* value,
4080 PropertyAttributes attributes,
4081 ValueType value_type,
4082 StoreMode mode,
4083 ExtensibilityCheck extensibility_check) {
4084 // TODO(mstarzinger): The trampoline is a giant hack, don't use it anywhere
4085 // else or handlification people will start hating you for all eternity.
4086 HandleScope scope(GetIsolate());
4087 IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
4088 return trampoline.CallWithReturnValue(
4089 &JSObject::SetLocalPropertyIgnoreAttributes,
4090 Handle<JSObject>(this),
4091 Handle<Name>(key),
4092 Handle<Object>(value, GetIsolate()),
4093 attributes,
4094 value_type,
4095 mode,
4096 extensibility_check);
4097}
4098
4099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004101// present, add it with attributes NONE. This code is an exact clone of
4102// SetProperty, with the check for IsReadOnly and the check for a
4103// callback setter removed. The two lines looking up the LookupResult
4104// result are also added. If one of the functions is changed, the other
4105// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004106// Note that this method cannot be used to set the prototype of a function
4107// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
4108// doesn't handle function prototypes correctly.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004109Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
4110 Handle<JSObject> object,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004111 Handle<Name> name,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004112 Handle<Object> value,
danno@chromium.org1fd77d52013-06-07 16:01:45 +00004113 PropertyAttributes attributes,
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004114 ValueType value_type,
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004115 StoreMode mode,
4116 ExtensibilityCheck extensibility_check) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004117 Isolate* isolate = object->GetIsolate();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004118
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119 // Make sure that the top context does not change when doing callbacks or
4120 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004121 AssertNoContextChange ncc(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004122
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004123 LookupResult lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004124 object->LocalLookup(*name, &lookup, true);
4125 if (!lookup.IsFound()) {
4126 object->map()->LookupTransition(*object, *name, &lookup);
4127 }
4128
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004129 // Check access rights if needed.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004130 if (object->IsAccessCheckNeeded()) {
4131 if (!isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
4132 return SetPropertyWithFailedAccessCheck(object, &lookup, name, value,
4133 false, kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004134 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004135 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004136
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004137 if (object->IsJSGlobalProxy()) {
4138 Handle<Object> proto(object->GetPrototype(), isolate);
4139 if (proto->IsNull()) return value;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004140 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004141 return SetLocalPropertyIgnoreAttributes(Handle<JSObject>::cast(proto),
4142 name, value, attributes, value_type, mode, extensibility_check);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004143 }
4144
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004145 if (lookup.IsFound() &&
4146 (lookup.type() == INTERCEPTOR || lookup.type() == CALLBACKS)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004147 object->LocalLookupRealNamedProperty(*name, &lookup);
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004148 }
4149
ager@chromium.org7c537e22008-10-16 08:43:32 +00004150 // Check for accessor in prototype chain removed here in clone.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004151 if (!lookup.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004152 // Neither properties nor transitions found.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004153 return AddProperty(object, name, value, attributes, kNonStrictMode,
rossberg@chromium.org92597162013-08-23 13:28:00 +00004154 MAY_BE_STORE_FROM_KEYED, extensibility_check, value_type, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004155 }
4156
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004157 Handle<Object> old_value = isolate->factory()->the_hole_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004158 PropertyAttributes old_attributes = ABSENT;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004159 bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
danno@chromium.org169691d2013-07-15 08:01:13 +00004160 if (is_observed && lookup.IsProperty()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00004161 if (lookup.IsDataProperty()) old_value =
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004162 Object::GetProperty(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004163 old_attributes = lookup.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004165
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004166 // Check of IsReadOnly removed from here in clone.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004167 switch (lookup.type()) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004168 case NORMAL:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004169 ReplaceSlowProperty(object, name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004170 break;
rossberg@chromium.org92597162013-08-23 13:28:00 +00004171 case FIELD:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004172 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004173 break;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004174 case CONSTANT:
rossberg@chromium.org92597162013-08-23 13:28:00 +00004175 // Only replace the constant if necessary.
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004176 if (lookup.GetAttributes() != attributes ||
4177 *value != lookup.GetConstant()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004178 SetPropertyToFieldWithAttributes(&lookup, name, value, attributes);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00004179 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004180 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004181 case CALLBACKS:
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004182 ConvertAndSetLocalProperty(&lookup, name, value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004183 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004184 case TRANSITION: {
4185 Handle<Object> result = SetPropertyUsingTransition(
4186 handle(lookup.holder()), &lookup, name, value, attributes);
4187 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<Object>());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004188 break;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004189 }
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004190 case NONEXISTENT:
mstarzinger@chromium.org1f410f92013-08-29 08:13:16 +00004191 case HANDLER:
4192 case INTERCEPTOR:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004193 UNREACHABLE();
4194 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004195
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00004196 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004197 if (lookup.IsTransition()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004198 EnqueueChangeRecord(object, "new", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00004199 } else if (old_value->IsTheHole()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004200 EnqueueChangeRecord(object, "reconfigured", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004201 } else {
4202 LookupResult new_lookup(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004203 object->LocalLookup(*name, &new_lookup, true);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004204 bool value_changed = false;
4205 if (new_lookup.IsDataProperty()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004206 Handle<Object> new_value = Object::GetProperty(object, name);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004207 value_changed = !old_value->SameValue(*new_value);
4208 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00004209 if (new_lookup.GetAttributes() != old_attributes) {
4210 if (!value_changed) old_value = isolate->factory()->the_hole_value();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004211 EnqueueChangeRecord(object, "reconfigured", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00004212 } else if (value_changed) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004213 EnqueueChangeRecord(object, "updated", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004214 }
4215 }
4216 }
4217
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004218 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004219}
4220
4221
4222PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
4223 JSObject* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004224 Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 bool continue_search) {
4226 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004227 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004229 if (result.IsFound()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
4231 if (continue_search) {
4232 // Continue searching via the prototype chain.
4233 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004234 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004235 return JSObject::cast(pt)->
4236 GetPropertyAttributeWithReceiver(receiver, name);
4237 }
4238 }
4239 return ABSENT;
4240}
4241
4242
4243PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
4244 JSObject* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004245 Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246 bool continue_search) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00004247 // TODO(rossberg): Support symbols in the API.
4248 if (name->IsSymbol()) return ABSENT;
4249
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004250 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004251 HandleScope scope(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 // Make sure that the top context does not change when doing
4254 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004255 AssertNoContextChange ncc(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004257 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
4258 Handle<JSObject> receiver_handle(receiver);
4259 Handle<JSObject> holder_handle(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004260 Handle<String> name_handle(String::cast(name));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004261 PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004262 if (!interceptor->query()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004263 v8::NamedPropertyQueryCallback query =
4264 v8::ToCData<v8::NamedPropertyQueryCallback>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004265 LOG(isolate,
4266 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004267 v8::Handle<v8::Integer> result =
4268 args.Call(query, v8::Utils::ToLocal(name_handle));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004269 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004270 ASSERT(result->IsInt32());
4271 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272 }
4273 } else if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004274 v8::NamedPropertyGetterCallback getter =
4275 v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004276 LOG(isolate,
4277 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004278 v8::Handle<v8::Value> result =
4279 args.Call(getter, v8::Utils::ToLocal(name_handle));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004280 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004281 }
4282 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
4283 *name_handle,
4284 continue_search);
4285}
4286
4287
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004288PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
4289 JSReceiver* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004290 Name* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004291 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004292 if (IsJSObject() && key->AsArrayIndex(&index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004293 return JSObject::cast(this)->GetElementAttributeWithReceiver(
4294 receiver, index, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295 }
4296 // Named property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004297 LookupResult lookup(GetIsolate());
4298 Lookup(key, &lookup);
4299 return GetPropertyAttributeForResult(receiver, &lookup, key, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300}
4301
4302
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004303PropertyAttributes JSReceiver::GetPropertyAttributeForResult(
4304 JSReceiver* receiver,
4305 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004306 Name* name,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004307 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004308 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004309 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004310 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004311 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004312 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
4313 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004314 receiver, lookup, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004315 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004316 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004317 if (lookup->IsFound()) {
4318 switch (lookup->type()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004319 case NORMAL: // fall through
4320 case FIELD:
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004321 case CONSTANT:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004322 case CALLBACKS:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004323 return lookup->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004324 case HANDLER: {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004325 return JSProxy::cast(lookup->proxy())->GetPropertyAttributeWithHandler(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004326 receiver, name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004327 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004328 case INTERCEPTOR:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004329 return lookup->holder()->GetPropertyAttributeWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004330 JSObject::cast(receiver), name, continue_search);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004331 case TRANSITION:
4332 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004333 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 }
4335 }
4336 return ABSENT;
4337}
4338
4339
ulan@chromium.org750145a2013-03-07 15:14:13 +00004340PropertyAttributes JSReceiver::GetLocalPropertyAttribute(Name* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004341 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004342 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004343 if (IsJSObject() && name->AsArrayIndex(&index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004344 return GetLocalElementAttribute(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004345 }
4346 // Named property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004347 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004348 LocalLookup(name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004349 return GetPropertyAttributeForResult(this, &lookup, name, false);
4350}
4351
4352
4353PropertyAttributes JSObject::GetElementAttributeWithReceiver(
4354 JSReceiver* receiver, uint32_t index, bool continue_search) {
4355 Isolate* isolate = GetIsolate();
4356
4357 // Check access rights if needed.
4358 if (IsAccessCheckNeeded()) {
4359 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
4360 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4361 return ABSENT;
4362 }
4363 }
4364
4365 if (IsJSGlobalProxy()) {
4366 Object* proto = GetPrototype();
4367 if (proto->IsNull()) return ABSENT;
4368 ASSERT(proto->IsJSGlobalObject());
4369 return JSObject::cast(proto)->GetElementAttributeWithReceiver(
4370 receiver, index, continue_search);
4371 }
4372
4373 // Check for lookup interceptor except when bootstrapping.
4374 if (HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4375 return GetElementAttributeWithInterceptor(receiver, index, continue_search);
4376 }
4377
4378 return GetElementAttributeWithoutInterceptor(
4379 receiver, index, continue_search);
4380}
4381
4382
4383PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
4384 JSReceiver* receiver, uint32_t index, bool continue_search) {
4385 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004386 HandleScope scope(isolate);
4387
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004388 // Make sure that the top context does not change when doing
4389 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00004390 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00004391
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004392 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
4393 Handle<JSReceiver> hreceiver(receiver);
4394 Handle<JSObject> holder(this);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004395 PropertyCallbackArguments args(isolate, interceptor->data(), receiver, this);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004396 if (!interceptor->query()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004397 v8::IndexedPropertyQueryCallback query =
4398 v8::ToCData<v8::IndexedPropertyQueryCallback>(interceptor->query());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004399 LOG(isolate,
4400 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004401 v8::Handle<v8::Integer> result = args.Call(query, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004402 if (!result.IsEmpty())
4403 return static_cast<PropertyAttributes>(result->Int32Value());
4404 } else if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00004405 v8::IndexedPropertyGetterCallback getter =
4406 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004407 LOG(isolate,
4408 ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004409 v8::Handle<v8::Value> result = args.Call(getter, index);
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004410 if (!result.IsEmpty()) return NONE;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004411 }
4412
4413 return holder->GetElementAttributeWithoutInterceptor(
4414 *hreceiver, index, continue_search);
4415}
4416
4417
4418PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor(
4419 JSReceiver* receiver, uint32_t index, bool continue_search) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004420 PropertyAttributes attr = GetElementsAccessor()->GetAttributes(
4421 receiver, this, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004422 if (attr != ABSENT) return attr;
4423
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004424 // Handle [] on String objects.
4425 if (IsStringObjectWithCharacterAt(index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004426 return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
4427 }
4428
4429 if (!continue_search) return ABSENT;
4430
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004431 Object* pt = GetPrototype();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004432 if (pt->IsJSProxy()) {
4433 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004434 return JSProxy::cast(pt)->GetElementAttributeWithHandler(receiver, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004435 }
4436 if (pt->IsNull()) return ABSENT;
4437 return JSObject::cast(pt)->GetElementAttributeWithReceiver(
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004438 receiver, index, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439}
4440
4441
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004442Handle<Map> NormalizedMapCache::Get(Handle<NormalizedMapCache> cache,
4443 Handle<JSObject> obj,
4444 PropertyNormalizationMode mode) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004445 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004446 int index = fast->Hash() % kEntries;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004447 Object* result = cache->get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004448 if (result->IsMap() &&
4449 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004450#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004451 if (FLAG_verify_heap) {
4452 Map::cast(result)->SharedMapVerify();
4453 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004454#endif
4455#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004456 if (FLAG_enable_slow_asserts) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004457 // The cached map should match newly created normalized map bit-by-bit,
4458 // except for the code cache, which can contain some ics which can be
4459 // applied to the shared map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004460 Object* fresh;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004461 MaybeObject* maybe_fresh =
4462 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
4463 if (maybe_fresh->ToObject(&fresh)) {
4464 ASSERT(memcmp(Map::cast(fresh)->address(),
4465 Map::cast(result)->address(),
4466 Map::kCodeCacheOffset) == 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004467 STATIC_ASSERT(Map::kDependentCodeOffset ==
4468 Map::kCodeCacheOffset + kPointerSize);
4469 int offset = Map::kDependentCodeOffset + kPointerSize;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004470 ASSERT(memcmp(Map::cast(fresh)->address() + offset,
4471 Map::cast(result)->address() + offset,
4472 Map::kSize - offset) == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004473 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004474 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004475#endif
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004476 return handle(Map::cast(result));
ricow@chromium.org65fae842010-08-25 15:26:24 +00004477 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004478
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004479 Isolate* isolate = cache->GetIsolate();
4480 Handle<Map> map = Map::CopyNormalized(handle(fast), mode,
4481 SHARED_NORMALIZED_MAP);
4482 ASSERT(map->is_dictionary_map());
4483 cache->set(index, *map);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004484 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004485
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004486 return map;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004487}
4488
4489
ricow@chromium.org65fae842010-08-25 15:26:24 +00004490void NormalizedMapCache::Clear() {
4491 int entries = length();
4492 for (int i = 0; i != entries; i++) {
4493 set_undefined(i);
4494 }
4495}
4496
4497
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00004498void HeapObject::UpdateMapCodeCache(Handle<HeapObject> object,
4499 Handle<Name> name,
4500 Handle<Code> code) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004501 Handle<Map> map(object->map());
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004502 Map::UpdateCodeCache(map, name, code);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004503}
4504
4505
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004506void JSObject::NormalizeProperties(Handle<JSObject> object,
4507 PropertyNormalizationMode mode,
4508 int expected_additional_properties) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004509 if (!object->HasFastProperties()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004510
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004511 // The global object is always normalized.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004512 ASSERT(!object->IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004513 // JSGlobalProxy must never be normalized
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004514 ASSERT(!object->IsJSGlobalProxy());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004515
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004516 Isolate* isolate = object->GetIsolate();
4517 HandleScope scope(isolate);
4518 Handle<Map> map(object->map());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004519
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004520 // Allocate new content.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004521 int real_size = map->NumberOfOwnDescriptors();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004522 int property_count = real_size;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004523 if (expected_additional_properties > 0) {
4524 property_count += expected_additional_properties;
4525 } else {
4526 property_count += 2; // Make space for two more properties.
4527 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004528 Handle<NameDictionary> dictionary =
4529 isolate->factory()->NewNameDictionary(property_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004530
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004531 Handle<DescriptorArray> descs(map->instance_descriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004532 for (int i = 0; i < real_size; i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004533 PropertyDetails details = descs->GetDetails(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534 switch (details.type()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00004535 case CONSTANT: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004536 Handle<Name> key(descs->GetKey(i));
4537 Handle<Object> value(descs->GetConstant(i), isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004538 PropertyDetails d = PropertyDetails(
4539 details.attributes(), NORMAL, i + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004540 dictionary = NameDictionaryAdd(dictionary, key, value, d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 break;
4542 }
4543 case FIELD: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004544 Handle<Name> key(descs->GetKey(i));
4545 Handle<Object> value(
4546 object->RawFastPropertyAt(descs->GetFieldIndex(i)), isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004547 PropertyDetails d =
4548 PropertyDetails(details.attributes(), NORMAL, i + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004549 dictionary = NameDictionaryAdd(dictionary, key, value, d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 break;
4551 }
4552 case CALLBACKS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004553 Handle<Name> key(descs->GetKey(i));
4554 Handle<Object> value(descs->GetCallbacksObject(i), isolate);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004555 PropertyDetails d = PropertyDetails(
4556 details.attributes(), CALLBACKS, i + 1);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004557 dictionary = NameDictionaryAdd(dictionary, key, value, d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004558 break;
4559 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004560 case INTERCEPTOR:
4561 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004562 case HANDLER:
4563 case NORMAL:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004564 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004565 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004566 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00004567 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568 }
4569 }
4570
4571 // Copy the next enumeration index from instance descriptor.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004572 dictionary->SetNextEnumerationIndex(real_size + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004573
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004574 Handle<NormalizedMapCache> cache(
4575 isolate->context()->native_context()->normalized_map_cache());
4576 Handle<Map> new_map = NormalizedMapCache::Get(cache, object, mode);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004577 ASSERT(new_map->is_dictionary_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004578
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004579 // From here on we cannot fail and we shouldn't GC anymore.
4580 DisallowHeapAllocation no_allocation;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004581
4582 // Resize the object in the heap if necessary.
4583 int new_instance_size = new_map->instance_size();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004584 int instance_size_delta = map->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004585 ASSERT(instance_size_delta >= 0);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004586 isolate->heap()->CreateFillerObjectAt(object->address() + new_instance_size,
4587 instance_size_delta);
4588 if (Marking::IsBlack(Marking::MarkBitFrom(*object))) {
4589 MemoryChunk::IncrementLiveBytesFromMutator(object->address(),
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004590 -instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004591 }
4592
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004593 object->set_map(*new_map);
4594 map->NotifyLeafMapLayoutChange();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004596 object->set_properties(*dictionary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004597
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004598 isolate->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004599
4600#ifdef DEBUG
4601 if (FLAG_trace_normalization) {
4602 PrintF("Object properties have been normalized:\n");
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004603 object->Print();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004604 }
4605#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004606}
4607
4608
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004609void JSObject::TransformToFastProperties(Handle<JSObject> object,
4610 int unused_property_fields) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004611 if (object->HasFastProperties()) return;
4612 ASSERT(!object->IsGlobalObject());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004613 CALL_HEAP_FUNCTION_VOID(
4614 object->GetIsolate(),
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004615 object->property_dictionary()->TransformPropertiesToFastFor(
4616 *object, unused_property_fields));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004617}
4618
4619
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004620static MUST_USE_RESULT MaybeObject* CopyFastElementsToDictionary(
4621 Isolate* isolate,
4622 FixedArrayBase* array,
4623 int length,
4624 SeededNumberDictionary* dictionary) {
4625 Heap* heap = isolate->heap();
4626 bool has_double_elements = array->IsFixedDoubleArray();
4627 for (int i = 0; i < length; i++) {
4628 Object* value = NULL;
4629 if (has_double_elements) {
4630 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
4631 if (double_array->is_the_hole(i)) {
4632 value = isolate->heap()->the_hole_value();
4633 } else {
4634 // Objects must be allocated in the old object space, since the
4635 // overall number of HeapNumbers needed for the conversion might
4636 // exceed the capacity of new space, and we would fail repeatedly
4637 // trying to convert the FixedDoubleArray.
4638 MaybeObject* maybe_value_object =
4639 heap->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
4640 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
4641 }
4642 } else {
4643 value = FixedArray::cast(array)->get(i);
4644 }
4645 if (!value->IsTheHole()) {
4646 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
4647 MaybeObject* maybe_result =
4648 dictionary->AddNumberEntry(i, value, details);
4649 if (!maybe_result->To(&dictionary)) return maybe_result;
4650 }
4651 }
4652 return dictionary;
4653}
4654
4655
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004656static Handle<SeededNumberDictionary> CopyFastElementsToDictionary(
4657 Handle<FixedArrayBase> array,
4658 int length,
4659 Handle<SeededNumberDictionary> dict) {
4660 Isolate* isolate = array->GetIsolate();
4661 CALL_HEAP_FUNCTION(isolate,
4662 CopyFastElementsToDictionary(
4663 isolate, *array, length, *dict),
4664 SeededNumberDictionary);
4665}
4666
4667
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004668Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4669 Handle<JSObject> object) {
4670 CALL_HEAP_FUNCTION(object->GetIsolate(),
4671 object->NormalizeElements(),
4672 SeededNumberDictionary);
4673}
4674
4675
lrn@chromium.org303ada72010-10-27 09:33:13 +00004676MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004677 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004678
whesse@chromium.org7b260152011-06-20 15:33:18 +00004679 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004680 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004681 Map* old_map = array->map();
4682 bool is_arguments =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004683 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004684 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004685 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004686 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004687 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004689 ASSERT(HasFastSmiOrObjectElements() ||
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004690 HasFastDoubleElements() ||
4691 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004692 // Compute the effective length and allocate a new backing store.
4693 int length = IsJSArray()
4694 ? Smi::cast(JSArray::cast(this)->length())->value()
4695 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004696 int old_capacity = 0;
4697 int used_elements = 0;
4698 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004699 SeededNumberDictionary* dictionary;
4700 MaybeObject* maybe_dictionary =
4701 SeededNumberDictionary::Allocate(GetHeap(), used_elements);
4702 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004703
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004704 maybe_dictionary = CopyFastElementsToDictionary(
4705 GetIsolate(), array, length, dictionary);
4706 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707
whesse@chromium.org7b260152011-06-20 15:33:18 +00004708 // Switch to using the dictionary as the backing storage for elements.
4709 if (is_arguments) {
4710 FixedArray::cast(elements())->set(1, dictionary);
4711 } else {
4712 // Set the new map first to satify the elements type assert in
4713 // set_elements().
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004714 Map* new_map;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004715 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
4716 DICTIONARY_ELEMENTS);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00004717 if (!maybe->To(&new_map)) return maybe;
4718 set_map(new_map);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004719 set_elements(dictionary);
4720 }
4721
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004722 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
4723 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004724
4725#ifdef DEBUG
4726 if (FLAG_trace_normalization) {
4727 PrintF("Object elements have been normalized:\n");
4728 Print();
4729 }
4730#endif
4731
whesse@chromium.org7b260152011-06-20 15:33:18 +00004732 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4733 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004734}
4735
4736
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004737Smi* JSReceiver::GenerateIdentityHash() {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004738 Isolate* isolate = GetIsolate();
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004739
4740 int hash_value;
4741 int attempts = 0;
4742 do {
4743 // Generate a random 32-bit hash value but limit range to fit
4744 // within a smi.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004745 hash_value = isolate->random_number_generator()->NextInt() & Smi::kMaxValue;
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004746 attempts++;
4747 } while (hash_value == 0 && attempts < 30);
4748 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
4749
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004750 return Smi::FromInt(hash_value);
4751}
4752
4753
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004754void JSObject::SetIdentityHash(Handle<JSObject> object, Smi* hash) {
4755 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
4756 object->SetHiddenProperty(
4757 object->GetHeap()->identity_hash_string(), hash));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004758}
4759
4760
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004761int JSObject::GetIdentityHash(Handle<JSObject> object) {
4762 CALL_AND_RETRY_OR_DIE(object->GetIsolate(),
4763 object->GetIdentityHash(ALLOW_CREATION),
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004764 return Smi::cast(__object__)->value(),
4765 return 0);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004766}
4767
4768
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004769MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004770 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004771 if (stored_value->IsSmi()) return stored_value;
4772
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004773 // Do not generate permanent identity hash code if not requested.
4774 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
4775
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004776 Smi* hash = GenerateIdentityHash();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004777 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_string(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004778 hash);
4779 if (result->IsFailure()) return result;
4780 if (result->ToObjectUnchecked()->IsUndefined()) {
4781 // Trying to get hash of detached proxy.
4782 return Smi::FromInt(0);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004783 }
4784 return hash;
4785}
4786
4787
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004788Handle<Object> JSProxy::GetIdentityHash(Handle<JSProxy> proxy,
4789 CreationFlag flag) {
4790 CALL_HEAP_FUNCTION(proxy->GetIsolate(), proxy->GetIdentityHash(flag), Object);
4791}
4792
4793
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004794MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
4795 Object* hash = this->hash();
4796 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
4797 hash = GenerateIdentityHash();
4798 set_hash(hash);
4799 }
4800 return hash;
4801}
4802
4803
ulan@chromium.org750145a2013-03-07 15:14:13 +00004804Object* JSObject::GetHiddenProperty(Name* key) {
4805 ASSERT(key->IsUniqueName());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004806 if (IsJSGlobalProxy()) {
4807 // For a proxy, use the prototype as target object.
4808 Object* proxy_parent = GetPrototype();
4809 // If the proxy is detached, return undefined.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004810 if (proxy_parent->IsNull()) return GetHeap()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004811 ASSERT(proxy_parent->IsJSGlobalObject());
4812 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
4813 }
4814 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004815 MaybeObject* hidden_lookup =
4816 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004817 Object* inline_value = hidden_lookup->ToObjectUnchecked();
4818
4819 if (inline_value->IsSmi()) {
4820 // Handle inline-stored identity hash.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004821 if (key == GetHeap()->identity_hash_string()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004822 return inline_value;
4823 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004824 return GetHeap()->the_hole_value();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004825 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004826 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004827
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004828 if (inline_value->IsUndefined()) return GetHeap()->the_hole_value();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004829
4830 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4831 Object* entry = hashtable->Lookup(key);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004832 return entry;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004833}
4834
4835
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004836Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004837 Handle<Name> key,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004838 Handle<Object> value) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004839 CALL_HEAP_FUNCTION(obj->GetIsolate(),
4840 obj->SetHiddenProperty(*key, *value),
4841 Object);
4842}
4843
4844
ulan@chromium.org750145a2013-03-07 15:14:13 +00004845MaybeObject* JSObject::SetHiddenProperty(Name* key, Object* value) {
4846 ASSERT(key->IsUniqueName());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004847 if (IsJSGlobalProxy()) {
4848 // For a proxy, use the prototype as target object.
4849 Object* proxy_parent = GetPrototype();
4850 // If the proxy is detached, return undefined.
4851 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
4852 ASSERT(proxy_parent->IsJSGlobalObject());
4853 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
4854 }
4855 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004856 MaybeObject* hidden_lookup =
4857 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004858 Object* inline_value = hidden_lookup->ToObjectUnchecked();
4859
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004860 // If there is no backing store yet, store the identity hash inline.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004861 if (value->IsSmi() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004862 key == GetHeap()->identity_hash_string() &&
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004863 (inline_value->IsUndefined() || inline_value->IsSmi())) {
4864 return SetHiddenPropertiesHashTable(value);
4865 }
4866
4867 hidden_lookup = GetHiddenPropertiesHashTable(CREATE_NEW_IF_ABSENT);
4868 ObjectHashTable* hashtable;
4869 if (!hidden_lookup->To(&hashtable)) return hidden_lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004870
4871 // If it was found, check if the key is already in the dictionary.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004872 MaybeObject* insert_result = hashtable->Put(key, value);
4873 ObjectHashTable* new_table;
4874 if (!insert_result->To(&new_table)) return insert_result;
4875 if (new_table != hashtable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004876 // If adding the key expanded the dictionary (i.e., Add returned a new
4877 // dictionary), store it back to the object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004878 MaybeObject* store_result = SetHiddenPropertiesHashTable(new_table);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004879 if (store_result->IsFailure()) return store_result;
4880 }
4881 // Return this to mark success.
4882 return this;
4883}
4884
4885
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004886void JSObject::DeleteHiddenProperty(Handle<JSObject> object, Handle<Name> key) {
4887 Isolate* isolate = object->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00004888 ASSERT(key->IsUniqueName());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004889
4890 if (object->IsJSGlobalProxy()) {
4891 Handle<Object> proto(object->GetPrototype(), isolate);
4892 if (proto->IsNull()) return;
4893 ASSERT(proto->IsJSGlobalObject());
4894 return DeleteHiddenProperty(Handle<JSObject>::cast(proto), key);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004895 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004896
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004897 MaybeObject* hidden_lookup =
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004898 object->GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004899 Object* inline_value = hidden_lookup->ToObjectUnchecked();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004900
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004901 // We never delete (inline-stored) identity hashes.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004902 ASSERT(*key != isolate->heap()->identity_hash_string());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004903 if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
4904
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00004905 Handle<ObjectHashTable> hashtable(ObjectHashTable::cast(inline_value));
4906 PutIntoObjectHashTable(hashtable, key, isolate->factory()->the_hole_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004907}
4908
4909
4910bool JSObject::HasHiddenProperties() {
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00004911 return GetPropertyAttributePostInterceptor(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004912 GetHeap()->hidden_string(),
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00004913 false) != ABSENT;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004914}
4915
4916
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004917MaybeObject* JSObject::GetHiddenPropertiesHashTable(
4918 InitializeHiddenProperties init_option) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004919 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004920 Object* inline_value;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004921 if (HasFastProperties()) {
4922 // If the object has fast properties, check whether the first slot
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004923 // in the descriptor array matches the hidden string. Since the
ulan@chromium.org750145a2013-03-07 15:14:13 +00004924 // hidden strings hash code is zero (and no other name has hash
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004925 // code zero) it will always occupy the first entry if present.
4926 DescriptorArray* descriptors = this->map()->instance_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004927 if (descriptors->number_of_descriptors() > 0) {
4928 int sorted_index = descriptors->GetSortedKeyIndex(0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004929 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004930 sorted_index < map()->NumberOfOwnDescriptors()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004931 ASSERT(descriptors->GetType(sorted_index) == FIELD);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004932 MaybeObject* maybe_value = this->FastPropertyAt(
4933 descriptors->GetDetails(sorted_index).representation(),
4934 descriptors->GetFieldIndex(sorted_index));
4935 if (!maybe_value->To(&inline_value)) return maybe_value;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004936 } else {
4937 inline_value = GetHeap()->undefined_value();
4938 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004939 } else {
4940 inline_value = GetHeap()->undefined_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004941 }
4942 } else {
4943 PropertyAttributes attributes;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004944 // You can't install a getter on a property indexed by the hidden string,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004945 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
4946 // object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004947 inline_value =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004948 GetLocalPropertyPostInterceptor(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004949 GetHeap()->hidden_string(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004950 &attributes)->ToObjectUnchecked();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004951 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004952
4953 if (init_option == ONLY_RETURN_INLINE_VALUE ||
4954 inline_value->IsHashTable()) {
4955 return inline_value;
4956 }
4957
4958 ObjectHashTable* hashtable;
4959 static const int kInitialCapacity = 4;
4960 MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004961 ObjectHashTable::Allocate(GetHeap(),
4962 kInitialCapacity,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004963 ObjectHashTable::USE_CUSTOM_MINIMUM_CAPACITY);
4964 if (!maybe_obj->To<ObjectHashTable>(&hashtable)) return maybe_obj;
4965
4966 if (inline_value->IsSmi()) {
4967 // We were storing the identity hash inline and now allocated an actual
4968 // dictionary. Put the identity hash into the new dictionary.
4969 MaybeObject* insert_result =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004970 hashtable->Put(GetHeap()->identity_hash_string(), inline_value);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004971 ObjectHashTable* new_table;
4972 if (!insert_result->To(&new_table)) return insert_result;
4973 // We expect no resizing for the first insert.
4974 ASSERT_EQ(hashtable, new_table);
4975 }
4976
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00004977 MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline(
4978 GetHeap()->hidden_string(),
4979 hashtable,
4980 DONT_ENUM,
4981 OPTIMAL_REPRESENTATION,
4982 ALLOW_AS_CONSTANT,
4983 OMIT_EXTENSIBILITY_CHECK);
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00004984 if (store_result->IsFailure()) return store_result;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004985 return hashtable;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004986}
4987
4988
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004989MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004990 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004991 // We can store the identity hash inline iff there is no backing store
4992 // for hidden properties yet.
4993 ASSERT(HasHiddenProperties() != value->IsSmi());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004994 if (HasFastProperties()) {
4995 // If the object has fast properties, check whether the first slot
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004996 // in the descriptor array matches the hidden string. Since the
ulan@chromium.org750145a2013-03-07 15:14:13 +00004997 // hidden strings hash code is zero (and no other name has hash
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004998 // code zero) it will always occupy the first entry if present.
4999 DescriptorArray* descriptors = this->map()->instance_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005000 if (descriptors->number_of_descriptors() > 0) {
5001 int sorted_index = descriptors->GetSortedKeyIndex(0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00005002 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005003 sorted_index < map()->NumberOfOwnDescriptors()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005004 ASSERT(descriptors->GetType(sorted_index) == FIELD);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005005 FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005006 return this;
5007 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005008 }
5009 }
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00005010 MaybeObject* store_result = SetLocalPropertyIgnoreAttributesTrampoline(
5011 GetHeap()->hidden_string(),
5012 value,
5013 DONT_ENUM,
5014 OPTIMAL_REPRESENTATION,
5015 ALLOW_AS_CONSTANT,
5016 OMIT_EXTENSIBILITY_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005017 if (store_result->IsFailure()) return store_result;
5018 return this;
5019}
5020
5021
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005022Handle<Object> JSObject::DeletePropertyPostInterceptor(Handle<JSObject> object,
5023 Handle<Name> name,
5024 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005025 // Check local property, ignore interceptor.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005026 Isolate* isolate = object->GetIsolate();
5027 LookupResult result(isolate);
5028 object->LocalLookupRealNamedProperty(*name, &result);
5029 if (!result.IsFound()) return isolate->factory()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005030
5031 // Normalize object if needed.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005032 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005033
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005034 return DeleteNormalizedProperty(object, name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005035}
5036
5037
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005038Handle<Object> JSObject::DeletePropertyWithInterceptor(Handle<JSObject> object,
5039 Handle<Name> name) {
5040 Isolate* isolate = object->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005041
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005042 // TODO(rossberg): Support symbols in the API.
5043 if (name->IsSymbol()) return isolate->factory()->false_value();
5044
5045 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005046 if (!interceptor->deleter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +00005047 v8::NamedPropertyDeleterCallback deleter =
5048 v8::ToCData<v8::NamedPropertyDeleterCallback>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 LOG(isolate,
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005050 ApiNamedPropertyAccess("interceptor-named-delete", *object, *name));
5051 PropertyCallbackArguments args(
5052 isolate, interceptor->data(), *object, *object);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00005053 v8::Handle<v8::Boolean> result =
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005054 args.Call(deleter, v8::Utils::ToLocal(Handle<String>::cast(name)));
5055 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005056 if (!result.IsEmpty()) {
5057 ASSERT(result->IsBoolean());
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00005058 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5059 result_internal->VerifyApiCallResultType();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005060 // Rebox CustomArguments::kReturnValueOffset before returning.
5061 return handle(*result_internal, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005062 }
5063 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005064 Handle<Object> result =
5065 DeletePropertyPostInterceptor(object, name, NORMAL_DELETION);
5066 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5067 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005068}
5069
5070
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005071// TODO(mstarzinger): Temporary wrapper until handlified.
5072static Handle<Object> AccessorDelete(Handle<JSObject> object,
5073 uint32_t index,
5074 JSObject::DeleteMode mode) {
5075 CALL_HEAP_FUNCTION(object->GetIsolate(),
5076 object->GetElementsAccessor()->Delete(*object,
5077 index,
5078 mode),
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005079 Object);
5080}
5081
5082
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005083Handle<Object> JSObject::DeleteElementWithInterceptor(Handle<JSObject> object,
5084 uint32_t index) {
5085 Isolate* isolate = object->GetIsolate();
5086 Factory* factory = isolate->factory();
5087
5088 // Make sure that the top context does not change when doing
5089 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00005090 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005091
5092 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor());
5093 if (interceptor->deleter()->IsUndefined()) return factory->false_value();
5094 v8::IndexedPropertyDeleterCallback deleter =
5095 v8::ToCData<v8::IndexedPropertyDeleterCallback>(interceptor->deleter());
5096 LOG(isolate,
5097 ApiIndexedPropertyAccess("interceptor-indexed-delete", *object, index));
5098 PropertyCallbackArguments args(
5099 isolate, interceptor->data(), *object, *object);
5100 v8::Handle<v8::Boolean> result = args.Call(deleter, index);
5101 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5102 if (!result.IsEmpty()) {
5103 ASSERT(result->IsBoolean());
5104 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
5105 result_internal->VerifyApiCallResultType();
5106 // Rebox CustomArguments::kReturnValueOffset before returning.
5107 return handle(*result_internal, isolate);
5108 }
5109 Handle<Object> delete_result = AccessorDelete(object, index, NORMAL_DELETION);
5110 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5111 return delete_result;
5112}
5113
5114
5115Handle<Object> JSObject::DeleteElement(Handle<JSObject> object,
5116 uint32_t index,
5117 DeleteMode mode) {
5118 Isolate* isolate = object->GetIsolate();
5119 Factory* factory = isolate->factory();
5120
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005121 // Check access rights if needed.
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005122 if (object->IsAccessCheckNeeded() &&
5123 !isolate->MayIndexedAccess(*object, index, v8::ACCESS_DELETE)) {
5124 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_DELETE);
5125 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5126 return factory->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005127 }
5128
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005129 if (object->IsStringObjectWithCharacterAt(index)) {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005130 if (mode == STRICT_DELETION) {
5131 // Deleting a non-configurable property in strict mode.
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005132 Handle<Object> name = factory->NewNumberFromUint(index);
5133 Handle<Object> args[2] = { name, object };
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005134 Handle<Object> error =
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005135 factory->NewTypeError("strict_delete_property",
5136 HandleVector(args, 2));
5137 isolate->Throw(*error);
5138 return Handle<Object>();
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005139 }
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005140 return factory->false_value();
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00005141 }
5142
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005143 if (object->IsJSGlobalProxy()) {
5144 Handle<Object> proto(object->GetPrototype(), isolate);
5145 if (proto->IsNull()) return factory->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005146 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005147 return DeleteElement(Handle<JSObject>::cast(proto), index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005148 }
5149
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005150 Handle<Object> old_value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005151 bool should_enqueue_change_record = false;
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005152 if (FLAG_harmony_observation && object->map()->is_observed()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005153 should_enqueue_change_record = HasLocalElement(object, index);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005154 if (should_enqueue_change_record) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005155 old_value = object->GetLocalElementAccessorPair(index) != NULL
5156 ? Handle<Object>::cast(factory->the_hole_value())
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00005157 : Object::GetElement(isolate, object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005158 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005159 }
5160
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005161 // Skip interceptor if forcing deletion.
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005162 Handle<Object> result;
5163 if (object->HasIndexedInterceptor() && mode != FORCE_DELETION) {
5164 result = DeleteElementWithInterceptor(object, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005165 } else {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005166 result = AccessorDelete(object, index, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005167 }
5168
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005169 if (should_enqueue_change_record && !HasLocalElement(object, index)) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005170 Handle<String> name = factory->Uint32ToString(index);
5171 EnqueueChangeRecord(object, "deleted", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005172 }
5173
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00005174 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175}
5176
5177
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005178Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
5179 Handle<Name> name,
5180 DeleteMode mode) {
5181 Isolate* isolate = object->GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005182 // ECMA-262, 3rd, 8.6.2.5
ulan@chromium.org750145a2013-03-07 15:14:13 +00005183 ASSERT(name->IsName());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005185 // Check access rights if needed.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005186 if (object->IsAccessCheckNeeded() &&
5187 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_DELETE)) {
5188 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_DELETE);
5189 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5190 return isolate->factory()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005191 }
5192
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005193 if (object->IsJSGlobalProxy()) {
5194 Object* proto = object->GetPrototype();
5195 if (proto->IsNull()) return isolate->factory()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005196 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005197 return JSGlobalObject::DeleteProperty(
5198 handle(JSGlobalObject::cast(proto)), name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005199 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005201 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 if (name->AsArrayIndex(&index)) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005203 return DeleteElement(object, index, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005204 }
5205
5206 LookupResult lookup(isolate);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005207 object->LocalLookup(*name, &lookup, true);
5208 if (!lookup.IsFound()) return isolate->factory()->true_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005209 // Ignore attributes if forcing a deletion.
5210 if (lookup.IsDontDelete() && mode != FORCE_DELETION) {
5211 if (mode == STRICT_DELETION) {
5212 // Deleting a non-configurable property in strict mode.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005213 Handle<Object> args[2] = { name, object };
5214 Handle<Object> error = isolate->factory()->NewTypeError(
5215 "strict_delete_property", HandleVector(args, ARRAY_SIZE(args)));
5216 isolate->Throw(*error);
5217 return Handle<Object>();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005218 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005219 return isolate->factory()->false_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005220 }
5221
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005222 Handle<Object> old_value = isolate->factory()->the_hole_value();
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005223 bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005224 if (is_observed && lookup.IsDataProperty()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005225 old_value = Object::GetProperty(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005226 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005227 Handle<Object> result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005228
5229 // Check for interceptor.
5230 if (lookup.IsInterceptor()) {
5231 // Skip interceptor if forcing a deletion.
5232 if (mode == FORCE_DELETION) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005233 result = DeletePropertyPostInterceptor(object, name, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005234 } else {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005235 result = DeletePropertyWithInterceptor(object, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005236 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005237 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005238 // Normalize object if needed.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005239 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 // Make sure the properties are normalized before removing the entry.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005241 result = DeleteNormalizedProperty(object, name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005243
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005244 if (is_observed && !HasLocalProperty(object, name)) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005245 EnqueueChangeRecord(object, "deleted", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005246 }
5247
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005248 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005249}
5250
5251
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005252Handle<Object> JSReceiver::DeleteElement(Handle<JSReceiver> object,
5253 uint32_t index,
5254 DeleteMode mode) {
5255 if (object->IsJSProxy()) {
5256 return JSProxy::DeleteElementWithHandler(
5257 Handle<JSProxy>::cast(object), index, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005258 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005259 return JSObject::DeleteElement(Handle<JSObject>::cast(object), index, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005260}
5261
5262
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005263Handle<Object> JSReceiver::DeleteProperty(Handle<JSReceiver> object,
5264 Handle<Name> name,
5265 DeleteMode mode) {
5266 if (object->IsJSProxy()) {
5267 return JSProxy::DeletePropertyWithHandler(
5268 Handle<JSProxy>::cast(object), name, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005269 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00005270 return JSObject::DeleteProperty(Handle<JSObject>::cast(object), name, mode);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005271}
5272
5273
whesse@chromium.org7b260152011-06-20 15:33:18 +00005274bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5275 ElementsKind kind,
5276 Object* object) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005277 ASSERT(IsFastObjectElementsKind(kind) ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005278 kind == DICTIONARY_ELEMENTS);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005279 if (IsFastObjectElementsKind(kind)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005280 int length = IsJSArray()
5281 ? Smi::cast(JSArray::cast(this)->length())->value()
5282 : elements->length();
5283 for (int i = 0; i < length; ++i) {
5284 Object* element = elements->get(i);
5285 if (!element->IsTheHole() && element == object) return true;
5286 }
5287 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005288 Object* key =
5289 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00005290 if (!key->IsUndefined()) return true;
5291 }
5292 return false;
5293}
5294
5295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005296// Check whether this object references another object.
5297bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005298 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005299 Heap* heap = GetHeap();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00005300 DisallowHeapAllocation no_allocation;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005301
5302 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005303 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005304 return true;
5305 }
5306
5307 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005308 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005309 return true;
5310 }
5311
5312 // Check if the object is among the named properties.
5313 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005314 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 return true;
5316 }
5317
5318 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00005319 ElementsKind kind = GetElementsKind();
5320 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005321 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00005322 case EXTERNAL_BYTE_ELEMENTS:
5323 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5324 case EXTERNAL_SHORT_ELEMENTS:
5325 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5326 case EXTERNAL_INT_ELEMENTS:
5327 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5328 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005329 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00005330 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005331 case FAST_HOLEY_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00005332 // Raw pixels and external arrays do not reference other
5333 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005334 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005335 case FAST_SMI_ELEMENTS:
5336 case FAST_HOLEY_SMI_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005337 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005338 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005339 case FAST_HOLEY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005340 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005341 FixedArray* elements = FixedArray::cast(this->elements());
5342 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005343 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00005345 case NON_STRICT_ARGUMENTS_ELEMENTS: {
5346 FixedArray* parameter_map = FixedArray::cast(elements());
5347 // Check the mapped parameters.
5348 int length = parameter_map->length();
5349 for (int i = 2; i < length; ++i) {
5350 Object* value = parameter_map->get(i);
5351 if (!value->IsTheHole() && value == obj) return true;
5352 }
5353 // Check the arguments.
5354 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005355 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5356 FAST_HOLEY_ELEMENTS;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005357 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005358 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 }
5361
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005362 // For functions check the context.
5363 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005364 // Get the constructor function for arguments array.
5365 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005366 heap->isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005367 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005368 JSFunction* arguments_function =
5369 JSFunction::cast(arguments_boilerplate->map()->constructor());
5370
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005371 // Get the context and don't check if it is the native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005372 JSFunction* f = JSFunction::cast(this);
5373 Context* context = f->context();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005374 if (context->IsNativeContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005375 return false;
5376 }
5377
5378 // Check the non-special context slots.
5379 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5380 // Only check JS objects.
5381 if (context->get(i)->IsJSObject()) {
5382 JSObject* ctxobj = JSObject::cast(context->get(i));
5383 // If it is an arguments array check the content.
5384 if (ctxobj->map()->constructor() == arguments_function) {
5385 if (ctxobj->ReferencesObject(obj)) {
5386 return true;
5387 }
5388 } else if (ctxobj == obj) {
5389 return true;
5390 }
5391 }
5392 }
5393
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005394 // Check the context extension (if any) if it can have references.
5395 if (context->has_extension() && !context->IsCatchContext()) {
5396 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 }
5398 }
5399
5400 // No references to object.
5401 return false;
5402}
5403
5404
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005405Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005406 Isolate* isolate = object->GetIsolate();
5407 if (object->IsAccessCheckNeeded() &&
5408 !isolate->MayNamedAccess(*object,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409 isolate->heap()->undefined_value(),
5410 v8::ACCESS_KEYS)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005411 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5412 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5413 return isolate->factory()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005414 }
5415
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005416 if (object->IsJSGlobalProxy()) {
5417 Handle<Object> proto(object->GetPrototype(), isolate);
5418 if (proto->IsNull()) return object;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005419 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005420 return PreventExtensions(Handle<JSObject>::cast(proto));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005421 }
5422
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005423 // It's not possible to seal objects with external array elements
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005424 if (object->HasExternalArrayElements()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005425 Handle<Object> error =
5426 isolate->factory()->NewTypeError(
5427 "cant_prevent_ext_external_array_elements",
5428 HandleVector(&object, 1));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005429 isolate->Throw(*error);
5430 return Handle<Object>();
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005431 }
5432
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005433 // If there are fast elements we normalize.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005434 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
5435 ASSERT(object->HasDictionaryElements() ||
5436 object->HasDictionaryArgumentsElements());
5437
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005438 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005439 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005440
5441 // Do a map transition, other objects with this map may still
5442 // be extensible.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005443 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005444 Handle<Map> new_map = Map::Copy(handle(object->map()));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005445
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005446 new_map->set_is_extensible(false);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005447 object->set_map(*new_map);
5448 ASSERT(!object->map()->is_extensible());
5449 return object;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005450}
5451
5452
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005453template<typename Dictionary>
5454static void FreezeDictionary(Dictionary* dictionary) {
5455 int capacity = dictionary->Capacity();
5456 for (int i = 0; i < capacity; i++) {
5457 Object* k = dictionary->KeyAt(i);
5458 if (dictionary->IsKey(k)) {
5459 PropertyDetails details = dictionary->DetailsAt(i);
5460 int attrs = DONT_DELETE;
5461 // READ_ONLY is an invalid attribute for JS setters/getters.
5462 if (details.type() != CALLBACKS ||
5463 !dictionary->ValueAt(i)->IsAccessorPair()) {
5464 attrs |= READ_ONLY;
5465 }
5466 details = details.CopyAddAttributes(
5467 static_cast<PropertyAttributes>(attrs));
5468 dictionary->DetailsAtPut(i, details);
5469 }
5470 }
5471}
5472
5473
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005474Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005475 // Freezing non-strict arguments should be handled elsewhere.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005476 ASSERT(!object->HasNonStrictArgumentsElements());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005477
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005478 if (object->map()->is_frozen()) return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005479
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005480 Isolate* isolate = object->GetIsolate();
5481 if (object->IsAccessCheckNeeded() &&
5482 !isolate->MayNamedAccess(*object,
5483 isolate->heap()->undefined_value(),
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005484 v8::ACCESS_KEYS)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005485 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5486 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
5487 return isolate->factory()->false_value();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005488 }
5489
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005490 if (object->IsJSGlobalProxy()) {
5491 Handle<Object> proto(object->GetPrototype(), isolate);
5492 if (proto->IsNull()) return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005493 ASSERT(proto->IsJSGlobalObject());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005494 return Freeze(Handle<JSObject>::cast(proto));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005495 }
5496
5497 // It's not possible to freeze objects with external array elements
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005498 if (object->HasExternalArrayElements()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005499 Handle<Object> error =
5500 isolate->factory()->NewTypeError(
5501 "cant_prevent_ext_external_array_elements",
5502 HandleVector(&object, 1));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005503 isolate->Throw(*error);
5504 return Handle<Object>();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005505 }
5506
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005507 Handle<SeededNumberDictionary> new_element_dictionary;
5508 if (!object->elements()->IsDictionary()) {
5509 int length = object->IsJSArray()
5510 ? Smi::cast(Handle<JSArray>::cast(object)->length())->value()
5511 : object->elements()->length();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005512 if (length > 0) {
5513 int capacity = 0;
5514 int used = 0;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005515 object->GetElementsCapacityAndUsage(&capacity, &used);
5516 new_element_dictionary =
5517 isolate->factory()->NewSeededNumberDictionary(used);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005518
5519 // Move elements to a dictionary; avoid calling NormalizeElements to avoid
5520 // unnecessary transitions.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005521 new_element_dictionary = CopyFastElementsToDictionary(
5522 handle(object->elements()), length, new_element_dictionary);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005523 } else {
5524 // No existing elements, use a pre-allocated empty backing store
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005525 new_element_dictionary =
5526 isolate->factory()->empty_slow_element_dictionary();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005527 }
5528 }
5529
5530 LookupResult result(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005531 Handle<Map> old_map(object->map());
5532 old_map->LookupTransition(*object, isolate->heap()->frozen_symbol(), &result);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005533 if (result.IsTransition()) {
5534 Map* transition_map = result.GetTransitionTarget();
5535 ASSERT(transition_map->has_dictionary_elements());
5536 ASSERT(transition_map->is_frozen());
5537 ASSERT(!transition_map->is_extensible());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005538 object->set_map(transition_map);
5539 } else if (object->HasFastProperties() && old_map->CanHaveMoreTransitions()) {
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005540 // Create a new descriptor array with fully-frozen properties
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005541 int num_descriptors = old_map->NumberOfOwnDescriptors();
5542 Handle<DescriptorArray> new_descriptors =
5543 DescriptorArray::CopyUpToAddAttributes(
5544 handle(old_map->instance_descriptors()), num_descriptors, FROZEN);
5545 Handle<Map> new_map = Map::CopyReplaceDescriptors(
5546 old_map, new_descriptors, INSERT_TRANSITION,
5547 isolate->factory()->frozen_symbol());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005548 new_map->freeze();
5549 new_map->set_is_extensible(false);
5550 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005551 object->set_map(*new_map);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005552 } else {
5553 // Slow path: need to normalize properties for safety
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005554 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005555
5556 // Create a new map, since other objects with this map may be extensible.
5557 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005558 Handle<Map> new_map = Map::Copy(handle(object->map()));
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005559 new_map->freeze();
5560 new_map->set_is_extensible(false);
5561 new_map->set_elements_kind(DICTIONARY_ELEMENTS);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005562 object->set_map(*new_map);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005563
5564 // Freeze dictionary-mode properties
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005565 FreezeDictionary(object->property_dictionary());
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005566 }
5567
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005568 ASSERT(object->map()->has_dictionary_elements());
5569 if (!new_element_dictionary.is_null()) {
5570 object->set_elements(*new_element_dictionary);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005571 }
5572
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005573 if (object->elements() != isolate->heap()->empty_slow_element_dictionary()) {
5574 SeededNumberDictionary* dictionary = object->element_dictionary();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005575 // Make sure we never go back to the fast case
5576 dictionary->set_requires_slow_elements();
5577 // Freeze all elements in the dictionary
5578 FreezeDictionary(dictionary);
5579 }
5580
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005581 return object;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00005582}
5583
5584
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005585void JSObject::SetObserved(Handle<JSObject> object) {
5586 Isolate* isolate = object->GetIsolate();
danno@chromium.org169691d2013-07-15 08:01:13 +00005587
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005588 if (object->map()->is_observed())
5589 return;
danno@chromium.org169691d2013-07-15 08:01:13 +00005590
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005591 if (!object->HasExternalArrayElements()) {
danno@chromium.org169691d2013-07-15 08:01:13 +00005592 // Go to dictionary mode, so that we don't skip map checks.
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005593 NormalizeElements(object);
5594 ASSERT(!object->HasFastElements());
danno@chromium.org169691d2013-07-15 08:01:13 +00005595 }
5596
5597 LookupResult result(isolate);
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005598 object->map()->LookupTransition(*object,
5599 isolate->heap()->observed_symbol(),
5600 &result);
danno@chromium.org169691d2013-07-15 08:01:13 +00005601
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005602 Handle<Map> new_map;
danno@chromium.org169691d2013-07-15 08:01:13 +00005603 if (result.IsTransition()) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005604 new_map = handle(result.GetTransitionTarget());
danno@chromium.org169691d2013-07-15 08:01:13 +00005605 ASSERT(new_map->is_observed());
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005606 } else if (object->map()->CanHaveMoreTransitions()) {
5607 new_map = Map::CopyForObserved(handle(object->map()));
danno@chromium.org169691d2013-07-15 08:01:13 +00005608 } else {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005609 new_map = Map::Copy(handle(object->map()));
danno@chromium.org169691d2013-07-15 08:01:13 +00005610 new_map->set_is_observed(true);
5611 }
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005612 object->set_map(*new_map);
5613}
danno@chromium.org169691d2013-07-15 08:01:13 +00005614
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005615
5616Handle<JSObject> JSObject::Copy(Handle<JSObject> object,
5617 Handle<AllocationSite> site) {
5618 Isolate* isolate = object->GetIsolate();
5619 CALL_HEAP_FUNCTION(isolate,
5620 isolate->heap()->CopyJSObject(*object, *site), JSObject);
danno@chromium.org169691d2013-07-15 08:01:13 +00005621}
5622
5623
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005624Handle<JSObject> JSObject::Copy(Handle<JSObject> object) {
5625 Isolate* isolate = object->GetIsolate();
5626 CALL_HEAP_FUNCTION(isolate,
5627 isolate->heap()->CopyJSObject(*object), JSObject);
5628}
5629
5630
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005631class JSObjectWalkVisitor {
5632 public:
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005633 explicit JSObjectWalkVisitor(AllocationSiteContext* site_context) :
5634 site_context_(site_context) {}
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005635 virtual ~JSObjectWalkVisitor() {}
5636
5637 Handle<JSObject> Visit(Handle<JSObject> object) {
5638 return StructureWalk(object);
5639 }
5640
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005641 virtual bool is_copying() = 0;
5642
5643 protected:
5644 Handle<JSObject> StructureWalk(Handle<JSObject> object);
5645
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005646 // The returned handle will be used for the object in all subsequent usages.
5647 // This allows VisitObject to make a copy of the object if desired.
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005648 virtual Handle<JSObject> VisitObject(Handle<JSObject> object) = 0;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005649 virtual Handle<JSObject> VisitElementOrProperty(Handle<JSObject> object,
5650 Handle<JSObject> value) = 0;
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005651
5652 AllocationSiteContext* site_context() { return site_context_; }
5653
5654 private:
5655 AllocationSiteContext* site_context_;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005656};
5657
5658
5659class JSObjectCopyVisitor: public JSObjectWalkVisitor {
5660 public:
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005661 explicit JSObjectCopyVisitor(AllocationSiteContext* site_context)
5662 : JSObjectWalkVisitor(site_context) {}
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005663
5664 virtual bool is_copying() V8_OVERRIDE { return true; }
5665
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005666 // The returned handle will be used for the object in all
5667 // subsequent usages. This allows VisitObject to make a copy
5668 // of the object if desired.
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005669 virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005670 // Only create a memento if
5671 // 1) we have a JSArray, and
5672 // 2) the elements kind is palatable
5673 // 3) allow_mementos is true
5674 Handle<JSObject> copy;
5675 if (site_context()->activated() &&
5676 AllocationSite::CanTrack(object->map()->instance_type()) &&
5677 AllocationSite::GetMode(object->GetElementsKind()) ==
5678 TRACK_ALLOCATION_SITE) {
5679 copy = JSObject::Copy(object, site_context()->current());
5680 } else {
5681 copy = JSObject::Copy(object);
5682 }
5683
5684 return copy;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005685 }
5686
5687 virtual Handle<JSObject> VisitElementOrProperty(
5688 Handle<JSObject> object,
5689 Handle<JSObject> value) V8_OVERRIDE {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005690 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5691 Handle<JSObject> copy_of_value = StructureWalk(value);
5692 site_context()->ExitScope(current_site, value);
5693 return copy_of_value;
5694 }
5695};
5696
5697
5698class JSObjectCreateAllocationSitesVisitor: public JSObjectWalkVisitor {
5699 public:
5700 explicit JSObjectCreateAllocationSitesVisitor(
5701 AllocationSiteContext* site_context)
5702 : JSObjectWalkVisitor(site_context) {}
5703
5704 virtual bool is_copying() V8_OVERRIDE { return false; }
5705
5706 // The returned handle will be used for the object in all
5707 // subsequent usages. This allows VisitObject to make a copy
5708 // of the object if desired.
5709 virtual Handle<JSObject> VisitObject(Handle<JSObject> object) V8_OVERRIDE {
5710 return object;
5711 }
5712
5713 virtual Handle<JSObject> VisitElementOrProperty(
5714 Handle<JSObject> object,
5715 Handle<JSObject> value) V8_OVERRIDE {
5716 Handle<AllocationSite> current_site = site_context()->EnterNewScope();
5717 value = StructureWalk(value);
5718 site_context()->ExitScope(current_site, value);
5719 return value;
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005720 }
5721};
5722
5723
5724Handle<JSObject> JSObjectWalkVisitor::StructureWalk(Handle<JSObject> object) {
5725 bool copying = is_copying();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005726 Isolate* isolate = object->GetIsolate();
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00005727 StackLimitCheck check(isolate);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005728 if (check.HasOverflowed()) {
5729 isolate->StackOverflow();
5730 return Handle<JSObject>::null();
mvstanton@chromium.org5a4733b2013-09-16 07:33:24 +00005731 }
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00005732
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005733 if (object->map()->is_deprecated()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005734 JSObject::MigrateInstance(object);
hpayer@chromium.org4f626d12013-09-18 07:47:45 +00005735 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005736
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005737 Handle<JSObject> copy = VisitObject(object);
5738 ASSERT(copying || copy.is_identical_to(object));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005739
5740 HandleScope scope(isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005741
5742 // Deep copy local properties.
5743 if (copy->HasFastProperties()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005744 Handle<DescriptorArray> descriptors(copy->map()->instance_descriptors());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005745 int limit = copy->map()->NumberOfOwnDescriptors();
5746 for (int i = 0; i < limit; i++) {
5747 PropertyDetails details = descriptors->GetDetails(i);
5748 if (details.type() != FIELD) continue;
5749 int index = descriptors->GetFieldIndex(i);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005750 Handle<Object> value(object->RawFastPropertyAt(index), isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005751 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005752 value = VisitElementOrProperty(copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005753 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, value, Handle<JSObject>());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005754 } else {
5755 Representation representation = details.representation();
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005756 value = NewStorageFor(isolate, value, representation);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005757 }
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005758 if (copying) {
5759 copy->FastPropertyAtPut(index, *value);
5760 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005761 }
5762 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005763 Handle<FixedArray> names =
5764 isolate->factory()->NewFixedArray(copy->NumberOfLocalProperties());
5765 copy->GetLocalPropertyNames(*names, 0);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005766 for (int i = 0; i < names->length(); i++) {
5767 ASSERT(names->get(i)->IsString());
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005768 Handle<String> key_string(String::cast(names->get(i)));
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005769 PropertyAttributes attributes =
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005770 copy->GetLocalPropertyAttribute(*key_string);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005771 // Only deep copy fields from the object literal expression.
5772 // In particular, don't try to copy the length attribute of
5773 // an array.
5774 if (attributes != NONE) continue;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005775 Handle<Object> value(
5776 copy->GetProperty(*key_string, &attributes)->ToObjectUnchecked(),
5777 isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005778 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005779 Handle<JSObject> result = VisitElementOrProperty(
5780 copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005781 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005782 if (copying) {
5783 // Creating object copy for literals. No strict mode needed.
5784 CHECK_NOT_EMPTY_HANDLE(isolate, JSObject::SetProperty(
5785 copy, key_string, result, NONE, kNonStrictMode));
5786 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005787 }
5788 }
5789 }
5790
5791 // Deep copy local elements.
5792 // Pixel elements cannot be created using an object literal.
5793 ASSERT(!copy->HasExternalArrayElements());
5794 switch (copy->GetElementsKind()) {
5795 case FAST_SMI_ELEMENTS:
5796 case FAST_ELEMENTS:
5797 case FAST_HOLEY_SMI_ELEMENTS:
5798 case FAST_HOLEY_ELEMENTS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005799 Handle<FixedArray> elements(FixedArray::cast(copy->elements()));
5800 if (elements->map() == isolate->heap()->fixed_cow_array_map()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005801 isolate->counters()->cow_arrays_created_runtime()->Increment();
5802#ifdef DEBUG
5803 for (int i = 0; i < elements->length(); i++) {
5804 ASSERT(!elements->get(i)->IsJSObject());
5805 }
5806#endif
5807 } else {
5808 for (int i = 0; i < elements->length(); i++) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005809 Handle<Object> value(elements->get(i), isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005810 ASSERT(value->IsSmi() ||
5811 value->IsTheHole() ||
5812 (IsFastObjectElementsKind(copy->GetElementsKind())));
5813 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005814 Handle<JSObject> result = VisitElementOrProperty(
5815 copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005816 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005817 if (copying) {
5818 elements->set(i, *result);
5819 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005820 }
5821 }
5822 }
5823 break;
5824 }
5825 case DICTIONARY_ELEMENTS: {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005826 Handle<SeededNumberDictionary> element_dictionary(
5827 copy->element_dictionary());
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005828 int capacity = element_dictionary->Capacity();
5829 for (int i = 0; i < capacity; i++) {
5830 Object* k = element_dictionary->KeyAt(i);
5831 if (element_dictionary->IsKey(k)) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005832 Handle<Object> value(element_dictionary->ValueAt(i), isolate);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005833 if (value->IsJSObject()) {
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005834 Handle<JSObject> result = VisitElementOrProperty(
5835 copy, Handle<JSObject>::cast(value));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00005836 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, result, Handle<JSObject>());
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005837 if (copying) {
5838 element_dictionary->ValueAtPut(i, *result);
5839 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005840 }
5841 }
5842 }
5843 break;
5844 }
5845 case NON_STRICT_ARGUMENTS_ELEMENTS:
5846 UNIMPLEMENTED();
5847 break;
5848 case EXTERNAL_PIXEL_ELEMENTS:
5849 case EXTERNAL_BYTE_ELEMENTS:
5850 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5851 case EXTERNAL_SHORT_ELEMENTS:
5852 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5853 case EXTERNAL_INT_ELEMENTS:
5854 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5855 case EXTERNAL_FLOAT_ELEMENTS:
5856 case EXTERNAL_DOUBLE_ELEMENTS:
5857 case FAST_DOUBLE_ELEMENTS:
5858 case FAST_HOLEY_DOUBLE_ELEMENTS:
5859 // No contained objects, nothing to do.
5860 break;
5861 }
5862 return copy;
5863}
5864
5865
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00005866Handle<JSObject> JSObject::DeepWalk(Handle<JSObject> object,
5867 AllocationSiteContext* site_context) {
5868 JSObjectCreateAllocationSitesVisitor v(site_context);
5869 Handle<JSObject> result = v.Visit(object);
5870 ASSERT(!v.is_copying() &&
5871 (result.is_null() || result.is_identical_to(object)));
5872 return result;
5873}
5874
5875
5876Handle<JSObject> JSObject::DeepCopy(Handle<JSObject> object,
5877 AllocationSiteContext* site_context) {
5878 JSObjectCopyVisitor v(site_context);
jkummerow@chromium.orgc3669762013-09-30 13:42:25 +00005879 Handle<JSObject> copy = v.Visit(object);
5880 ASSERT(v.is_copying() && !copy.is_identical_to(object));
5881 return copy;
5882}
5883
5884
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005885// Tests for the fast common case for property enumeration:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005886// - This object and all prototypes has an enum cache (which means that
5887// it is no proxy, has no interceptors and needs no access checks).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005888// - This object has no elements.
5889// - No prototype has enumerable properties/elements.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005890bool JSReceiver::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005891 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005893 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005894 o = JSObject::cast(o)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005895 if (!o->IsJSObject()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005896 JSObject* curr = JSObject::cast(o);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005897 int enum_length = curr->map()->EnumLength();
5898 if (enum_length == Map::kInvalidEnumCache) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005899 ASSERT(!curr->HasNamedInterceptor());
5900 ASSERT(!curr->HasIndexedInterceptor());
5901 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005902 if (curr->NumberOfEnumElements() > 0) return false;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005903 if (curr != this && enum_length != 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904 }
5905 return true;
5906}
5907
5908
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005909int Map::NumberOfDescribedProperties(DescriptorFlag which,
5910 PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005912 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005913 int limit = which == ALL_DESCRIPTORS
5914 ? descs->number_of_descriptors()
5915 : NumberOfOwnDescriptors();
5916 for (int i = 0; i < limit; i++) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005917 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
5918 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
5919 result++;
5920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005921 }
5922 return result;
5923}
5924
5925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005927 int max_index = -1;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005928 int number_of_own_descriptors = NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005929 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005930 for (int i = 0; i < number_of_own_descriptors; i++) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005931 if (descs->GetType(i) == FIELD) {
5932 int current_index = descs->GetFieldIndex(i);
5933 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005934 }
5935 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005936 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005937}
5938
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939
ulan@chromium.org750145a2013-03-07 15:14:13 +00005940AccessorDescriptor* Map::FindAccessor(Name* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005941 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005942 int number_of_own_descriptors = NumberOfOwnDescriptors();
5943 for (int i = 0; i < number_of_own_descriptors; i++) {
5944 if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005945 return descs->GetCallbacks(i);
5946 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005947 }
5948 return NULL;
5949}
5950
5951
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005952void JSReceiver::LocalLookup(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005953 Name* name, LookupResult* result, bool search_hidden_prototypes) {
5954 ASSERT(name->IsName());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005955
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005956 Heap* heap = GetHeap();
5957
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005958 if (IsJSGlobalProxy()) {
5959 Object* proto = GetPrototype();
5960 if (proto->IsNull()) return result->NotFound();
5961 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005962 return JSReceiver::cast(proto)->LocalLookup(
5963 name, result, search_hidden_prototypes);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005964 }
5965
5966 if (IsJSProxy()) {
5967 result->HandlerResult(JSProxy::cast(this));
5968 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005969 }
5970
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005971 // Do not use inline caching if the object is a non-global object
5972 // that requires access checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005973 if (IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005974 result->DisallowCaching();
5975 }
5976
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005977 JSObject* js_object = JSObject::cast(this);
5978
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979 // Check for lookup interceptor except when bootstrapping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005980 if (js_object->HasNamedInterceptor() &&
5981 !heap->isolate()->bootstrapper()->IsActive()) {
5982 result->InterceptorResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 return;
5984 }
5985
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005986 js_object->LocalLookupRealNamedProperty(name, result);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005987 if (result->IsFound() || !search_hidden_prototypes) return;
5988
5989 Object* proto = js_object->GetPrototype();
5990 if (!proto->IsJSReceiver()) return;
5991 JSReceiver* receiver = JSReceiver::cast(proto);
5992 if (receiver->map()->is_hidden_prototype()) {
5993 receiver->LocalLookup(name, result, search_hidden_prototypes);
5994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995}
5996
5997
ulan@chromium.org750145a2013-03-07 15:14:13 +00005998void JSReceiver::Lookup(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005999 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006002 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006003 current = JSObject::cast(current)->GetPrototype()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006004 JSReceiver::cast(current)->LocalLookup(name, result, false);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006005 if (result->IsFound()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006006 }
6007 result->NotFound();
6008}
6009
6010
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006011// Search object and its prototype chain for callback properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006012void JSObject::LookupCallbackProperty(Name* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006013 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006014 for (Object* current = this;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006015 current != heap->null_value() && current->IsJSObject();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006016 current = JSObject::cast(current)->GetPrototype()) {
6017 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006018 if (result->IsPropertyCallbacks()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 }
6020 result->NotFound();
6021}
6022
6023
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006024// Try to update an accessor in an elements dictionary. Return true if the
6025// update succeeded, and false otherwise.
6026static bool UpdateGetterSetterInDictionary(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006027 SeededNumberDictionary* dictionary,
6028 uint32_t index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00006029 Object* getter,
6030 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006031 PropertyAttributes attributes) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00006032 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006033 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00006034 Object* result = dictionary->ValueAt(entry);
6035 PropertyDetails details = dictionary->DetailsAt(entry);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006036 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00006037 ASSERT(!details.IsDontDelete());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006038 if (details.attributes() != attributes) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00006039 dictionary->DetailsAtPut(
6040 entry,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006041 PropertyDetails(attributes, CALLBACKS, index));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006042 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00006043 AccessorPair::cast(result)->SetComponents(getter, setter);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006044 return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006045 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00006046 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006047 return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006048}
6049
6050
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006051void JSObject::DefineElementAccessor(Handle<JSObject> object,
6052 uint32_t index,
6053 Handle<Object> getter,
6054 Handle<Object> setter,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006055 PropertyAttributes attributes,
6056 v8::AccessControl access_control) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006057 switch (object->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006058 case FAST_SMI_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006059 case FAST_ELEMENTS:
6060 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006061 case FAST_HOLEY_SMI_ELEMENTS:
6062 case FAST_HOLEY_ELEMENTS:
6063 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006064 break;
6065 case EXTERNAL_PIXEL_ELEMENTS:
6066 case EXTERNAL_BYTE_ELEMENTS:
6067 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6068 case EXTERNAL_SHORT_ELEMENTS:
6069 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6070 case EXTERNAL_INT_ELEMENTS:
6071 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6072 case EXTERNAL_FLOAT_ELEMENTS:
6073 case EXTERNAL_DOUBLE_ELEMENTS:
6074 // Ignore getters and setters on pixel and external array elements.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006075 return;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006076 case DICTIONARY_ELEMENTS:
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006077 if (UpdateGetterSetterInDictionary(object->element_dictionary(),
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006078 index,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006079 *getter,
6080 *setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006081 attributes)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006082 return;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006083 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006084 break;
6085 case NON_STRICT_ARGUMENTS_ELEMENTS: {
6086 // Ascertain whether we have read-only properties or an existing
6087 // getter/setter pair in an arguments elements dictionary backing
6088 // store.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006089 FixedArray* parameter_map = FixedArray::cast(object->elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006090 uint32_t length = parameter_map->length();
6091 Object* probe =
6092 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
6093 if (probe == NULL || probe->IsTheHole()) {
6094 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
6095 if (arguments->IsDictionary()) {
6096 SeededNumberDictionary* dictionary =
6097 SeededNumberDictionary::cast(arguments);
6098 if (UpdateGetterSetterInDictionary(dictionary,
6099 index,
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006100 *getter,
6101 *setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006102 attributes)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006103 return;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006104 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006105 }
6106 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006107 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006108 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006109 }
6110
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006111 Isolate* isolate = object->GetIsolate();
6112 Handle<AccessorPair> accessors = isolate->factory()->NewAccessorPair();
6113 accessors->SetComponents(*getter, *setter);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006114 accessors->set_access_flags(access_control);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006115
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006116 SetElementCallback(object, index, accessors, attributes);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006117}
6118
6119
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006120Handle<AccessorPair> JSObject::CreateAccessorPairFor(Handle<JSObject> object,
6121 Handle<Name> name) {
6122 Isolate* isolate = object->GetIsolate();
6123 LookupResult result(isolate);
6124 object->LocalLookupRealNamedProperty(*name, &result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006125 if (result.IsPropertyCallbacks()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006126 // Note that the result can actually have IsDontDelete() == true when we
6127 // e.g. have to fall back to the slow case while adding a setter after
6128 // successfully reusing a map transition for a getter. Nevertheless, this is
6129 // OK, because the assertion only holds for the whole addition of both
6130 // accessors, not for the addition of each part. See first comment in
6131 // DefinePropertyAccessor below.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006132 Object* obj = result.GetCallbackObject();
6133 if (obj->IsAccessorPair()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006134 return AccessorPair::Copy(handle(AccessorPair::cast(obj), isolate));
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006135 }
6136 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006137 return isolate->factory()->NewAccessorPair();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00006138}
6139
6140
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006141void JSObject::DefinePropertyAccessor(Handle<JSObject> object,
6142 Handle<Name> name,
6143 Handle<Object> getter,
6144 Handle<Object> setter,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006145 PropertyAttributes attributes,
6146 v8::AccessControl access_control) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006147 // We could assert that the property is configurable here, but we would need
6148 // to do a lookup, which seems to be a bit of overkill.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006149 bool only_attribute_changes = getter->IsNull() && setter->IsNull();
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006150 if (object->HasFastProperties() && !only_attribute_changes &&
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006151 access_control == v8::DEFAULT &&
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006152 (object->map()->NumberOfOwnDescriptors() <
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006153 DescriptorArray::kMaxNumberOfDescriptors)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006154 bool getterOk = getter->IsNull() ||
6155 DefineFastAccessor(object, name, ACCESSOR_GETTER, getter, attributes);
6156 bool setterOk = !getterOk || setter->IsNull() ||
6157 DefineFastAccessor(object, name, ACCESSOR_SETTER, setter, attributes);
6158 if (getterOk && setterOk) return;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006159 }
6160
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006161 Handle<AccessorPair> accessors = CreateAccessorPairFor(object, name);
6162 accessors->SetComponents(*getter, *setter);
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006163 accessors->set_access_flags(access_control);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006164
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006165 SetPropertyCallback(object, name, accessors, attributes);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006166}
6167
6168
ulan@chromium.org750145a2013-03-07 15:14:13 +00006169bool JSObject::CanSetCallback(Name* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006170 ASSERT(!IsAccessCheckNeeded() ||
6171 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006172
6173 // Check if there is an API defined callback object which prohibits
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006174 // callback overwriting in this object or its prototype chain.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006175 // This mechanism is needed for instance in a browser setting, where
6176 // certain accessors such as window.location should not be allowed
6177 // to be overwritten because allowing overwriting could potentially
6178 // cause security problems.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006179 LookupResult callback_result(GetIsolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006180 LookupCallbackProperty(name, &callback_result);
6181 if (callback_result.IsFound()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006182 Object* obj = callback_result.GetCallbackObject();
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006183 if (obj->IsAccessorInfo()) {
6184 return !AccessorInfo::cast(obj)->prohibits_overwriting();
6185 }
6186 if (obj->IsAccessorPair()) {
6187 return !AccessorPair::cast(obj)->prohibits_overwriting();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006188 }
6189 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006190 return true;
6191}
6192
6193
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006194void JSObject::SetElementCallback(Handle<JSObject> object,
6195 uint32_t index,
6196 Handle<Object> structure,
6197 PropertyAttributes attributes) {
6198 Heap* heap = object->GetHeap();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006199 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006200
6201 // Normalize elements to make this operation simple.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006202 Handle<SeededNumberDictionary> dictionary = NormalizeElements(object);
6203 ASSERT(object->HasDictionaryElements() ||
6204 object->HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006205
6206 // Update the dictionary with the new CALLBACKS property.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006207 dictionary = SeededNumberDictionary::Set(dictionary, index, structure,
6208 details);
whesse@chromium.org7b260152011-06-20 15:33:18 +00006209 dictionary->set_requires_slow_elements();
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006210
whesse@chromium.org7b260152011-06-20 15:33:18 +00006211 // Update the dictionary backing store on the object.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006212 if (object->elements()->map() == heap->non_strict_arguments_elements_map()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00006213 // Also delete any parameter alias.
6214 //
6215 // TODO(kmillikin): when deleting the last parameter alias we could
6216 // switch to a direct backing store without the parameter map. This
6217 // would allow GC of the context.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006218 FixedArray* parameter_map = FixedArray::cast(object->elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006219 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006220 parameter_map->set(index + 2, heap->the_hole_value());
whesse@chromium.org7b260152011-06-20 15:33:18 +00006221 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006222 parameter_map->set(1, *dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00006223 } else {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006224 object->set_elements(*dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00006225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006226}
6227
6228
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006229void JSObject::SetPropertyCallback(Handle<JSObject> object,
6230 Handle<Name> name,
6231 Handle<Object> structure,
6232 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006233 // Normalize object to make this operation simple.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006234 NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006235
6236 // For the global object allocate a new map to invalidate the global inline
6237 // caches which have a global property cell reference directly in the code.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006238 if (object->IsGlobalObject()) {
6239 Handle<Map> new_map = Map::CopyDropDescriptors(handle(object->map()));
erik.corry@gmail.com88767242012-08-08 14:43:45 +00006240 ASSERT(new_map->is_dictionary_map());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006241 object->set_map(*new_map);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006242
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006243 // When running crankshaft, changing the map is not enough. We
6244 // need to deoptimize all functions that rely on this global
6245 // object.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006246 Deoptimizer::DeoptimizeGlobalObject(*object);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006247 }
6248
6249 // Update the dictionary with the new CALLBACKS property.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006250 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006251 SetNormalizedProperty(object, name, structure, details);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006252}
6253
danno@chromium.org88aa0582012-03-23 15:11:57 +00006254
6255void JSObject::DefineAccessor(Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00006256 Handle<Name> name,
danno@chromium.org88aa0582012-03-23 15:11:57 +00006257 Handle<Object> getter,
6258 Handle<Object> setter,
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006259 PropertyAttributes attributes,
6260 v8::AccessControl access_control) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006261 Isolate* isolate = object->GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006262 // Check access rights if needed.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006263 if (object->IsAccessCheckNeeded() &&
6264 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
6265 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
6266 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006267 }
6268
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006269 if (object->IsJSGlobalProxy()) {
6270 Handle<Object> proto(object->GetPrototype(), isolate);
6271 if (proto->IsNull()) return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006272 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006273 DefineAccessor(Handle<JSObject>::cast(proto),
6274 name,
6275 getter,
6276 setter,
6277 attributes,
6278 access_control);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006279 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006280 }
6281
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006282 // Make sure that the top context does not change when doing callbacks or
6283 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006284 AssertNoContextChange ncc(isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006285
6286 // Try to flatten before operating on the string.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006287 if (name->IsString()) String::cast(*name)->TryFlatten();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006288
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006289 if (!object->CanSetCallback(*name)) return;
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00006290
6291 uint32_t index = 0;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006292 bool is_element = name->AsArrayIndex(&index);
6293
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00006294 Handle<Object> old_value = isolate->factory()->the_hole_value();
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006295 bool is_observed = FLAG_harmony_observation && object->map()->is_observed();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006296 bool preexists = false;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00006297 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006298 if (is_element) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006299 preexists = HasLocalElement(object, index);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006300 if (preexists && object->GetLocalElementAccessorPair(index) == NULL) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006301 old_value = Object::GetElement(isolate, object, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006302 }
6303 } else {
6304 LookupResult lookup(isolate);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006305 object->LocalLookup(*name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006306 preexists = lookup.IsProperty();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006307 if (preexists && lookup.IsDataProperty()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006308 old_value = Object::GetProperty(object, name);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00006309 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006310 }
6311 }
6312
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006313 if (is_element) {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006314 DefineElementAccessor(
6315 object, index, getter, setter, attributes, access_control);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006316 } else {
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00006317 DefinePropertyAccessor(
6318 object, name, getter, setter, attributes, access_control);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006319 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006320
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00006321 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006322 const char* type = preexists ? "reconfigured" : "new";
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006323 EnqueueChangeRecord(object, type, name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006325}
6326
6327
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006328static bool TryAccessorTransition(JSObject* self,
6329 Map* transitioned_map,
6330 int target_descriptor,
6331 AccessorComponent component,
6332 Object* accessor,
6333 PropertyAttributes attributes) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006334 DescriptorArray* descs = transitioned_map->instance_descriptors();
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006335 PropertyDetails details = descs->GetDetails(target_descriptor);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006336
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006337 // If the transition target was not callbacks, fall back to the slow case.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006338 if (details.type() != CALLBACKS) return false;
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006339 Object* descriptor = descs->GetCallbacksObject(target_descriptor);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006340 if (!descriptor->IsAccessorPair()) return false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006341
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006342 Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006343 PropertyAttributes target_attributes = details.attributes();
6344
6345 // Reuse transition if adding same accessor with same attributes.
6346 if (target_accessor == accessor && target_attributes == attributes) {
6347 self->set_map(transitioned_map);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006348 return true;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006349 }
6350
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006351 // If either not the same accessor, or not the same attributes, fall back to
6352 // the slow case.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006353 return false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006354}
6355
6356
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006357static MaybeObject* CopyInsertDescriptor(Map* map,
6358 Name* name,
6359 AccessorPair* accessors,
6360 PropertyAttributes attributes) {
6361 CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
6362 return map->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
6363}
6364
6365
6366static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
6367 Handle<Name> name,
6368 Handle<AccessorPair> accessors,
6369 PropertyAttributes attributes) {
6370 CALL_HEAP_FUNCTION(map->GetIsolate(),
6371 CopyInsertDescriptor(*map, *name, *accessors, attributes),
6372 Map);
6373}
6374
6375
6376bool JSObject::DefineFastAccessor(Handle<JSObject> object,
6377 Handle<Name> name,
6378 AccessorComponent component,
6379 Handle<Object> accessor,
6380 PropertyAttributes attributes) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006381 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006382 Isolate* isolate = object->GetIsolate();
6383 LookupResult result(isolate);
6384 object->LocalLookup(*name, &result);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006385
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006386 if (result.IsFound() && !result.IsPropertyCallbacks()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006387 return false;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00006388 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006389
6390 // Return success if the same accessor with the same attributes already exist.
6391 AccessorPair* source_accessors = NULL;
6392 if (result.IsPropertyCallbacks()) {
6393 Object* callback_value = result.GetCallbackObject();
6394 if (callback_value->IsAccessorPair()) {
6395 source_accessors = AccessorPair::cast(callback_value);
6396 Object* entry = source_accessors->get(component);
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006397 if (entry == *accessor && result.GetAttributes() == attributes) {
6398 return true;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006399 }
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006400 } else {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006401 return false;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006402 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006403
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006404 int descriptor_number = result.GetDescriptorIndex();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006405
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006406 object->map()->LookupTransition(*object, *name, &result);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006407
6408 if (result.IsFound()) {
6409 Map* target = result.GetTransitionTarget();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006410 ASSERT(target->NumberOfOwnDescriptors() ==
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006411 object->map()->NumberOfOwnDescriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006412 // This works since descriptors are sorted in order of addition.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006413 ASSERT(object->map()->instance_descriptors()->
6414 GetKey(descriptor_number) == *name);
6415 return TryAccessorTransition(*object, target, descriptor_number,
6416 component, *accessor, attributes);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006417 }
6418 } else {
6419 // If not, lookup a transition.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006420 object->map()->LookupTransition(*object, *name, &result);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006421
6422 // If there is a transition, try to follow it.
6423 if (result.IsFound()) {
6424 Map* target = result.GetTransitionTarget();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006425 int descriptor_number = target->LastAdded();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00006426 ASSERT(target->instance_descriptors()->GetKey(descriptor_number)
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006427 ->Equals(*name));
6428 return TryAccessorTransition(*object, target, descriptor_number,
6429 component, *accessor, attributes);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00006430 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006431 }
6432
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006433 // If there is no transition yet, add a transition to the a new accessor pair
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006434 // containing the accessor. Allocate a new pair if there were no source
6435 // accessors. Otherwise, copy the pair and modify the accessor.
6436 Handle<AccessorPair> accessors = source_accessors != NULL
6437 ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
6438 : isolate->factory()->NewAccessorPair();
6439 accessors->set(component, *accessor);
6440 Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()),
6441 name, accessors, attributes);
6442 object->set_map(*new_map);
6443 return true;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006444}
6445
6446
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006447Handle<Object> JSObject::SetAccessor(Handle<JSObject> object,
6448 Handle<AccessorInfo> info) {
6449 Isolate* isolate = object->GetIsolate();
6450 Factory* factory = isolate->factory();
6451 Handle<Name> name(Name::cast(info->name()));
6452
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006453 // Check access rights if needed.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006454 if (object->IsAccessCheckNeeded() &&
6455 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_SET)) {
6456 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_SET);
6457 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
6458 return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006459 }
6460
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006461 if (object->IsJSGlobalProxy()) {
6462 Handle<Object> proto(object->GetPrototype(), isolate);
6463 if (proto->IsNull()) return object;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006464 ASSERT(proto->IsJSGlobalObject());
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006465 return SetAccessor(Handle<JSObject>::cast(proto), info);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006466 }
6467
6468 // Make sure that the top context does not change when doing callbacks or
6469 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006470 AssertNoContextChange ncc(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006471
6472 // Try to flatten before operating on the string.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006473 if (name->IsString()) FlattenString(Handle<String>::cast(name));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006474
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006475 if (!object->CanSetCallback(*name)) return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006476
6477 uint32_t index = 0;
6478 bool is_element = name->AsArrayIndex(&index);
6479
6480 if (is_element) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006481 if (object->IsJSArray()) return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006482
6483 // Accessors overwrite previous callbacks (cf. with getters/setters).
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006484 switch (object->GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006485 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006486 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00006487 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006488 case FAST_HOLEY_SMI_ELEMENTS:
6489 case FAST_HOLEY_ELEMENTS:
6490 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006491 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006492 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006493 case EXTERNAL_BYTE_ELEMENTS:
6494 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6495 case EXTERNAL_SHORT_ELEMENTS:
6496 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6497 case EXTERNAL_INT_ELEMENTS:
6498 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6499 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006500 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006501 // Ignore getters and setters on pixel and external array
6502 // elements.
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006503 return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006504 case DICTIONARY_ELEMENTS:
6505 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006506 case NON_STRICT_ARGUMENTS_ELEMENTS:
6507 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006508 break;
6509 }
6510
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006511 SetElementCallback(object, index, info, info->property_attributes());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006512 } else {
6513 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006514 LookupResult result(isolate);
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006515 object->LocalLookup(*name, &result, true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006516 // ES5 forbids turning a property into an accessor if it's not
6517 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006518 if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006519 return factory->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006520 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006521
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006522 SetPropertyCallback(object, name, info, info->property_attributes());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006523 }
6524
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +00006525 return object;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006526}
6527
6528
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006529Handle<Object> JSObject::GetAccessor(Handle<JSObject> object,
6530 Handle<Name> name,
6531 AccessorComponent component) {
6532 Isolate* isolate = object->GetIsolate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 // Make sure that the top context does not change when doing callbacks or
6535 // interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006536 AssertNoContextChange ncc(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006537
6538 // Check access rights if needed.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006539 if (object->IsAccessCheckNeeded() &&
6540 !isolate->MayNamedAccess(*object, *name, v8::ACCESS_HAS)) {
6541 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_HAS);
6542 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
6543 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 }
6545
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006546 // Make the lookup and include prototypes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006547 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006548 if (name->AsArrayIndex(&index)) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006549 for (Handle<Object> obj = object;
6550 *obj != isolate->heap()->null_value();
6551 obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
6552 if (obj->IsJSObject() && JSObject::cast(*obj)->HasDictionaryElements()) {
6553 JSObject* js_object = JSObject::cast(*obj);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006554 SeededNumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00006555 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006556 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006557 Object* element = dictionary->ValueAt(entry);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006558 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6559 element->IsAccessorPair()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006560 return handle(AccessorPair::cast(element)->GetComponent(component),
6561 isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006562 }
6563 }
6564 }
6565 }
6566 } else {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006567 for (Handle<Object> obj = object;
6568 *obj != isolate->heap()->null_value();
6569 obj = handle(JSReceiver::cast(*obj)->GetPrototype(), isolate)) {
6570 LookupResult result(isolate);
6571 JSReceiver::cast(*obj)->LocalLookup(*name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006572 if (result.IsFound()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006573 if (result.IsReadOnly()) return isolate->factory()->undefined_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006574 if (result.IsPropertyCallbacks()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006575 Object* obj = result.GetCallbackObject();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006576 if (obj->IsAccessorPair()) {
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006577 return handle(AccessorPair::cast(obj)->GetComponent(component),
6578 isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006579 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006580 }
6581 }
6582 }
6583 }
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +00006584 return isolate->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585}
6586
6587
6588Object* JSObject::SlowReverseLookup(Object* value) {
6589 if (HasFastProperties()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006590 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006591 DescriptorArray* descs = map()->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006592 for (int i = 0; i < number_of_own_descriptors; i++) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006593 if (descs->GetType(i) == FIELD) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006594 Object* property = RawFastPropertyAt(descs->GetFieldIndex(i));
6595 if (FLAG_track_double_fields &&
6596 descs->GetDetails(i).representation().IsDouble()) {
6597 ASSERT(property->IsHeapNumber());
6598 if (value->IsNumber() && property->Number() == value->Number()) {
6599 return descs->GetKey(i);
6600 }
6601 } else if (property == value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006602 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00006604 } else if (descs->GetType(i) == CONSTANT) {
6605 if (descs->GetConstant(i) == value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006606 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006607 }
6608 }
6609 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006610 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006611 } else {
6612 return property_dictionary()->SlowReverseLookup(value);
6613 }
6614}
6615
6616
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006617MaybeObject* Map::RawCopy(int instance_size) {
6618 Map* result;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006619 MaybeObject* maybe_result =
6620 GetHeap()->AllocateMap(instance_type(), instance_size);
6621 if (!maybe_result->To(&result)) return maybe_result;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006622
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006623 result->set_prototype(prototype());
6624 result->set_constructor(constructor());
6625 result->set_bit_field(bit_field());
6626 result->set_bit_field2(bit_field2());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006627 int new_bit_field3 = bit_field3();
6628 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
6629 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
6630 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006631 new_bit_field3 = Deprecated::update(new_bit_field3, false);
danno@chromium.orgd3c42102013-08-01 16:58:23 +00006632 new_bit_field3 = IsUnstable::update(new_bit_field3, false);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006633 result->set_bit_field3(new_bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634 return result;
6635}
6636
6637
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00006638Handle<Map> Map::CopyNormalized(Handle<Map> map,
6639 PropertyNormalizationMode mode,
6640 NormalizedMapSharingMode sharing) {
6641 CALL_HEAP_FUNCTION(map->GetIsolate(),
6642 map->CopyNormalized(mode, sharing),
6643 Map);
6644}
6645
6646
lrn@chromium.org303ada72010-10-27 09:33:13 +00006647MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
6648 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00006649 int new_instance_size = instance_size();
6650 if (mode == CLEAR_INOBJECT_PROPERTIES) {
6651 new_instance_size -= inobject_properties() * kPointerSize;
6652 }
6653
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006654 Map* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006655 MaybeObject* maybe_result = RawCopy(new_instance_size);
6656 if (!maybe_result->To(&result)) return maybe_result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00006657
6658 if (mode != CLEAR_INOBJECT_PROPERTIES) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006659 result->set_inobject_properties(inobject_properties());
ricow@chromium.org65fae842010-08-25 15:26:24 +00006660 }
6661
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006662 result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00006663 result->set_dictionary_map(true);
danno@chromium.org59400602013-08-13 17:09:37 +00006664 result->set_migration_target(false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006665
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006666#ifdef VERIFY_HEAP
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006667 if (FLAG_verify_heap && result->is_shared()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006668 result->SharedMapVerify();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006669 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00006670#endif
6671
6672 return result;
6673}
6674
6675
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00006676Handle<Map> Map::CopyDropDescriptors(Handle<Map> map) {
6677 CALL_HEAP_FUNCTION(map->GetIsolate(), map->CopyDropDescriptors(), Map);
6678}
6679
6680
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006681MaybeObject* Map::CopyDropDescriptors() {
6682 Map* result;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006683 MaybeObject* maybe_result = RawCopy(instance_size());
6684 if (!maybe_result->To(&result)) return maybe_result;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006685
6686 // Please note instance_type and instance_size are set when allocated.
6687 result->set_inobject_properties(inobject_properties());
6688 result->set_unused_property_fields(unused_property_fields());
6689
6690 result->set_pre_allocated_property_fields(pre_allocated_property_fields());
6691 result->set_is_shared(false);
6692 result->ClearCodeCache(GetHeap());
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006693 NotifyLeafMapLayoutChange();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006694 return result;
6695}
6696
6697
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006698MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors,
6699 Descriptor* descriptor) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006700 // Sanity check. This path is only to be taken if the map owns its descriptor
6701 // array, implying that its NumberOfOwnDescriptors equals the number of
6702 // descriptors in the descriptor array.
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006703 ASSERT(NumberOfOwnDescriptors() ==
6704 instance_descriptors()->number_of_descriptors());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006705 Map* result;
6706 MaybeObject* maybe_result = CopyDropDescriptors();
6707 if (!maybe_result->To(&result)) return maybe_result;
6708
ulan@chromium.org750145a2013-03-07 15:14:13 +00006709 Name* name = descriptor->GetKey();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006710
6711 TransitionArray* transitions;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006712 MaybeObject* maybe_transitions =
6713 AddTransition(name, result, SIMPLE_TRANSITION);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006714 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
6715
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006716 int old_size = descriptors->number_of_descriptors();
6717
6718 DescriptorArray* new_descriptors;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006719
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006720 if (descriptors->NumberOfSlackDescriptors() > 0) {
6721 new_descriptors = descriptors;
6722 new_descriptors->Append(descriptor);
6723 } else {
6724 // Descriptor arrays grow by 50%.
6725 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00006726 GetIsolate(), old_size, old_size < 4 ? 1 : old_size / 2);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006727 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006728
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006729 DescriptorArray::WhitenessWitness witness(new_descriptors);
6730
6731 // Copy the descriptors, inserting a descriptor.
6732 for (int i = 0; i < old_size; ++i) {
6733 new_descriptors->CopyFrom(i, descriptors, i, witness);
6734 }
6735
6736 new_descriptors->Append(descriptor, witness);
6737
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006738 if (old_size > 0) {
6739 // If the source descriptors had an enum cache we copy it. This ensures
6740 // that the maps to which we push the new descriptor array back can rely
6741 // on a cache always being available once it is set. If the map has more
6742 // enumerated descriptors than available in the original cache, the cache
6743 // will be lazily replaced by the extended cache when needed.
6744 if (descriptors->HasEnumCache()) {
6745 new_descriptors->CopyEnumCacheFrom(descriptors);
6746 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006747
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006748 Map* map;
6749 // Replace descriptors by new_descriptors in all maps that share it.
6750 for (Object* current = GetBackPointer();
6751 !current->IsUndefined();
6752 current = map->GetBackPointer()) {
6753 map = Map::cast(current);
6754 if (map->instance_descriptors() != descriptors) break;
6755 map->set_instance_descriptors(new_descriptors);
6756 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006757
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006758 set_instance_descriptors(new_descriptors);
6759 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006760 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006761
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006762 result->SetBackPointer(this);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006763 result->InitializeDescriptors(new_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006764 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1);
6765
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006766 set_transitions(transitions);
6767 set_owns_descriptors(false);
6768
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006769 return result;
6770}
6771
6772
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006773Handle<Map> Map::CopyReplaceDescriptors(Handle<Map> map,
6774 Handle<DescriptorArray> descriptors,
6775 TransitionFlag flag,
6776 Handle<Name> name) {
6777 CALL_HEAP_FUNCTION(map->GetIsolate(),
6778 map->CopyReplaceDescriptors(*descriptors, flag, *name),
6779 Map);
6780}
6781
6782
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006783MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006784 TransitionFlag flag,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006785 Name* name,
6786 SimpleTransitionFlag simple_flag) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006787 ASSERT(descriptors->IsSortedNoDuplicates());
6788
6789 Map* result;
6790 MaybeObject* maybe_result = CopyDropDescriptors();
6791 if (!maybe_result->To(&result)) return maybe_result;
6792
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006793 result->InitializeDescriptors(descriptors);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006794
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006795 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006796 TransitionArray* transitions;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006797 MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006798 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006799 set_transitions(transitions);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006800 result->SetBackPointer(this);
rossberg@chromium.org92597162013-08-23 13:28:00 +00006801 } else {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006802 descriptors->InitializeRepresentations(Representation::Tagged());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006803 }
6804
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006805 return result;
6806}
6807
6808
machenbach@chromium.org528ce022013-09-23 14:09:36 +00006809Handle<Map> Map::CopyInstallDescriptors(Handle<Map> map,
6810 int new_descriptor,
6811 Handle<DescriptorArray> descriptors) {
6812 CALL_HEAP_FUNCTION(map->GetIsolate(),
6813 map->CopyInstallDescriptors(new_descriptor, *descriptors),
6814 Map);
6815}
6816
6817
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00006818// Since this method is used to rewrite an existing transition tree, it can
6819// always insert transitions without checking.
danno@chromium.orgf005df62013-04-30 16:36:45 +00006820MaybeObject* Map::CopyInstallDescriptors(int new_descriptor,
6821 DescriptorArray* descriptors) {
6822 ASSERT(descriptors->IsSortedNoDuplicates());
6823
6824 Map* result;
6825 MaybeObject* maybe_result = CopyDropDescriptors();
6826 if (!maybe_result->To(&result)) return maybe_result;
6827
6828 result->InitializeDescriptors(descriptors);
6829 result->SetNumberOfOwnDescriptors(new_descriptor + 1);
6830
6831 int unused_property_fields = this->unused_property_fields();
6832 if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
6833 unused_property_fields = this->unused_property_fields() - 1;
6834 if (unused_property_fields < 0) {
6835 unused_property_fields += JSObject::kFieldsAdded;
6836 }
6837 }
6838
6839 result->set_unused_property_fields(unused_property_fields);
6840 result->set_owns_descriptors(false);
6841
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00006842 Name* name = descriptors->GetKey(new_descriptor);
6843 TransitionArray* transitions;
6844 MaybeObject* maybe_transitions =
6845 AddTransition(name, result, SIMPLE_TRANSITION);
6846 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
danno@chromium.orgf005df62013-04-30 16:36:45 +00006847
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00006848 set_transitions(transitions);
6849 result->SetBackPointer(this);
danno@chromium.orgf005df62013-04-30 16:36:45 +00006850
6851 return result;
6852}
6853
6854
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006855MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006856 if (flag == INSERT_TRANSITION) {
6857 ASSERT(!HasElementsTransition() ||
6858 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
6859 IsExternalArrayElementsKind(
6860 elements_transition_map()->elements_kind())) &&
6861 (kind == DICTIONARY_ELEMENTS ||
6862 IsExternalArrayElementsKind(kind))));
6863 ASSERT(!IsFastElementsKind(kind) ||
6864 IsMoreGeneralElementsKindTransition(elements_kind(), kind));
6865 ASSERT(kind != elements_kind());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006866 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006867
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006868 bool insert_transition =
6869 flag == INSERT_TRANSITION && !HasElementsTransition();
6870
6871 if (insert_transition && owns_descriptors()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006872 // In case the map owned its own descriptors, share the descriptors and
6873 // transfer ownership to the new map.
6874 Map* new_map;
6875 MaybeObject* maybe_new_map = CopyDropDescriptors();
6876 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
6877
6878 MaybeObject* added_elements = set_elements_transition_map(new_map);
6879 if (added_elements->IsFailure()) return added_elements;
6880
6881 new_map->set_elements_kind(kind);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006882 new_map->InitializeDescriptors(instance_descriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006883 new_map->SetBackPointer(this);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006884 set_owns_descriptors(false);
6885 return new_map;
6886 }
6887
6888 // In case the map did not own its own descriptors, a split is forced by
6889 // copying the map; creating a new descriptor array cell.
6890 // Create a new free-floating map only if we are not allowed to store it.
6891 Map* new_map;
6892 MaybeObject* maybe_new_map = Copy();
6893 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006894
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006895 new_map->set_elements_kind(kind);
6896
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006897 if (insert_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006898 MaybeObject* added_elements = set_elements_transition_map(new_map);
6899 if (added_elements->IsFailure()) return added_elements;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006900 new_map->SetBackPointer(this);
6901 }
6902
6903 return new_map;
6904}
6905
6906
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +00006907Handle<Map> Map::CopyForObserved(Handle<Map> map) {
6908 CALL_HEAP_FUNCTION(map->GetIsolate(),
6909 map->CopyForObserved(),
6910 Map);
6911}
6912
6913
danno@chromium.org169691d2013-07-15 08:01:13 +00006914MaybeObject* Map::CopyForObserved() {
6915 ASSERT(!is_observed());
6916
6917 // In case the map owned its own descriptors, share the descriptors and
6918 // transfer ownership to the new map.
6919 Map* new_map;
6920 MaybeObject* maybe_new_map;
6921 if (owns_descriptors()) {
6922 maybe_new_map = CopyDropDescriptors();
6923 } else {
6924 maybe_new_map = Copy();
6925 }
6926 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
6927
6928 TransitionArray* transitions;
6929 MaybeObject* maybe_transitions = AddTransition(GetHeap()->observed_symbol(),
6930 new_map,
6931 FULL_TRANSITION);
6932 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
6933 set_transitions(transitions);
6934
6935 new_map->set_is_observed(true);
6936
6937 if (owns_descriptors()) {
6938 new_map->InitializeDescriptors(instance_descriptors());
6939 set_owns_descriptors(false);
6940 }
6941
6942 new_map->SetBackPointer(this);
6943 return new_map;
6944}
6945
6946
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006947MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
6948 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
6949
6950 // If the map has pre-allocated properties always start out with a descriptor
6951 // array describing these properties.
6952 ASSERT(constructor()->IsJSFunction());
6953 JSFunction* ctor = JSFunction::cast(constructor());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006954 Map* map = ctor->initial_map();
6955 DescriptorArray* descriptors = map->instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006956
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006957 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
6958 DescriptorArray* new_descriptors;
6959 MaybeObject* maybe_descriptors =
6960 descriptors->CopyUpTo(number_of_own_descriptors);
6961 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
6962
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006963 return CopyReplaceDescriptors(new_descriptors, OMIT_TRANSITION);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006964}
6965
6966
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00006967Handle<Map> Map::Copy(Handle<Map> map) {
6968 CALL_HEAP_FUNCTION(map->GetIsolate(), map->Copy(), Map);
6969}
6970
6971
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006972MaybeObject* Map::Copy() {
6973 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006974 DescriptorArray* new_descriptors;
6975 int number_of_own_descriptors = NumberOfOwnDescriptors();
6976 MaybeObject* maybe_descriptors =
6977 descriptors->CopyUpTo(number_of_own_descriptors);
6978 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
6979
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00006980 return CopyReplaceDescriptors(new_descriptors, OMIT_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006981}
6982
6983
6984MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
6985 TransitionFlag flag) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006986 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006987
ulan@chromium.org750145a2013-03-07 15:14:13 +00006988 // Ensure the key is unique.
6989 MaybeObject* maybe_failure = descriptor->KeyToUniqueName();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006990 if (maybe_failure->IsFailure()) return maybe_failure;
6991
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006992 int old_size = NumberOfOwnDescriptors();
verwaest@chromium.org652f4fa2012-10-08 08:48:51 +00006993 int new_size = old_size + 1;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006994
6995 if (flag == INSERT_TRANSITION &&
6996 owns_descriptors() &&
6997 CanHaveMoreTransitions()) {
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006998 return ShareDescriptor(descriptors, descriptor);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006999 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007000
7001 DescriptorArray* new_descriptors;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007002 MaybeObject* maybe_descriptors =
7003 DescriptorArray::Allocate(GetIsolate(), old_size, 1);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007004 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
7005
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007006 DescriptorArray::WhitenessWitness witness(new_descriptors);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007007
7008 // Copy the descriptors, inserting a descriptor.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007009 for (int i = 0; i < old_size; ++i) {
7010 new_descriptors->CopyFrom(i, descriptors, i, witness);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007011 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007012
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007013 if (old_size != descriptors->number_of_descriptors()) {
7014 new_descriptors->SetNumberOfDescriptors(new_size);
7015 new_descriptors->Set(old_size, descriptor, witness);
7016 new_descriptors->Sort();
7017 } else {
7018 new_descriptors->Append(descriptor, witness);
7019 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007020
ulan@chromium.org750145a2013-03-07 15:14:13 +00007021 Name* key = descriptor->GetKey();
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007022 return CopyReplaceDescriptors(new_descriptors, flag, key, SIMPLE_TRANSITION);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007023}
7024
7025
7026MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor,
7027 TransitionFlag flag) {
7028 DescriptorArray* old_descriptors = instance_descriptors();
7029
ulan@chromium.org750145a2013-03-07 15:14:13 +00007030 // Ensure the key is unique.
7031 MaybeObject* maybe_result = descriptor->KeyToUniqueName();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007032 if (maybe_result->IsFailure()) return maybe_result;
7033
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007034 // We replace the key if it is already present.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007035 int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007036 if (index != DescriptorArray::kNotFound) {
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00007037 return CopyReplaceDescriptor(old_descriptors, descriptor, index, flag);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00007038 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007039 return CopyAddDescriptor(descriptor, flag);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007040}
7041
7042
machenbach@chromium.org528ce022013-09-23 14:09:36 +00007043Handle<DescriptorArray> DescriptorArray::CopyUpToAddAttributes(
7044 Handle<DescriptorArray> desc,
7045 int enumeration_index,
7046 PropertyAttributes attributes) {
7047 CALL_HEAP_FUNCTION(desc->GetIsolate(),
7048 desc->CopyUpToAddAttributes(enumeration_index, attributes),
7049 DescriptorArray);
7050}
7051
7052
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007053MaybeObject* DescriptorArray::CopyUpToAddAttributes(
7054 int enumeration_index, PropertyAttributes attributes) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007055 if (enumeration_index == 0) return GetHeap()->empty_descriptor_array();
7056
7057 int size = enumeration_index;
7058
7059 DescriptorArray* descriptors;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007060 MaybeObject* maybe_descriptors = Allocate(GetIsolate(), size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007061 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
7062 DescriptorArray::WhitenessWitness witness(descriptors);
7063
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007064 if (attributes != NONE) {
7065 for (int i = 0; i < size; ++i) {
7066 Object* value = GetValue(i);
7067 PropertyDetails details = GetDetails(i);
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00007068 int mask = DONT_DELETE | DONT_ENUM;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007069 // READ_ONLY is an invalid attribute for JS setters/getters.
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00007070 if (details.type() != CALLBACKS || !value->IsAccessorPair()) {
7071 mask |= READ_ONLY;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007072 }
svenpanne@chromium.org53ad1752013-05-27 12:20:38 +00007073 details = details.CopyAddAttributes(
7074 static_cast<PropertyAttributes>(attributes & mask));
7075 Descriptor desc(GetKey(i), value, details);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007076 descriptors->Set(i, &desc, witness);
7077 }
7078 } else {
7079 for (int i = 0; i < size; ++i) {
7080 descriptors->CopyFrom(i, this, i, witness);
7081 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007082 }
7083
7084 if (number_of_descriptors() != enumeration_index) descriptors->Sort();
7085
7086 return descriptors;
7087}
7088
7089
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00007090MaybeObject* Map::CopyReplaceDescriptor(DescriptorArray* descriptors,
7091 Descriptor* descriptor,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007092 int insertion_index,
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007093 TransitionFlag flag) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00007094 // Ensure the key is unique.
7095 MaybeObject* maybe_failure = descriptor->KeyToUniqueName();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007096 if (maybe_failure->IsFailure()) return maybe_failure;
7097
ulan@chromium.org750145a2013-03-07 15:14:13 +00007098 Name* key = descriptor->GetKey();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007099 ASSERT(key == descriptors->GetKey(insertion_index));
7100
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007101 int new_size = NumberOfOwnDescriptors();
7102 ASSERT(0 <= insertion_index && insertion_index < new_size);
verwaest@chromium.org652f4fa2012-10-08 08:48:51 +00007103
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007104 ASSERT_LT(insertion_index, new_size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007105
7106 DescriptorArray* new_descriptors;
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007107 MaybeObject* maybe_descriptors =
7108 DescriptorArray::Allocate(GetIsolate(), new_size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007109 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00007110 DescriptorArray::WhitenessWitness witness(new_descriptors);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007111
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007112 for (int i = 0; i < new_size; ++i) {
7113 if (i == insertion_index) {
7114 new_descriptors->Set(i, descriptor, witness);
7115 } else {
7116 new_descriptors->CopyFrom(i, descriptors, i, witness);
7117 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007118 }
7119
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007120 // Re-sort if descriptors were removed.
7121 if (new_size != descriptors->length()) new_descriptors->Sort();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007122
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00007123 SimpleTransitionFlag simple_flag =
7124 (insertion_index == descriptors->number_of_descriptors() - 1)
7125 ? SIMPLE_TRANSITION
7126 : FULL_TRANSITION;
7127 return CopyReplaceDescriptors(new_descriptors, flag, key, simple_flag);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007128}
7129
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007130
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007131void Map::UpdateCodeCache(Handle<Map> map,
ulan@chromium.org750145a2013-03-07 15:14:13 +00007132 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007133 Handle<Code> code) {
7134 Isolate* isolate = map->GetIsolate();
7135 CALL_HEAP_FUNCTION_VOID(isolate,
7136 map->UpdateCodeCache(*name, *code));
7137}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007138
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007139
ulan@chromium.org750145a2013-03-07 15:14:13 +00007140MaybeObject* Map::UpdateCodeCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007141 // Allocate the code cache if not present.
7142 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007143 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007144 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007145 if (!maybe_result->ToObject(&result)) return maybe_result;
7146 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007147 set_code_cache(result);
7148 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007149
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007150 // Update the code cache.
7151 return CodeCache::cast(code_cache())->Update(name, code);
7152}
7153
7154
ulan@chromium.org750145a2013-03-07 15:14:13 +00007155Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007156 // Do a lookup if a code cache exists.
7157 if (!code_cache()->IsFixedArray()) {
7158 return CodeCache::cast(code_cache())->Lookup(name, flags);
7159 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007160 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007161 }
7162}
7163
7164
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00007165int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007166 // Get the internal index if a code cache exists.
7167 if (!code_cache()->IsFixedArray()) {
7168 return CodeCache::cast(code_cache())->GetIndex(name, code);
7169 }
7170 return -1;
7171}
7172
7173
ulan@chromium.org750145a2013-03-07 15:14:13 +00007174void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007175 // No GC is supposed to happen between a call to IndexInCodeCache and
7176 // RemoveFromCodeCache so the code cache must be there.
7177 ASSERT(!code_cache()->IsFixedArray());
7178 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
7179}
7180
7181
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007182// An iterator over all map transitions in an descriptor array, reusing the map
7183// field of the contens array while it is running.
7184class IntrusiveMapTransitionIterator {
7185 public:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007186 explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
7187 : transition_array_(transition_array) { }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007188
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007189 void Start() {
7190 ASSERT(!IsIterating());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007191 *TransitionArrayHeader() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007192 }
7193
7194 bool IsIterating() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007195 return (*TransitionArrayHeader())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007196 }
7197
7198 Map* Next() {
7199 ASSERT(IsIterating());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007200 int index = Smi::cast(*TransitionArrayHeader())->value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007201 int number_of_transitions = transition_array_->number_of_transitions();
7202 while (index < number_of_transitions) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007203 *TransitionArrayHeader() = Smi::FromInt(index + 1);
7204 return transition_array_->GetTarget(index);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007205 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007206
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007207 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007208 return NULL;
7209 }
7210
7211 private:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007212 Object** TransitionArrayHeader() {
7213 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007214 }
7215
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007216 TransitionArray* transition_array_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007217};
7218
7219
7220// An iterator over all prototype transitions, reusing the map field of the
7221// underlying array while it is running.
7222class IntrusivePrototypeTransitionIterator {
7223 public:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007224 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007225 : proto_trans_(proto_trans) { }
7226
7227 void Start() {
7228 ASSERT(!IsIterating());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007229 *Header() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007230 }
7231
7232 bool IsIterating() {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007233 return (*Header())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007234 }
7235
7236 Map* Next() {
7237 ASSERT(IsIterating());
7238 int transitionNumber = Smi::cast(*Header())->value();
7239 if (transitionNumber < NumberOfTransitions()) {
7240 *Header() = Smi::FromInt(transitionNumber + 1);
7241 return GetTransition(transitionNumber);
7242 }
7243 *Header() = proto_trans_->GetHeap()->fixed_array_map();
7244 return NULL;
7245 }
7246
7247 private:
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007248 Object** Header() {
7249 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
7250 }
7251
7252 int NumberOfTransitions() {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007253 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7254 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007255 return Smi::cast(num)->value();
7256 }
7257
7258 Map* GetTransition(int transitionNumber) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007259 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
7260 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007261 }
7262
7263 int IndexFor(int transitionNumber) {
7264 return Map::kProtoTransitionHeaderSize +
7265 Map::kProtoTransitionMapOffset +
7266 transitionNumber * Map::kProtoTransitionElementsPerEntry;
7267 }
7268
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00007269 HeapObject* proto_trans_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007270};
7271
7272
7273// To traverse the transition tree iteratively, we have to store two kinds of
7274// information in a map: The parent map in the traversal and which children of a
7275// node have already been visited. To do this without additional memory, we
7276// temporarily reuse two maps with known values:
7277//
7278// (1) The map of the map temporarily holds the parent, and is restored to the
7279// meta map afterwards.
7280//
7281// (2) The info which children have already been visited depends on which part
7282// of the map we currently iterate:
7283//
7284// (a) If we currently follow normal map transitions, we temporarily store
7285// the current index in the map of the FixedArray of the desciptor
7286// array's contents, and restore it to the fixed array map afterwards.
7287// Note that a single descriptor can have 0, 1, or 2 transitions.
7288//
7289// (b) If we currently follow prototype transitions, we temporarily store
7290// the current index in the map of the FixedArray holding the prototype
7291// transitions, and restore it to the fixed array map afterwards.
7292//
7293// Note that the child iterator is just a concatenation of two iterators: One
7294// iterating over map transitions and one iterating over prototype transisitons.
7295class TraversableMap : public Map {
7296 public:
7297 // Record the parent in the traversal within this map. Note that this destroys
7298 // this map's map!
7299 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
7300
7301 // Reset the current map's map, returning the parent previously stored in it.
7302 TraversableMap* GetAndResetParent() {
7303 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
7304 set_map_no_write_barrier(GetHeap()->meta_map());
7305 return old_parent;
7306 }
7307
7308 // Start iterating over this map's children, possibly destroying a FixedArray
7309 // map (see explanation above).
7310 void ChildIteratorStart() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007311 if (HasTransitionArray()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007312 if (HasPrototypeTransitions()) {
7313 IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start();
7314 }
7315
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007316 IntrusiveMapTransitionIterator(transitions()).Start();
7317 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007318 }
7319
7320 // If we have an unvisited child map, return that one and advance. If we have
7321 // none, return NULL and reset any destroyed FixedArray maps.
7322 TraversableMap* ChildIteratorNext() {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007323 TransitionArray* transition_array = unchecked_transition_array();
7324 if (!transition_array->map()->IsSmi() &&
7325 !transition_array->IsTransitionArray()) {
7326 return NULL;
7327 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007328
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007329 if (transition_array->HasPrototypeTransitions()) {
7330 HeapObject* proto_transitions =
7331 transition_array->UncheckedPrototypeTransitions();
7332 IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
7333 if (proto_iterator.IsIterating()) {
7334 Map* next = proto_iterator.Next();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00007335 if (next != NULL) return static_cast<TraversableMap*>(next);
7336 }
verwaest@chromium.org37141392012-05-31 13:27:02 +00007337 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00007338
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00007339 IntrusiveMapTransitionIterator transition_iterator(transition_array);
7340 if (transition_iterator.IsIterating()) {
7341 Map* next = transition_iterator.Next();
7342 if (next != NULL) return static_cast<TraversableMap*>(next);
7343 }
7344
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007345 return NULL;
7346 }
7347};
7348
7349
7350// Traverse the transition tree in postorder without using the C++ stack by
7351// doing pointer reversal.
7352void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
7353 TraversableMap* current = static_cast<TraversableMap*>(this);
7354 current->ChildIteratorStart();
7355 while (true) {
7356 TraversableMap* child = current->ChildIteratorNext();
7357 if (child != NULL) {
7358 child->ChildIteratorStart();
7359 child->SetParent(current);
7360 current = child;
7361 } else {
7362 TraversableMap* parent = current->GetAndResetParent();
7363 callback(current, data);
7364 if (current == this) break;
7365 current = parent;
7366 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007367 }
7368}
7369
7370
ulan@chromium.org750145a2013-03-07 15:14:13 +00007371MaybeObject* CodeCache::Update(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007372 // The number of monomorphic stubs for normal load/store/call IC's can grow to
7373 // a large number and therefore they need to go into a hash table. They are
7374 // used to load global properties from cells.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007375 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007376 // Make sure that a hash table is allocated for the normal load code cache.
7377 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007378 Object* result;
7379 { MaybeObject* maybe_result =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007380 CodeCacheHashTable::Allocate(GetHeap(),
7381 CodeCacheHashTable::kInitialSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007382 if (!maybe_result->ToObject(&result)) return maybe_result;
7383 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007384 set_normal_type_cache(result);
7385 }
7386 return UpdateNormalTypeCache(name, code);
7387 } else {
7388 ASSERT(default_cache()->IsFixedArray());
7389 return UpdateDefaultCache(name, code);
7390 }
7391}
7392
7393
ulan@chromium.org750145a2013-03-07 15:14:13 +00007394MaybeObject* CodeCache::UpdateDefaultCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007395 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007396 // flags. This allows call constant stubs to overwrite call field
7397 // stubs, etc.
7398 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
7399
7400 // First check whether we can update existing code cache without
7401 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007402 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007403 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00007404 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007405 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007406 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00007407 if (key->IsNull()) {
7408 if (deleted_index < 0) deleted_index = i;
7409 continue;
7410 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007411 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00007412 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007413 cache->set(i + kCodeCacheEntryNameOffset, name);
7414 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007415 return this;
7416 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00007417 if (name->Equals(Name::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007418 Code::Flags found =
7419 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007421 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422 return this;
7423 }
7424 }
7425 }
7426
ager@chromium.org236ad962008-09-25 09:45:57 +00007427 // Reached the end of the code cache. If there were deleted
7428 // elements, reuse the space for the first of them.
7429 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007430 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
7431 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00007432 return this;
7433 }
7434
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007435 // Extend the code cache with some new entries (at least one). Must be a
7436 // multiple of the entry size.
7437 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
7438 new_length = new_length - new_length % kCodeCacheEntrySize;
7439 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007440 Object* result;
7441 { MaybeObject* maybe_result = cache->CopySize(new_length);
7442 if (!maybe_result->ToObject(&result)) return maybe_result;
7443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444
7445 // Add the (name, code) pair to the new cache.
7446 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007447 cache->set(length + kCodeCacheEntryNameOffset, name);
7448 cache->set(length + kCodeCacheEntryCodeOffset, code);
7449 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450 return this;
7451}
7452
7453
ulan@chromium.org750145a2013-03-07 15:14:13 +00007454MaybeObject* CodeCache::UpdateNormalTypeCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007455 // Adding a new entry can cause a new cache to be allocated.
7456 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007457 Object* new_cache;
7458 { MaybeObject* maybe_new_cache = cache->Put(name, code);
7459 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
7460 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007461 set_normal_type_cache(new_cache);
7462 return this;
7463}
7464
7465
ulan@chromium.org750145a2013-03-07 15:14:13 +00007466Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00007467 flags = Code::RemoveTypeFromFlags(flags);
7468 Object* result = LookupDefaultCache(name, flags);
7469 if (result->IsCode()) return result;
7470 return LookupNormalTypeCache(name, flags);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007471}
7472
7473
ulan@chromium.org750145a2013-03-07 15:14:13 +00007474Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007475 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007477 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
7478 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00007479 // Skip deleted elements.
7480 if (key->IsNull()) continue;
7481 if (key->IsUndefined()) return key;
ulan@chromium.org750145a2013-03-07 15:14:13 +00007482 if (name->Equals(Name::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007483 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00007484 if (Code::RemoveTypeFromFlags(code->flags()) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007485 return code;
7486 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487 }
7488 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007489 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490}
7491
7492
ulan@chromium.org750145a2013-03-07 15:14:13 +00007493Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007494 if (!normal_type_cache()->IsUndefined()) {
7495 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
7496 return cache->Lookup(name, flags);
7497 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007498 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007499 }
7500}
7501
7502
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00007503int CodeCache::GetIndex(Object* name, Code* code) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007504 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007505 if (normal_type_cache()->IsUndefined()) return -1;
7506 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
ulan@chromium.org750145a2013-03-07 15:14:13 +00007507 return cache->GetIndex(Name::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007508 }
7509
7510 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007511 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007512 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
7513 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007514 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007515 return -1;
7516}
7517
7518
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00007519void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00007520 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007521 ASSERT(!normal_type_cache()->IsUndefined());
7522 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
ulan@chromium.org750145a2013-03-07 15:14:13 +00007523 ASSERT(cache->GetIndex(Name::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007524 cache->RemoveByIndex(index);
7525 } else {
7526 FixedArray* array = default_cache();
7527 ASSERT(array->length() >= index && array->get(index)->IsCode());
7528 // Use null instead of undefined for deleted elements to distinguish
7529 // deleted elements from unused elements. This distinction is used
7530 // when looking up in the cache and when updating the cache.
7531 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
7532 array->set_null(index - 1); // Name.
7533 array->set_null(index); // Code.
7534 }
7535}
7536
7537
7538// The key in the code cache hash table consists of the property name and the
7539// code object. The actual match is on the name and the code flags. If a key
7540// is created using the flags and not a code object it can only be used for
7541// lookup not to create a new entry.
7542class CodeCacheHashTableKey : public HashTableKey {
7543 public:
ulan@chromium.org750145a2013-03-07 15:14:13 +00007544 CodeCacheHashTableKey(Name* name, Code::Flags flags)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007545 : name_(name), flags_(flags), code_(NULL) { }
7546
ulan@chromium.org750145a2013-03-07 15:14:13 +00007547 CodeCacheHashTableKey(Name* name, Code* code)
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00007548 : name_(name), flags_(code->flags()), code_(code) { }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007549
7550
7551 bool IsMatch(Object* other) {
7552 if (!other->IsFixedArray()) return false;
7553 FixedArray* pair = FixedArray::cast(other);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007554 Name* name = Name::cast(pair->get(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007555 Code::Flags flags = Code::cast(pair->get(1))->flags();
7556 if (flags != flags_) {
7557 return false;
7558 }
7559 return name_->Equals(name);
7560 }
7561
ulan@chromium.org750145a2013-03-07 15:14:13 +00007562 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007563 return name->Hash() ^ flags;
7564 }
7565
7566 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
7567
7568 uint32_t HashForObject(Object* obj) {
7569 FixedArray* pair = FixedArray::cast(obj);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007570 Name* name = Name::cast(pair->get(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007571 Code* code = Code::cast(pair->get(1));
7572 return NameFlagsHashHelper(name, code->flags());
7573 }
7574
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007575 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007576 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007577 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007578 { MaybeObject* maybe_obj = heap->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007579 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7580 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007581 FixedArray* pair = FixedArray::cast(obj);
7582 pair->set(0, name_);
7583 pair->set(1, code_);
7584 return pair;
7585 }
7586
7587 private:
ulan@chromium.org750145a2013-03-07 15:14:13 +00007588 Name* name_;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007589 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007590 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007591 Code* code_;
7592};
7593
7594
ulan@chromium.org750145a2013-03-07 15:14:13 +00007595Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007596 CodeCacheHashTableKey key(name, flags);
7597 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007598 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007599 return get(EntryToIndex(entry) + 1);
7600}
7601
7602
ulan@chromium.org750145a2013-03-07 15:14:13 +00007603MaybeObject* CodeCacheHashTable::Put(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007604 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007605 Object* obj;
7606 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
7607 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7608 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007609
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007610 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007611 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
7612
7613 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007614 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007615 { MaybeObject* maybe_k = key.AsObject(GetHeap());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007616 if (!maybe_k->ToObject(&k)) return maybe_k;
7617 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007618
7619 cache->set(EntryToIndex(entry), k);
7620 cache->set(EntryToIndex(entry) + 1, code);
7621 cache->ElementAdded();
7622 return cache;
7623}
7624
7625
ulan@chromium.org750145a2013-03-07 15:14:13 +00007626int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007627 CodeCacheHashTableKey key(name, flags);
7628 int entry = FindEntry(&key);
7629 return (entry == kNotFound) ? -1 : entry;
7630}
7631
7632
7633void CodeCacheHashTable::RemoveByIndex(int index) {
7634 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007635 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007636 set(EntryToIndex(index), heap->the_hole_value());
7637 set(EntryToIndex(index) + 1, heap->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007638 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639}
7640
7641
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007642void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
7643 MapHandleList* maps,
7644 Code::Flags flags,
7645 Handle<Code> code) {
7646 Isolate* isolate = cache->GetIsolate();
7647 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
7648}
7649
7650
7651MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007652 Code::Flags flags,
7653 Code* code) {
7654 // Initialize cache if necessary.
7655 if (cache()->IsUndefined()) {
7656 Object* result;
7657 { MaybeObject* maybe_result =
7658 PolymorphicCodeCacheHashTable::Allocate(
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007659 GetHeap(),
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007660 PolymorphicCodeCacheHashTable::kInitialSize);
7661 if (!maybe_result->ToObject(&result)) return maybe_result;
7662 }
7663 set_cache(result);
7664 } else {
7665 // This entry shouldn't be contained in the cache yet.
7666 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
7667 ->Lookup(maps, flags)->IsUndefined());
7668 }
7669 PolymorphicCodeCacheHashTable* hash_table =
7670 PolymorphicCodeCacheHashTable::cast(cache());
7671 Object* new_cache;
7672 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
7673 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
7674 }
7675 set_cache(new_cache);
7676 return this;
7677}
7678
7679
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007680Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
7681 Code::Flags flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007682 if (!cache()->IsUndefined()) {
7683 PolymorphicCodeCacheHashTable* hash_table =
7684 PolymorphicCodeCacheHashTable::cast(cache());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007685 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007686 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007687 return GetIsolate()->factory()->undefined_value();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007688 }
7689}
7690
7691
7692// Despite their name, object of this class are not stored in the actual
7693// hash table; instead they're temporarily used for lookups. It is therefore
7694// safe to have a weak (non-owning) pointer to a MapList as a member field.
7695class PolymorphicCodeCacheHashTableKey : public HashTableKey {
7696 public:
7697 // Callers must ensure that |maps| outlives the newly constructed object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007698 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007699 : maps_(maps),
7700 code_flags_(code_flags) {}
7701
7702 bool IsMatch(Object* other) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007703 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007704 int other_flags;
7705 FromObject(other, &other_flags, &other_maps);
7706 if (code_flags_ != other_flags) return false;
7707 if (maps_->length() != other_maps.length()) return false;
7708 // Compare just the hashes first because it's faster.
7709 int this_hash = MapsHashHelper(maps_, code_flags_);
7710 int other_hash = MapsHashHelper(&other_maps, other_flags);
7711 if (this_hash != other_hash) return false;
7712
7713 // Full comparison: for each map in maps_, look for an equivalent map in
7714 // other_maps. This implementation is slow, but probably good enough for
7715 // now because the lists are short (<= 4 elements currently).
7716 for (int i = 0; i < maps_->length(); ++i) {
7717 bool match_found = false;
7718 for (int j = 0; j < other_maps.length(); ++j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00007719 if (*(maps_->at(i)) == *(other_maps.at(j))) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007720 match_found = true;
7721 break;
7722 }
7723 }
7724 if (!match_found) return false;
7725 }
7726 return true;
7727 }
7728
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007729 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007730 uint32_t hash = code_flags;
7731 for (int i = 0; i < maps->length(); ++i) {
7732 hash ^= maps->at(i)->Hash();
7733 }
7734 return hash;
7735 }
7736
7737 uint32_t Hash() {
7738 return MapsHashHelper(maps_, code_flags_);
7739 }
7740
7741 uint32_t HashForObject(Object* obj) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007742 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007743 int other_flags;
7744 FromObject(obj, &other_flags, &other_maps);
7745 return MapsHashHelper(&other_maps, other_flags);
7746 }
7747
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007748 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007749 Object* obj;
7750 // The maps in |maps_| must be copied to a newly allocated FixedArray,
7751 // both because the referenced MapList is short-lived, and because C++
7752 // objects can't be stored in the heap anyway.
7753 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007754 heap->AllocateUninitializedFixedArray(maps_->length() + 1);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007755 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7756 }
7757 FixedArray* list = FixedArray::cast(obj);
7758 list->set(0, Smi::FromInt(code_flags_));
7759 for (int i = 0; i < maps_->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007760 list->set(i + 1, *maps_->at(i));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007761 }
7762 return list;
7763 }
7764
7765 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007766 static MapHandleList* FromObject(Object* obj,
7767 int* code_flags,
7768 MapHandleList* maps) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007769 FixedArray* list = FixedArray::cast(obj);
7770 maps->Rewind(0);
7771 *code_flags = Smi::cast(list->get(0))->value();
7772 for (int i = 1; i < list->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007773 maps->Add(Handle<Map>(Map::cast(list->get(i))));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007774 }
7775 return maps;
7776 }
7777
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007778 MapHandleList* maps_; // weak.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007779 int code_flags_;
whesse@chromium.org7b260152011-06-20 15:33:18 +00007780 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007781};
7782
7783
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007784Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
7785 int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007786 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
7787 int entry = FindEntry(&key);
7788 if (entry == kNotFound) return GetHeap()->undefined_value();
7789 return get(EntryToIndex(entry) + 1);
7790}
7791
7792
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007793MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007794 int code_flags,
7795 Code* code) {
7796 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
7797 Object* obj;
7798 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
7799 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7800 }
7801 PolymorphicCodeCacheHashTable* cache =
7802 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
7803 int entry = cache->FindInsertionEntry(key.Hash());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007804 { MaybeObject* maybe_obj = key.AsObject(GetHeap());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007805 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7806 }
7807 cache->set(EntryToIndex(entry), obj);
7808 cache->set(EntryToIndex(entry) + 1, code);
7809 cache->ElementAdded();
7810 return cache;
7811}
7812
7813
lrn@chromium.org303ada72010-10-27 09:33:13 +00007814MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007815 ElementsAccessor* accessor = array->GetElementsAccessor();
7816 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007817 accessor->AddElementsToFixedArray(array, array, this);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007818 FixedArray* result;
7819 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
7820#ifdef DEBUG
7821 if (FLAG_enable_slow_asserts) {
7822 for (int i = 0; i < result->length(); i++) {
7823 Object* current = result->get(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007824 ASSERT(current->IsNumber() || current->IsName());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007825 }
7826 }
7827#endif
7828 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007829}
7830
7831
lrn@chromium.org303ada72010-10-27 09:33:13 +00007832MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007833 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
7834 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007835 accessor->AddElementsToFixedArray(NULL, NULL, this, other);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007836 FixedArray* result;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00007837 if (!maybe_result->To(&result)) return maybe_result;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007838#ifdef DEBUG
7839 if (FLAG_enable_slow_asserts) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007840 for (int i = 0; i < result->length(); i++) {
7841 Object* current = result->get(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007842 ASSERT(current->IsNumber() || current->IsName());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007843 }
7844 }
7845#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007846 return result;
7847}
7848
7849
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00007850MaybeObject* FixedArray::CopySize(int new_length, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007851 Heap* heap = GetHeap();
7852 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007853 Object* obj;
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +00007854 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length, pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007855 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7856 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007858 // Copy the content
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007859 DisallowHeapAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007860 int len = length();
7861 if (new_length < len) len = new_length;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007862 // We are taking the map from the old fixed array so the map is sure to
7863 // be an immortal immutable object.
7864 result->set_map_no_write_barrier(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007865 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007866 for (int i = 0; i < len; i++) {
7867 result->set(i, get(i), mode);
7868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869 return result;
7870}
7871
7872
7873void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00007874 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007875 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007876 for (int index = 0; index < len; index++) {
7877 dest->set(dest_pos+index, get(pos+index), mode);
7878 }
7879}
7880
7881
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007882#ifdef DEBUG
7883bool FixedArray::IsEqualTo(FixedArray* other) {
7884 if (length() != other->length()) return false;
7885 for (int i = 0 ; i < length(); ++i) {
7886 if (get(i) != other->get(i)) return false;
7887 }
7888 return true;
7889}
7890#endif
7891
7892
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007893MaybeObject* DescriptorArray::Allocate(Isolate* isolate,
7894 int number_of_descriptors,
7895 int slack) {
7896 Heap* heap = isolate->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007897 // Do not use DescriptorArray::cast on incomplete object.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007898 int size = number_of_descriptors + slack;
7899 if (size == 0) return heap->empty_descriptor_array();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007900 FixedArray* result;
verwaest@chromium.org50915592012-06-18 12:15:44 +00007901 // Allocate the array of keys.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007902 MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size));
danno@chromium.org129d3982012-07-25 15:01:47 +00007903 if (!maybe_array->To(&result)) return maybe_array;
verwaest@chromium.org50915592012-06-18 12:15:44 +00007904
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007905 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007906 result->set(kEnumCacheIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007907 return result;
7908}
7909
7910
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007911void DescriptorArray::ClearEnumCache() {
7912 set(kEnumCacheIndex, Smi::FromInt(0));
7913}
7914
7915
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007916void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007917 FixedArray* new_cache,
7918 Object* new_index_cache) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007920 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007921 ASSERT(!IsEmpty());
7922 ASSERT(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
7923 FixedArray::cast(bridge_storage)->
7924 set(kEnumCacheBridgeCacheIndex, new_cache);
7925 FixedArray::cast(bridge_storage)->
7926 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
7927 set(kEnumCacheIndex, bridge_storage);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007928}
7929
7930
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007931void DescriptorArray::CopyFrom(int dst_index,
7932 DescriptorArray* src,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007933 int src_index,
7934 const WhitenessWitness& witness) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007935 Object* value = src->GetValue(src_index);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00007936 PropertyDetails details = src->GetDetails(src_index);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007937 Descriptor desc(src->GetKey(src_index), value, details);
7938 Set(dst_index, &desc, witness);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007939}
7940
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941
machenbach@chromium.org528ce022013-09-23 14:09:36 +00007942Handle<DescriptorArray> DescriptorArray::Merge(Handle<DescriptorArray> desc,
7943 int verbatim,
7944 int valid,
7945 int new_size,
7946 int modify_index,
7947 StoreMode store_mode,
7948 Handle<DescriptorArray> other) {
7949 CALL_HEAP_FUNCTION(desc->GetIsolate(),
7950 desc->Merge(verbatim, valid, new_size, modify_index,
7951 store_mode, *other),
7952 DescriptorArray);
7953}
7954
7955
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007956// Generalize the |other| descriptor array by merging it into the (at least
danno@chromium.orgf005df62013-04-30 16:36:45 +00007957// partly) updated |this| descriptor array.
7958// The method merges two descriptor array in three parts. Both descriptor arrays
7959// are identical up to |verbatim|. They also overlap in keys up to |valid|.
7960// Between |verbatim| and |valid|, the resulting descriptor type as well as the
7961// representation are generalized from both |this| and |other|. Beyond |valid|,
7962// the descriptors are copied verbatim from |other| up to |new_size|.
7963// In case of incompatible types, the type and representation of |other| is
7964// used.
7965MaybeObject* DescriptorArray::Merge(int verbatim,
7966 int valid,
7967 int new_size,
rossberg@chromium.org92597162013-08-23 13:28:00 +00007968 int modify_index,
7969 StoreMode store_mode,
danno@chromium.orgf005df62013-04-30 16:36:45 +00007970 DescriptorArray* other) {
7971 ASSERT(verbatim <= valid);
7972 ASSERT(valid <= new_size);
7973
7974 DescriptorArray* result;
7975 // Allocate a new descriptor array large enough to hold the required
7976 // descriptors, with minimally the exact same size as this descriptor array.
7977 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00007978 GetIsolate(), new_size,
7979 Max(new_size, other->number_of_descriptors()) - new_size);
danno@chromium.orgf005df62013-04-30 16:36:45 +00007980 if (!maybe_descriptors->To(&result)) return maybe_descriptors;
7981 ASSERT(result->length() > length() ||
7982 result->NumberOfSlackDescriptors() > 0 ||
7983 result->number_of_descriptors() == other->number_of_descriptors());
7984 ASSERT(result->number_of_descriptors() == new_size);
7985
7986 DescriptorArray::WhitenessWitness witness(result);
7987
7988 int descriptor;
7989
7990 // 0 -> |verbatim|
7991 int current_offset = 0;
7992 for (descriptor = 0; descriptor < verbatim; descriptor++) {
7993 if (GetDetails(descriptor).type() == FIELD) current_offset++;
hpayer@chromium.org2311a912013-08-28 13:39:38 +00007994 result->CopyFrom(descriptor, other, descriptor, witness);
danno@chromium.orgf005df62013-04-30 16:36:45 +00007995 }
7996
7997 // |verbatim| -> |valid|
7998 for (; descriptor < valid; descriptor++) {
7999 Name* key = GetKey(descriptor);
8000 PropertyDetails details = GetDetails(descriptor);
8001 PropertyDetails other_details = other->GetDetails(descriptor);
danno@chromium.orgf005df62013-04-30 16:36:45 +00008002
8003 if (details.type() == FIELD || other_details.type() == FIELD ||
rossberg@chromium.org92597162013-08-23 13:28:00 +00008004 (store_mode == FORCE_FIELD && descriptor == modify_index) ||
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00008005 (details.type() == CONSTANT &&
8006 other_details.type() == CONSTANT &&
danno@chromium.orgf005df62013-04-30 16:36:45 +00008007 GetValue(descriptor) != other->GetValue(descriptor))) {
8008 Representation representation =
8009 details.representation().generalize(other_details.representation());
8010 FieldDescriptor d(key,
8011 current_offset++,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008012 other_details.attributes(),
8013 representation);
danno@chromium.orgf005df62013-04-30 16:36:45 +00008014 result->Set(descriptor, &d, witness);
8015 } else {
8016 result->CopyFrom(descriptor, other, descriptor, witness);
8017 }
8018 }
8019
8020 // |valid| -> |new_size|
8021 for (; descriptor < new_size; descriptor++) {
8022 PropertyDetails details = other->GetDetails(descriptor);
rossberg@chromium.org92597162013-08-23 13:28:00 +00008023 if (details.type() == FIELD ||
8024 (store_mode == FORCE_FIELD && descriptor == modify_index)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00008025 Name* key = other->GetKey(descriptor);
8026 FieldDescriptor d(key,
8027 current_offset++,
8028 details.attributes(),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008029 details.representation());
danno@chromium.orgf005df62013-04-30 16:36:45 +00008030 result->Set(descriptor, &d, witness);
8031 } else {
8032 result->CopyFrom(descriptor, other, descriptor, witness);
8033 }
8034 }
8035
8036 result->Sort();
8037 return result;
8038}
8039
8040
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008041// Checks whether a merge of |other| into |this| would return a copy of |this|.
8042bool DescriptorArray::IsMoreGeneralThan(int verbatim,
8043 int valid,
8044 int new_size,
8045 DescriptorArray* other) {
8046 ASSERT(verbatim <= valid);
8047 ASSERT(valid <= new_size);
8048 if (valid != new_size) return false;
8049
8050 for (int descriptor = verbatim; descriptor < valid; descriptor++) {
8051 PropertyDetails details = GetDetails(descriptor);
8052 PropertyDetails other_details = other->GetDetails(descriptor);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00008053 if (!other_details.representation().fits_into(details.representation())) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008054 return false;
8055 }
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00008056 if (details.type() == CONSTANT) {
8057 if (other_details.type() != CONSTANT) return false;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00008058 if (GetValue(descriptor) != other->GetValue(descriptor)) return false;
8059 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00008060 }
8061
8062 return true;
8063}
8064
8065
verwaest@chromium.org37141392012-05-31 13:27:02 +00008066// We need the whiteness witness since sort will reshuffle the entries in the
8067// descriptor array. If the descriptor array were to be black, the shuffling
8068// would move a slot that was already recorded as pointing into an evacuation
8069// candidate. This would result in missing updates upon evacuation.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008070void DescriptorArray::Sort() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 // In-place heap sort.
8072 int len = number_of_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008073 // Reset sorting since the descriptor array might contain invalid pointers.
8074 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008075 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008076 // Index of the last node with children
8077 const int max_parent_index = (len / 2) - 1;
8078 for (int i = max_parent_index; i >= 0; --i) {
8079 int parent_index = i;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008080 const uint32_t parent_hash = GetSortedKey(i)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008081 while (parent_index <= max_parent_index) {
8082 int child_index = 2 * parent_index + 1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008083 uint32_t child_hash = GetSortedKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008084 if (child_index + 1 < len) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008085 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008086 if (right_child_hash > child_hash) {
8087 child_index++;
8088 child_hash = right_child_hash;
8089 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008091 if (child_hash <= parent_hash) break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008092 SwapSortedKeys(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008093 // Now element at child_index could be < its children.
8094 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095 }
8096 }
8097
8098 // Extract elements and create sorted array.
8099 for (int i = len - 1; i > 0; --i) {
8100 // Put max element at the back of the array.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008101 SwapSortedKeys(0, i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008102 // Shift down the new top element.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008103 int parent_index = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008104 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008105 const int max_parent_index = (i / 2) - 1;
8106 while (parent_index <= max_parent_index) {
8107 int child_index = parent_index * 2 + 1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008108 uint32_t child_hash = GetSortedKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008109 if (child_index + 1 < i) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008110 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008111 if (right_child_hash > child_hash) {
8112 child_index++;
8113 child_hash = right_child_hash;
8114 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008115 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008116 if (child_hash <= parent_hash) break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008117 SwapSortedKeys(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008118 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008119 }
8120 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008121 ASSERT(IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008122}
8123
8124
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00008125Handle<AccessorPair> AccessorPair::Copy(Handle<AccessorPair> pair) {
8126 Handle<AccessorPair> copy = pair->GetIsolate()->factory()->NewAccessorPair();
8127 copy->set_getter(pair->getter());
8128 copy->set_setter(pair->setter());
ulan@chromium.org65a89c22012-02-14 11:46:07 +00008129 return copy;
8130}
8131
8132
danno@chromium.org88aa0582012-03-23 15:11:57 +00008133Object* AccessorPair::GetComponent(AccessorComponent component) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00008134 Object* accessor = get(component);
8135 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00008136}
8137
8138
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008139MaybeObject* DeoptimizationInputData::Allocate(Isolate* isolate,
8140 int deopt_entry_count,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008141 PretenureFlag pretenure) {
8142 ASSERT(deopt_entry_count > 0);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008143 return isolate->heap()->AllocateFixedArray(LengthFor(deopt_entry_count),
8144 pretenure);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008145}
8146
8147
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008148MaybeObject* DeoptimizationOutputData::Allocate(Isolate* isolate,
8149 int number_of_deopt_points,
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008150 PretenureFlag pretenure) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00008151 if (number_of_deopt_points == 0) return isolate->heap()->empty_fixed_array();
8152 return isolate->heap()->AllocateFixedArray(
8153 LengthOfFixedArray(number_of_deopt_points), pretenure);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008154}
8155
8156
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008157#ifdef DEBUG
8158bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
8159 if (IsEmpty()) return other->IsEmpty();
8160 if (other->IsEmpty()) return false;
8161 if (length() != other->length()) return false;
8162 for (int i = 0; i < length(); ++i) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00008163 if (get(i) != other->get(i)) return false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008164 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00008165 return true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008166}
8167#endif
8168
8169
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00008170static bool IsIdentifier(UnicodeCache* cache, Name* name) {
8171 // Checks whether the buffer contains an identifier (no escape).
8172 if (!name->IsString()) return false;
8173 String* string = String::cast(name);
8174 if (string->length() == 0) return false;
8175 ConsStringIteratorOp op;
8176 StringCharacterStream stream(string, &op);
8177 if (!cache->IsIdentifierStart(stream.GetNext())) {
8178 return false;
8179 }
8180 while (stream.HasMore()) {
8181 if (!cache->IsIdentifierPart(stream.GetNext())) {
8182 return false;
8183 }
8184 }
8185 return true;
8186}
8187
8188
8189bool Name::IsCacheable(Isolate* isolate) {
8190 return IsSymbol() ||
8191 IsIdentifier(isolate->unicode_cache(), this) ||
8192 this == isolate->heap()->hidden_string();
8193}
8194
8195
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008196bool String::LooksValid() {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008197 if (!GetIsolate()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00008198 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008199}
8200
8201
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008202String::FlatContent String::GetFlatContent() {
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008203 ASSERT(!AllowHeapAllocation::IsAllowed());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008204 int length = this->length();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008205 StringShape shape(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00008206 String* string = this;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008207 int offset = 0;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008208 if (shape.representation_tag() == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008209 ConsString* cons = ConsString::cast(string);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008210 if (cons->second()->length() != 0) {
8211 return FlatContent();
8212 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00008213 string = cons->first();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008214 shape = StringShape(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +00008215 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008216 if (shape.representation_tag() == kSlicedStringTag) {
8217 SlicedString* slice = SlicedString::cast(string);
8218 offset = slice->offset();
8219 string = slice->parent();
8220 shape = StringShape(string);
8221 ASSERT(shape.representation_tag() != kConsStringTag &&
8222 shape.representation_tag() != kSlicedStringTag);
8223 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008224 if (shape.encoding_tag() == kOneByteStringTag) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008225 const uint8_t* start;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008226 if (shape.representation_tag() == kSeqStringTag) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008227 start = SeqOneByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008228 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00008229 start = ExternalAsciiString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008230 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008231 return FlatContent(Vector<const uint8_t>(start + offset, length));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008232 } else {
8233 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
8234 const uc16* start;
8235 if (shape.representation_tag() == kSeqStringTag) {
8236 start = SeqTwoByteString::cast(string)->GetChars();
8237 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00008238 start = ExternalTwoByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008239 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008240 return FlatContent(Vector<const uc16>(start + offset, length));
ager@chromium.org7c537e22008-10-16 08:43:32 +00008241 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00008242}
8243
8244
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008245SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8246 RobustnessFlag robust_flag,
8247 int offset,
8248 int length,
8249 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008250 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008251 return SmartArrayPointer<char>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008252 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008253 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008254
8255 // Negative length means the to the end of the string.
8256 if (length < 0) length = kMaxInt - offset;
8257
8258 // Compute the size of the UTF-8 string. Start at the specified offset.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008259 Access<ConsStringIteratorOp> op(
8260 heap->isolate()->objects_string_iterator());
8261 StringCharacterStream stream(this, op.value(), offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008262 int character_position = offset;
8263 int utf8_bytes = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008264 int last = unibrow::Utf16::kNoPreviousCharacter;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008265 while (stream.HasMore() && character_position++ < offset + length) {
8266 uint16_t character = stream.GetNext();
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008267 utf8_bytes += unibrow::Utf8::Length(character, last);
8268 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 }
8270
8271 if (length_return) {
8272 *length_return = utf8_bytes;
8273 }
8274
8275 char* result = NewArray<char>(utf8_bytes + 1);
8276
8277 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008278 stream.Reset(this, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008279 character_position = offset;
8280 int utf8_byte_position = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008281 last = unibrow::Utf16::kNoPreviousCharacter;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008282 while (stream.HasMore() && character_position++ < offset + length) {
8283 uint16_t character = stream.GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00008284 if (allow_nulls == DISALLOW_NULLS && character == 0) {
8285 character = ' ';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00008287 utf8_byte_position +=
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008288 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
8289 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008290 }
8291 result[utf8_byte_position] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008292 return SmartArrayPointer<char>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008293}
8294
8295
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008296SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
8297 RobustnessFlag robust_flag,
8298 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008299 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
8300}
8301
8302
8303const uc16* String::GetTwoByteData() {
8304 return GetTwoByteData(0);
8305}
8306
8307
8308const uc16* String::GetTwoByteData(unsigned start) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00008309 ASSERT(!IsOneByteRepresentationUnderneath());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008310 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00008312 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 case kExternalStringTag:
8314 return ExternalTwoByteString::cast(this)->
8315 ExternalTwoByteStringGetData(start);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008316 case kSlicedStringTag: {
8317 SlicedString* slice = SlicedString::cast(this);
8318 return slice->parent()->GetTwoByteData(start + slice->offset());
8319 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320 case kConsStringTag:
8321 UNREACHABLE();
8322 return NULL;
8323 }
8324 UNREACHABLE();
8325 return NULL;
8326}
8327
8328
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008329SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008331 return SmartArrayPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008333 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008334
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008335 Access<ConsStringIteratorOp> op(
8336 heap->isolate()->objects_string_iterator());
8337 StringCharacterStream stream(this, op.value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008338
8339 uc16* result = NewArray<uc16>(length() + 1);
8340
8341 int i = 0;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008342 while (stream.HasMore()) {
8343 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 result[i++] = character;
8345 }
8346 result[i] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008347 return SmartArrayPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008348}
8349
8350
ager@chromium.org7c537e22008-10-16 08:43:32 +00008351const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352 return reinterpret_cast<uc16*>(
8353 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
8354}
8355
8356
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008357void Relocatable::PostGarbageCollectionProcessing(Isolate* isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008358 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008359 while (current != NULL) {
8360 current->PostGarbageCollection();
8361 current = current->prev_;
8362 }
8363}
8364
8365
8366// Reserve space for statics needing saving and restoring.
8367int Relocatable::ArchiveSpacePerThread() {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008368 return sizeof(Relocatable*); // NOLINT
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008369}
8370
8371
8372// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008373char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008374 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
8375 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008376 return to + ArchiveSpacePerThread();
8377}
8378
8379
8380// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008381char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008382 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008383 return from + ArchiveSpacePerThread();
8384}
8385
8386
8387char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
8388 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
8389 Iterate(v, top);
8390 return thread_storage + ArchiveSpacePerThread();
8391}
8392
8393
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00008394void Relocatable::Iterate(Isolate* isolate, ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008395 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008396}
8397
8398
8399void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
8400 Relocatable* current = top;
8401 while (current != NULL) {
8402 current->IterateInstance(v);
8403 current = current->prev_;
8404 }
8405}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008406
8407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008408FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
8409 : Relocatable(isolate),
8410 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008411 length_(str->length()) {
8412 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008413}
8414
8415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008416FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
8417 : Relocatable(isolate),
8418 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008419 is_ascii_(true),
8420 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008421 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008422
8423
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008424void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008425 if (str_ == NULL) return;
8426 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008427 ASSERT(str->IsFlat());
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008428 DisallowHeapAllocation no_gc;
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00008429 // This does not actually prevent the vector from being relocated later.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008430 String::FlatContent content = str->GetFlatContent();
8431 ASSERT(content.IsFlat());
8432 is_ascii_ = content.IsAscii();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008433 if (is_ascii_) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008434 start_ = content.ToOneByteVector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008435 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008436 start_ = content.ToUC16Vector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008437 }
8438}
8439
8440
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008441String* ConsStringIteratorOp::Operate(String* string,
8442 unsigned* offset_out,
8443 int32_t* type_out,
8444 unsigned* length_out) {
8445 ASSERT(string->IsConsString());
8446 ConsString* cons_string = ConsString::cast(string);
8447 // Set up search data.
8448 root_ = cons_string;
8449 consumed_ = *offset_out;
8450 // Now search.
8451 return Search(offset_out, type_out, length_out);
8452}
8453
8454
8455String* ConsStringIteratorOp::Search(unsigned* offset_out,
8456 int32_t* type_out,
8457 unsigned* length_out) {
8458 ConsString* cons_string = root_;
8459 // Reset the stack, pushing the root string.
8460 depth_ = 1;
8461 maximum_depth_ = 1;
8462 frames_[0] = cons_string;
8463 const unsigned consumed = consumed_;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008464 unsigned offset = 0;
8465 while (true) {
8466 // Loop until the string is found which contains the target offset.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008467 String* string = cons_string->first();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008468 unsigned length = string->length();
8469 int32_t type;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008470 if (consumed < offset + length) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008471 // Target offset is in the left branch.
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008472 // Keep going if we're still in a ConString.
8473 type = string->map()->instance_type();
8474 if ((type & kStringRepresentationMask) == kConsStringTag) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008475 cons_string = ConsString::cast(string);
8476 PushLeft(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008477 continue;
8478 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008479 // Tell the stack we're done decending.
8480 AdjustMaximumDepth();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008481 } else {
8482 // Descend right.
8483 // Update progress through the string.
8484 offset += length;
8485 // Keep going if we're still in a ConString.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008486 string = cons_string->second();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008487 type = string->map()->instance_type();
8488 if ((type & kStringRepresentationMask) == kConsStringTag) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008489 cons_string = ConsString::cast(string);
8490 PushRight(cons_string);
8491 // TODO(dcarney) Add back root optimization.
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008492 continue;
8493 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008494 // Need this to be updated for the current string.
8495 length = string->length();
8496 // Account for the possibility of an empty right leaf.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008497 // This happens only if we have asked for an offset outside the string.
8498 if (length == 0) {
8499 // Reset depth so future operations will return null immediately.
8500 Reset();
8501 return NULL;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008502 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008503 // Tell the stack we're done decending.
8504 AdjustMaximumDepth();
8505 // Pop stack so next iteration is in correct place.
8506 Pop();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008507 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008508 ASSERT(length != 0);
8509 // Adjust return values and exit.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008510 consumed_ = offset + length;
8511 *offset_out = consumed - offset;
8512 *type_out = type;
8513 *length_out = length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008514 return string;
8515 }
8516 UNREACHABLE();
8517 return NULL;
8518}
8519
8520
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008521String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
8522 int32_t* type_out,
8523 unsigned* length_out) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008524 while (true) {
8525 // Tree traversal complete.
8526 if (depth_ == 0) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008527 *blew_stack = false;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008528 return NULL;
8529 }
8530 // We've lost track of higher nodes.
8531 if (maximum_depth_ - depth_ == kStackSize) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008532 *blew_stack = true;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008533 return NULL;
8534 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008535 // Go right.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008536 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
8537 String* string = cons_string->second();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008538 int32_t type = string->map()->instance_type();
8539 if ((type & kStringRepresentationMask) != kConsStringTag) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008540 // Pop stack so next iteration is in correct place.
8541 Pop();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008542 unsigned length = static_cast<unsigned>(string->length());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008543 // Could be a flattened ConsString.
8544 if (length == 0) continue;
8545 *length_out = length;
8546 *type_out = type;
8547 consumed_ += length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008548 return string;
8549 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008550 cons_string = ConsString::cast(string);
8551 // TODO(dcarney) Add back root optimization.
8552 PushRight(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008553 // Need to traverse all the way left.
8554 while (true) {
8555 // Continue left.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008556 string = cons_string->first();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008557 type = string->map()->instance_type();
8558 if ((type & kStringRepresentationMask) != kConsStringTag) {
8559 AdjustMaximumDepth();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008560 unsigned length = static_cast<unsigned>(string->length());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008561 ASSERT(length != 0);
8562 *length_out = length;
8563 *type_out = type;
8564 consumed_ += length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008565 return string;
8566 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008567 cons_string = ConsString::cast(string);
8568 PushLeft(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008569 }
8570 }
8571 UNREACHABLE();
8572 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008573}
8574
8575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576uint16_t ConsString::ConsStringGet(int index) {
8577 ASSERT(index >= 0 && index < this->length());
8578
8579 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00008580 if (second()->length() == 0) {
8581 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008582 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 }
8584
8585 String* string = String::cast(this);
8586
8587 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008588 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00008590 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008591 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008592 string = left;
8593 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008594 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00008595 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008596 }
8597 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008598 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599 }
8600 }
8601
8602 UNREACHABLE();
8603 return 0;
8604}
8605
8606
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008607uint16_t SlicedString::SlicedStringGet(int index) {
8608 return parent()->Get(offset() + index);
8609}
8610
8611
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008612template <typename sinkchar>
8613void String::WriteToFlat(String* src,
8614 sinkchar* sink,
8615 int f,
8616 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617 String* source = src;
8618 int from = f;
8619 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008620 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008621 ASSERT(0 <= from && from <= to && to <= source->length());
8622 switch (StringShape(source).full_representation_tag()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008623 case kOneByteStringTag | kExternalStringTag: {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008624 CopyChars(sink,
erikcorry0ad885c2011-11-21 13:51:57 +00008625 ExternalAsciiString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008626 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008627 return;
8628 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008629 case kTwoByteStringTag | kExternalStringTag: {
8630 const uc16* data =
erikcorry0ad885c2011-11-21 13:51:57 +00008631 ExternalTwoByteString::cast(source)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008632 CopyChars(sink,
8633 data + from,
8634 to - from);
8635 return;
8636 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008637 case kOneByteStringTag | kSeqStringTag: {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008638 CopyChars(sink,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008639 SeqOneByteString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008640 to - from);
8641 return;
8642 }
8643 case kTwoByteStringTag | kSeqStringTag: {
8644 CopyChars(sink,
8645 SeqTwoByteString::cast(source)->GetChars() + from,
8646 to - from);
8647 return;
8648 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008649 case kOneByteStringTag | kConsStringTag:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008650 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00008652 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008653 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00008654 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655 // Right hand side is longer. Recurse over left.
8656 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008657 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008658 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659 from = 0;
8660 } else {
8661 from -= boundary;
8662 }
8663 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00008664 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008665 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008666 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00008668 String* second = cons_string->second();
ulan@chromium.org812308e2012-02-29 15:58:45 +00008669 // When repeatedly appending to a string, we get a cons string that
8670 // is unbalanced to the left, a list, essentially. We inline the
8671 // common case of sequential ascii right child.
8672 if (to - boundary == 1) {
8673 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008674 } else if (second->IsSeqOneByteString()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00008675 CopyChars(sink + boundary - from,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008676 SeqOneByteString::cast(second)->GetChars(),
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008677 to - boundary);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008678 } else {
8679 WriteToFlat(second,
8680 sink + boundary - from,
8681 0,
8682 to - boundary);
8683 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 to = boundary;
8685 }
8686 source = first;
8687 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008688 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008689 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008690 case kOneByteStringTag | kSlicedStringTag:
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008691 case kTwoByteStringTag | kSlicedStringTag: {
8692 SlicedString* slice = SlicedString::cast(source);
8693 unsigned offset = slice->offset();
8694 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8695 return;
8696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697 }
8698 }
8699}
8700
8701
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008702// Compares the contents of two strings by reading and comparing
8703// int-sized blocks of characters.
8704template <typename Char>
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008705static inline bool CompareRawStringContents(const Char* const a,
8706 const Char* const b,
8707 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008708 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00008709#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008710 // If this architecture isn't comfortable reading unaligned ints
8711 // then we have to check that the strings are aligned before
8712 // comparing them blockwise.
8713 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008714 uint32_t pa_addr = reinterpret_cast<uint32_t>(a);
8715 uint32_t pb_addr = reinterpret_cast<uint32_t>(b);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008716 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008717#endif
8718 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
8719 int endpoint = length - kStepSize;
8720 // Compare blocks until we reach near the end of the string.
8721 for (; i <= endpoint; i += kStepSize) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008722 uint32_t wa = *reinterpret_cast<const uint32_t*>(a + i);
8723 uint32_t wb = *reinterpret_cast<const uint32_t*>(b + i);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008724 if (wa != wb) {
8725 return false;
8726 }
8727 }
ager@chromium.org9085a012009-05-11 19:22:57 +00008728#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008729 }
8730#endif
8731 // Compare the remaining characters that didn't fit into a block.
8732 for (; i < length; i++) {
8733 if (a[i] != b[i]) {
8734 return false;
8735 }
8736 }
8737 return true;
8738}
8739
8740
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008741template<typename Chars1, typename Chars2>
8742class RawStringComparator : public AllStatic {
8743 public:
8744 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
8745 ASSERT(sizeof(Chars1) != sizeof(Chars2));
8746 for (int i = 0; i < len; i++) {
8747 if (a[i] != b[i]) {
8748 return false;
8749 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00008750 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008751 return true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00008752 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008753};
8754
8755
8756template<>
8757class RawStringComparator<uint16_t, uint16_t> {
8758 public:
8759 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
8760 return CompareRawStringContents(a, b, len);
8761 }
8762};
8763
8764
8765template<>
8766class RawStringComparator<uint8_t, uint8_t> {
8767 public:
8768 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
8769 return CompareRawStringContents(a, b, len);
8770 }
8771};
8772
8773
8774class StringComparator {
8775 class State {
8776 public:
8777 explicit inline State(ConsStringIteratorOp* op)
8778 : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
8779
8780 inline void Init(String* string, unsigned len) {
8781 op_->Reset();
8782 int32_t type = string->map()->instance_type();
8783 String::Visit(string, 0, *this, *op_, type, len);
8784 }
8785
8786 inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
8787 is_one_byte_ = true;
8788 buffer8_ = chars;
8789 length_ = length;
8790 }
8791
8792 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
8793 is_one_byte_ = false;
8794 buffer16_ = chars;
8795 length_ = length;
8796 }
8797
8798 void Advance(unsigned consumed) {
8799 ASSERT(consumed <= length_);
8800 // Still in buffer.
8801 if (length_ != consumed) {
8802 if (is_one_byte_) {
8803 buffer8_ += consumed;
8804 } else {
8805 buffer16_ += consumed;
8806 }
8807 length_ -= consumed;
8808 return;
8809 }
8810 // Advance state.
8811 ASSERT(op_->HasMore());
8812 int32_t type = 0;
8813 unsigned length = 0;
8814 String* next = op_->ContinueOperation(&type, &length);
8815 ASSERT(next != NULL);
8816 ConsStringNullOp null_op;
8817 String::Visit(next, 0, *this, null_op, type, length);
8818 }
8819
8820 ConsStringIteratorOp* const op_;
8821 bool is_one_byte_;
8822 unsigned length_;
8823 union {
8824 const uint8_t* buffer8_;
8825 const uint16_t* buffer16_;
8826 };
danno@chromium.org1fd77d52013-06-07 16:01:45 +00008827
8828 private:
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008829 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
8830 };
8831
8832 public:
8833 inline StringComparator(ConsStringIteratorOp* op_1,
8834 ConsStringIteratorOp* op_2)
8835 : state_1_(op_1),
8836 state_2_(op_2) {
8837 }
8838
8839 template<typename Chars1, typename Chars2>
8840 static inline bool Equals(State* state_1, State* state_2, unsigned to_check) {
8841 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
8842 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
8843 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
8844 }
8845
8846 bool Equals(unsigned length, String* string_1, String* string_2) {
8847 ASSERT(length != 0);
8848 state_1_.Init(string_1, length);
8849 state_2_.Init(string_2, length);
8850 while (true) {
8851 unsigned to_check = Min(state_1_.length_, state_2_.length_);
8852 ASSERT(to_check > 0 && to_check <= length);
8853 bool is_equal;
8854 if (state_1_.is_one_byte_) {
8855 if (state_2_.is_one_byte_) {
8856 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
8857 } else {
8858 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
8859 }
8860 } else {
8861 if (state_2_.is_one_byte_) {
8862 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
8863 } else {
8864 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
8865 }
8866 }
8867 // Looping done.
8868 if (!is_equal) return false;
8869 length -= to_check;
8870 // Exit condition. Strings are equal.
8871 if (length == 0) return true;
8872 state_1_.Advance(to_check);
8873 state_2_.Advance(to_check);
8874 }
8875 }
8876
8877 private:
8878 State state_1_;
8879 State state_2_;
8880 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
8881};
ager@chromium.org7c537e22008-10-16 08:43:32 +00008882
8883
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008884bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008885 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008886 int len = length();
8887 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888 if (len == 0) return true;
8889
8890 // Fast check: if hash code is computed for both strings
8891 // a fast negative check can be performed.
8892 if (HasHashCode() && other->HasHashCode()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008893#ifdef DEBUG
8894 if (FLAG_enable_slow_asserts) {
8895 if (Hash() != other->Hash()) {
8896 bool found_difference = false;
8897 for (int i = 0; i < len; i++) {
8898 if (Get(i) != other->Get(i)) {
8899 found_difference = true;
8900 break;
8901 }
8902 }
8903 ASSERT(found_difference);
8904 }
8905 }
8906#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907 if (Hash() != other->Hash()) return false;
8908 }
8909
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00008910 // We know the strings are both non-empty. Compare the first chars
8911 // before we try to flatten the strings.
8912 if (this->Get(0) != other->Get(0)) return false;
8913
8914 String* lhs = this->TryFlattenGetString();
8915 String* rhs = other->TryFlattenGetString();
8916
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008917 // TODO(dcarney): Compare all types of flat strings with a Visitor.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00008918 if (StringShape(lhs).IsSequentialAscii() &&
8919 StringShape(rhs).IsSequentialAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008920 const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars();
8921 const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008922 return CompareRawStringContents(str1, str2, len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008923 }
8924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 Isolate* isolate = GetIsolate();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008926 StringComparator comparator(isolate->objects_string_compare_iterator_a(),
8927 isolate->objects_string_compare_iterator_b());
8928
8929 return comparator.Equals(static_cast<unsigned>(len), lhs, rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930}
8931
8932
8933bool String::MarkAsUndetectable() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008934 if (StringShape(this).IsInternalized()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008935
8936 Map* map = this->map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008937 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938 if (map == heap->string_map()) {
8939 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 } else if (map == heap->ascii_string_map()) {
8942 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008943 return true;
8944 }
8945 // Rest cannot be marked as undetectable
8946 return false;
8947}
8948
8949
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008950bool String::IsUtf8EqualTo(Vector<const char> str, bool allow_prefix_match) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008951 int slen = length();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008952 // Can't check exact length equality, but we can check bounds.
8953 int str_len = str.length();
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008954 if (!allow_prefix_match &&
8955 (str_len < slen ||
8956 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize))) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008957 return false;
8958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008959 int i;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008960 unsigned remaining_in_str = static_cast<unsigned>(str_len);
8961 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
8962 for (i = 0; i < slen && remaining_in_str > 0; i++) {
8963 unsigned cursor = 0;
8964 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
8965 ASSERT(cursor > 0 && cursor <= remaining_in_str);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008966 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
8967 if (i > slen - 1) return false;
8968 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
8969 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
8970 } else {
8971 if (Get(i) != r) return false;
8972 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008973 utf8_data += cursor;
8974 remaining_in_str -= cursor;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008975 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00008976 return (allow_prefix_match || i == slen) && remaining_in_str == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008977}
8978
8979
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008980bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008981 int slen = length();
8982 if (str.length() != slen) return false;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008983 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008984 FlatContent content = GetFlatContent();
8985 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008986 return CompareChars(content.ToOneByteVector().start(),
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008987 str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008988 }
8989 for (int i = 0; i < slen; i++) {
8990 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008991 }
8992 return true;
8993}
8994
8995
8996bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
8997 int slen = length();
8998 if (str.length() != slen) return false;
rossberg@chromium.org79e79022013-06-03 15:43:46 +00008999 DisallowHeapAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009000 FlatContent content = GetFlatContent();
9001 if (content.IsTwoByte()) {
9002 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009003 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009004 for (int i = 0; i < slen; i++) {
9005 if (Get(i) != str[i]) return false;
9006 }
9007 return true;
9008}
9009
9010
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009011class IteratingStringHasher: public StringHasher {
9012 public:
9013 static inline uint32_t Hash(String* string, uint32_t seed) {
9014 const unsigned len = static_cast<unsigned>(string->length());
9015 IteratingStringHasher hasher(len, seed);
9016 if (hasher.has_trivial_hash()) {
9017 return hasher.GetHashField();
9018 }
9019 int32_t type = string->map()->instance_type();
9020 ConsStringNullOp null_op;
9021 String::Visit(string, 0, hasher, null_op, type, len);
9022 // Flat strings terminate immediately.
9023 if (hasher.consumed_ == len) {
9024 ASSERT(!string->IsConsString());
9025 return hasher.GetHashField();
9026 }
9027 ASSERT(string->IsConsString());
9028 // This is a ConsString, iterate across it.
9029 ConsStringIteratorOp op;
9030 unsigned offset = 0;
9031 unsigned leaf_length = len;
9032 string = op.Operate(string, &offset, &type, &leaf_length);
9033 while (true) {
9034 ASSERT(hasher.consumed_ < len);
9035 String::Visit(string, 0, hasher, null_op, type, leaf_length);
9036 if (hasher.consumed_ == len) break;
9037 string = op.ContinueOperation(&type, &leaf_length);
9038 // This should be taken care of by the length check.
9039 ASSERT(string != NULL);
9040 }
9041 return hasher.GetHashField();
9042 }
9043 inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
9044 AddCharacters(chars, static_cast<int>(length));
9045 consumed_ += length;
9046 }
9047 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
9048 AddCharacters(chars, static_cast<int>(length));
9049 consumed_ += length;
9050 }
9051
9052 private:
9053 inline IteratingStringHasher(int len, uint32_t seed)
9054 : StringHasher(len, seed),
9055 consumed_(0) {}
9056 unsigned consumed_;
9057 DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
9058};
9059
9060
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009062 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009063 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009065 // Store the hash code in the object.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009066 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009067 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068
9069 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009070 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009071 uint32_t result = field >> kHashShift;
9072 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9073 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074}
9075
9076
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009077bool String::ComputeArrayIndex(uint32_t* index) {
9078 int length = this->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009079 if (length == 0 || length > kMaxArrayIndexSize) return false;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009080 ConsStringIteratorOp op;
9081 StringCharacterStream stream(this, &op);
9082 uint16_t ch = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009083
9084 // If the string begins with a '0' character, it must only consist
9085 // of it to be a legal array index.
9086 if (ch == '0') {
9087 *index = 0;
9088 return length == 1;
9089 }
9090
9091 // Convert string to uint32 array index; character by character.
9092 int d = ch - '0';
9093 if (d < 0 || d > 9) return false;
9094 uint32_t result = d;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009095 while (stream.HasMore()) {
9096 d = stream.GetNext() - '0';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009097 if (d < 0 || d > 9) return false;
9098 // Check that the new result is below the 32 bit limit.
9099 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
9100 result = (result * 10) + d;
9101 }
9102
9103 *index = result;
9104 return true;
9105}
9106
9107
9108bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009109 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009110 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009111 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009112 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009113 // Isolate the array index form the full hash field.
9114 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009115 return true;
9116 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00009117 return ComputeArrayIndex(index);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119}
9120
9121
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009122Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
9123 int new_size, old_size;
9124 int old_length = string->length();
9125 if (old_length <= new_length) return string;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009126
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009127 if (string->IsSeqOneByteString()) {
9128 old_size = SeqOneByteString::SizeFor(old_length);
9129 new_size = SeqOneByteString::SizeFor(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009130 } else {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009131 ASSERT(string->IsSeqTwoByteString());
9132 old_size = SeqTwoByteString::SizeFor(old_length);
9133 new_size = SeqTwoByteString::SizeFor(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009134 }
9135
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009136 int delta = old_size - new_size;
9137 string->set_length(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009138
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009139 Address start_of_string = string->address();
9140 ASSERT_OBJECT_ALIGNED(start_of_string);
9141 ASSERT_OBJECT_ALIGNED(start_of_string + new_size);
9142
9143 Heap* heap = string->GetHeap();
9144 NewSpace* newspace = heap->new_space();
9145 if (newspace->Contains(start_of_string) &&
9146 newspace->top() == start_of_string + old_size) {
9147 // Last allocated object in new space. Simply lower allocation top.
9148 *(newspace->allocation_top_address()) = start_of_string + new_size;
9149 } else {
9150 // Sizes are pointer size aligned, so that we can use filler objects
9151 // that are a multiple of pointer size.
9152 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009153 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009154 if (Marking::IsBlack(Marking::MarkBitFrom(start_of_string))) {
9155 MemoryChunk::IncrementLiveBytesFromMutator(start_of_string, -delta);
9156 }
9157
9158
9159 if (new_length == 0) return heap->isolate()->factory()->empty_string();
9160 return string;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00009161}
9162
9163
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00009164AllocationMemento* AllocationMemento::FindForJSObject(JSObject* object,
9165 bool in_GC) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009166 // Currently, AllocationMemento objects are only allocated immediately
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009167 // after JSArrays in NewSpace, and detecting whether a JSArray has one
9168 // involves carefully checking the object immediately after the JSArray
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009169 // (if there is one) to see if it's an AllocationMemento.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009170 if (FLAG_track_allocation_sites && object->GetHeap()->InNewSpace(object)) {
9171 Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag) +
9172 object->Size();
jkummerow@chromium.orgd8a3a142013-10-03 12:15:05 +00009173 Address top;
9174 if (in_GC) {
9175 top = object->GetHeap()->new_space()->FromSpacePageHigh();
9176 } else {
9177 top = object->GetHeap()->NewSpaceTop();
9178 }
9179 if ((ptr_end + AllocationMemento::kSize) <= top) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009180 // There is room in newspace for allocation info. Do we have some?
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009181 Map** possible_allocation_memento_map =
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009182 reinterpret_cast<Map**>(ptr_end);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009183 if (*possible_allocation_memento_map ==
9184 object->GetHeap()->allocation_memento_map()) {
9185 AllocationMemento* memento = AllocationMemento::cast(
dslomov@chromium.orge97852d2013-09-12 09:02:59 +00009186 reinterpret_cast<Object*>(ptr_end + kHeapObjectTag));
hpayer@chromium.org27ce8742013-09-19 09:59:01 +00009187 return memento;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00009188 }
9189 }
9190 }
9191 return NULL;
9192}
9193
9194
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009195uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009196 // For array indexes mix the length into the hash as an array index could
9197 // be zero.
9198 ASSERT(length > 0);
9199 ASSERT(length <= String::kMaxArrayIndexSize);
9200 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
9201 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009202
9203 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009204 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00009205
9206 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
9207 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
9208 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009209 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210}
9211
9212
ager@chromium.org7c537e22008-10-16 08:43:32 +00009213uint32_t StringHasher::GetHashField() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009214 if (length_ <= String::kMaxHashCalcLength) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009215 if (is_array_index_) {
9216 return MakeArrayIndexHash(array_index_, length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00009217 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009218 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
9219 String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00009220 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00009221 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00009223}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009224
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009226uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
9227 uint32_t seed,
9228 int* utf16_length_out) {
9229 int vector_length = chars.length();
9230 // Handle some edge cases
9231 if (vector_length <= 1) {
9232 ASSERT(vector_length == 0 ||
9233 static_cast<uint8_t>(chars.start()[0]) <=
9234 unibrow::Utf8::kMaxOneByteChar);
9235 *utf16_length_out = vector_length;
9236 return HashSequentialString(chars.start(), vector_length, seed);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009237 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009238 // Start with a fake length which won't affect computation.
9239 // It will be updated later.
9240 StringHasher hasher(String::kMaxArrayIndexSize, seed);
9241 unsigned remaining = static_cast<unsigned>(vector_length);
9242 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
9243 int utf16_length = 0;
9244 bool is_index = true;
9245 ASSERT(hasher.is_array_index_);
9246 while (remaining > 0) {
9247 unsigned consumed = 0;
9248 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
9249 ASSERT(consumed > 0 && consumed <= remaining);
9250 stream += consumed;
9251 remaining -= consumed;
9252 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
9253 utf16_length += is_two_characters ? 2 : 1;
9254 // No need to keep hashing. But we do need to calculate utf16_length.
9255 if (utf16_length > String::kMaxHashCalcLength) continue;
9256 if (is_two_characters) {
9257 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
9258 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
9259 hasher.AddCharacter(c1);
9260 hasher.AddCharacter(c2);
9261 if (is_index) is_index = hasher.UpdateIndex(c1);
9262 if (is_index) is_index = hasher.UpdateIndex(c2);
9263 } else {
9264 hasher.AddCharacter(c);
9265 if (is_index) is_index = hasher.UpdateIndex(c);
9266 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009267 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00009268 *utf16_length_out = static_cast<int>(utf16_length);
9269 // Must set length here so that hash computation is correct.
9270 hasher.length_ = utf16_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00009271 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009272}
9273
9274
lrn@chromium.org303ada72010-10-27 09:33:13 +00009275MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009276 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009277 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009278 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009279 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009280}
9281
9282
9283void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009284 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009285 for (int i = 0; i < length; i++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009286 PrintF(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009287 }
9288}
9289
9290
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009291static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) {
9292 int live_enum = map->EnumLength();
9293 if (live_enum == Map::kInvalidEnumCache) {
9294 live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
9295 }
9296 if (live_enum == 0) return descriptors->ClearEnumCache();
9297
9298 FixedArray* enum_cache = descriptors->GetEnumCache();
9299
9300 int to_trim = enum_cache->length() - live_enum;
9301 if (to_trim <= 0) return;
9302 RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim);
9303
9304 if (!descriptors->HasEnumIndicesCache()) return;
9305 FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
9306 RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim);
9307}
9308
9309
9310static void TrimDescriptorArray(Heap* heap,
9311 Map* map,
9312 DescriptorArray* descriptors,
9313 int number_of_own_descriptors) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00009314 int number_of_descriptors = descriptors->number_of_descriptors_storage();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009315 int to_trim = number_of_descriptors - number_of_own_descriptors;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00009316 if (to_trim == 0) return;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009317
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00009318 RightTrimFixedArray<FROM_GC>(
9319 heap, descriptors, to_trim * DescriptorArray::kDescriptorSize);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009320 descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
9321
9322 if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors);
9323 descriptors->Sort();
9324}
9325
9326
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009327// Clear a possible back pointer in case the transition leads to a dead map.
9328// Return true in case a back pointer has been cleared and false otherwise.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009329static bool ClearBackPointer(Heap* heap, Map* target) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009330 if (Marking::MarkBitFrom(target).Get()) return false;
9331 target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009332 return true;
9333}
9334
9335
9336// TODO(mstarzinger): This method should be moved into MarkCompactCollector,
9337// because it cannot be called from outside the GC and we already have methods
9338// depending on the transitions layout in the GC anyways.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00009339void Map::ClearNonLiveTransitions(Heap* heap) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009340 // If there are no transitions to be cleared, return.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009341 // TODO(verwaest) Should be an assert, otherwise back pointers are not
9342 // properly cleared.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009343 if (!HasTransitionArray()) return;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009344
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009345 TransitionArray* t = transitions();
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00009346 MarkCompactCollector* collector = heap->mark_compact_collector();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009347
9348 int transition_index = 0;
9349
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009350 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009351 bool descriptors_owner_died = false;
9352
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009353 // Compact all live descriptors to the left.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009354 for (int i = 0; i < t->number_of_transitions(); ++i) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009355 Map* target = t->GetTarget(i);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009356 if (ClearBackPointer(heap, target)) {
9357 if (target->instance_descriptors() == descriptors) {
9358 descriptors_owner_died = true;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009359 }
9360 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009361 if (i != transition_index) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00009362 Name* key = t->GetKey(i);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009363 t->SetKey(transition_index, key);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009364 Object** key_slot = t->GetKeySlot(transition_index);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009365 collector->RecordSlot(key_slot, key_slot, key);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00009366 // Target slots do not need to be recorded since maps are not compacted.
9367 t->SetTarget(transition_index, t->GetTarget(i));
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009368 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009369 transition_index++;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009370 }
9371 }
9372
danno@chromium.orgd3c42102013-08-01 16:58:23 +00009373 // If there are no transitions to be cleared, return.
9374 // TODO(verwaest) Should be an assert, otherwise back pointers are not
9375 // properly cleared.
9376 if (transition_index == t->number_of_transitions()) return;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009377
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009378 int number_of_own_descriptors = NumberOfOwnDescriptors();
9379
9380 if (descriptors_owner_died) {
9381 if (number_of_own_descriptors > 0) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009382 TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009383 ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
9384 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00009385 ASSERT(descriptors == GetHeap()->empty_descriptor_array());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009386 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00009387 }
9388
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00009389 int trim = t->number_of_transitions() - transition_index;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00009390 if (trim > 0) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00009391 RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition()
9392 ? trim : trim * TransitionArray::kTransitionSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009393 }
9394}
9395
9396
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009397int Map::Hash() {
9398 // For performance reasons we only hash the 3 most variable fields of a map:
9399 // constructor, prototype and bit_field2.
9400
9401 // Shift away the tag.
9402 int hash = (static_cast<uint32_t>(
9403 reinterpret_cast<uintptr_t>(constructor())) >> 2);
9404
9405 // XOR-ing the prototype and constructor directly yields too many zero bits
9406 // when the two pointers are close (which is fairly common).
9407 // To avoid this we shift the prototype 4 bits relatively to the constructor.
9408 hash ^= (static_cast<uint32_t>(
9409 reinterpret_cast<uintptr_t>(prototype())) << 2);
9410
9411 return hash ^ (hash >> 16) ^ bit_field2();
9412}
9413
9414
danno@chromium.orgf005df62013-04-30 16:36:45 +00009415static bool CheckEquivalent(Map* first, Map* second) {
9416 return
9417 first->constructor() == second->constructor() &&
9418 first->prototype() == second->prototype() &&
9419 first->instance_type() == second->instance_type() &&
9420 first->bit_field() == second->bit_field() &&
9421 first->bit_field2() == second->bit_field2() &&
9422 first->is_observed() == second->is_observed() &&
9423 first->function_with_prototype() == second->function_with_prototype();
9424}
9425
9426
9427bool Map::EquivalentToForTransition(Map* other) {
9428 return CheckEquivalent(this, other);
9429}
9430
9431
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009432bool Map::EquivalentToForNormalization(Map* other,
9433 PropertyNormalizationMode mode) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00009434 int properties = mode == CLEAR_INOBJECT_PROPERTIES
9435 ? 0 : other->inobject_properties();
9436 return CheckEquivalent(this, other) && inobject_properties() == properties;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009437}
9438
9439
mstarzinger@chromium.orga2e1a402013-10-15 08:25:05 +00009440void ConstantPoolArray::ConstantPoolIterateBody(ObjectVisitor* v) {
9441 int first_ptr_offset = OffsetOfElementAt(first_ptr_index());
9442 int last_ptr_offset =
9443 OffsetOfElementAt(first_ptr_index() + count_of_ptr_entries());
9444 v->VisitPointers(
9445 HeapObject::RawField(this, first_ptr_offset),
9446 HeapObject::RawField(this, last_ptr_offset));
9447}
9448
9449
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00009450void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
9451 // Iterate over all fields in the body but take care in dealing with
9452 // the code entry.
9453 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
9454 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
9455 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
9456}
9457
9458
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009459void JSFunction::MarkForLazyRecompilation() {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009460 ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009461 ASSERT(!IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00009462 ASSERT(shared()->allows_lazy_compilation() ||
9463 code()->optimizable());
danno@chromium.org59400602013-08-13 17:09:37 +00009464 ASSERT(!shared()->is_generator());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009465 set_code_no_write_barrier(
9466 GetIsolate()->builtins()->builtin(Builtins::kLazyRecompile));
9467 // No write barrier required, since the builtin is part of the root set.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009468}
9469
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009470
rossberg@chromium.org92597162013-08-23 13:28:00 +00009471void JSFunction::MarkForConcurrentRecompilation() {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009472 ASSERT(is_compiled() || GetIsolate()->DebuggerHasBreakPoints());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00009473 ASSERT(!IsOptimized());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00009474 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
danno@chromium.org59400602013-08-13 17:09:37 +00009475 ASSERT(!shared()->is_generator());
rossberg@chromium.org92597162013-08-23 13:28:00 +00009476 ASSERT(FLAG_concurrent_recompilation);
9477 if (FLAG_trace_concurrent_recompilation) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009478 PrintF(" ** Marking ");
9479 PrintName();
rossberg@chromium.org92597162013-08-23 13:28:00 +00009480 PrintF(" for concurrent recompilation.\n");
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009481 }
9482 set_code_no_write_barrier(
rossberg@chromium.org92597162013-08-23 13:28:00 +00009483 GetIsolate()->builtins()->builtin(Builtins::kConcurrentRecompile));
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009484 // No write barrier required, since the builtin is part of the root set.
yangguo@chromium.org304cc332012-07-24 07:59:48 +00009485}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009486
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009487
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009488void JSFunction::MarkInRecompileQueue() {
rossberg@chromium.org92597162013-08-23 13:28:00 +00009489 // We can only arrive here via the concurrent-recompilation builtin. If
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009490 // break points were set, the code would point to the lazy-compile builtin.
9491 ASSERT(!GetIsolate()->DebuggerHasBreakPoints());
rossberg@chromium.org92597162013-08-23 13:28:00 +00009492 ASSERT(IsMarkedForConcurrentRecompilation() && !IsOptimized());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009493 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
rossberg@chromium.org92597162013-08-23 13:28:00 +00009494 ASSERT(FLAG_concurrent_recompilation);
9495 if (FLAG_trace_concurrent_recompilation) {
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009496 PrintF(" ** Queueing ");
9497 PrintName();
rossberg@chromium.org92597162013-08-23 13:28:00 +00009498 PrintF(" for concurrent recompilation.\n");
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009499 }
9500 set_code_no_write_barrier(
9501 GetIsolate()->builtins()->builtin(Builtins::kInRecompileQueue));
9502 // No write barrier required, since the builtin is part of the root set.
9503}
9504
9505
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009506static bool CompileLazyHelper(CompilationInfo* info,
9507 ClearExceptionFlag flag) {
9508 // Compile the source information to a code object.
9509 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
9510 ASSERT(!info->isolate()->has_pending_exception());
9511 bool result = Compiler::CompileLazy(info);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00009512 ASSERT(result != info->isolate()->has_pending_exception());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009513 if (!result && flag == CLEAR_EXCEPTION) {
9514 info->isolate()->clear_pending_exception();
9515 }
9516 return result;
9517}
9518
9519
9520bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
9521 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009522 ASSERT(shared->allows_lazy_compilation_without_context());
9523 CompilationInfoWithZone info(shared);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009524 return CompileLazyHelper(&info, flag);
9525}
9526
9527
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009528void SharedFunctionInfo::AddToOptimizedCodeMap(
9529 Handle<SharedFunctionInfo> shared,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009530 Handle<Context> native_context,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009531 Handle<Code> code,
9532 Handle<FixedArray> literals) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009533 CALL_HEAP_FUNCTION_VOID(
9534 shared->GetIsolate(),
9535 shared->AddToOptimizedCodeMap(*native_context, *code, *literals));
9536}
9537
9538
9539MaybeObject* SharedFunctionInfo::AddToOptimizedCodeMap(Context* native_context,
9540 Code* code,
9541 FixedArray* literals) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009542 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009543 ASSERT(native_context->IsNativeContext());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009544 STATIC_ASSERT(kEntryLength == 3);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009545 Heap* heap = GetHeap();
9546 FixedArray* new_code_map;
9547 Object* value = optimized_code_map();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009548 if (value->IsSmi()) {
9549 // No optimized code map.
9550 ASSERT_EQ(0, Smi::cast(value)->value());
9551 // Crate 3 entries per context {context, code, literals}.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009552 MaybeObject* maybe = heap->AllocateFixedArray(kInitialLength);
9553 if (!maybe->To(&new_code_map)) return maybe;
9554 new_code_map->set(kEntriesStart + 0, native_context);
9555 new_code_map->set(kEntriesStart + 1, code);
9556 new_code_map->set(kEntriesStart + 2, literals);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009557 } else {
9558 // Copy old map and append one new entry.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009559 FixedArray* old_code_map = FixedArray::cast(value);
9560 ASSERT_EQ(-1, SearchOptimizedCodeMap(native_context));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009561 int old_length = old_code_map->length();
9562 int new_length = old_length + kEntryLength;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009563 MaybeObject* maybe = old_code_map->CopySize(new_length);
9564 if (!maybe->To(&new_code_map)) return maybe;
9565 new_code_map->set(old_length + 0, native_context);
9566 new_code_map->set(old_length + 1, code);
9567 new_code_map->set(old_length + 2, literals);
9568 // Zap the old map for the sake of the heap verifier.
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00009569 if (Heap::ShouldZapGarbage()) {
9570 Object** data = old_code_map->data_start();
9571 MemsetPointer(data, heap->the_hole_value(), old_length);
9572 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009573 }
9574#ifdef DEBUG
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009575 for (int i = kEntriesStart; i < new_code_map->length(); i += kEntryLength) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009576 ASSERT(new_code_map->get(i)->IsNativeContext());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009577 ASSERT(new_code_map->get(i + 1)->IsCode());
9578 ASSERT(Code::cast(new_code_map->get(i + 1))->kind() ==
9579 Code::OPTIMIZED_FUNCTION);
9580 ASSERT(new_code_map->get(i + 2)->IsFixedArray());
9581 }
9582#endif
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009583 set_optimized_code_map(new_code_map);
9584 return new_code_map;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009585}
9586
9587
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009588void SharedFunctionInfo::InstallFromOptimizedCodeMap(JSFunction* function,
9589 int index) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009590 ASSERT(index > kEntriesStart);
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009591 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9592 if (!bound()) {
9593 FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
9594 ASSERT(cached_literals != NULL);
9595 function->set_literals(cached_literals);
9596 }
9597 Code* code = Code::cast(code_map->get(index));
9598 ASSERT(code != NULL);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009599 ASSERT(function->context()->native_context() == code_map->get(index - 1));
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009600 function->ReplaceCode(code);
9601}
9602
9603
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009604void SharedFunctionInfo::ClearOptimizedCodeMap() {
9605 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9606
9607 // If the next map link slot is already used then the function was
9608 // enqueued with code flushing and we remove it now.
9609 if (!code_map->get(kNextMapIndex)->IsUndefined()) {
9610 CodeFlusher* flusher = GetHeap()->mark_compact_collector()->code_flusher();
9611 flusher->EvictOptimizedCodeMap(this);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009612 }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009613
9614 ASSERT(code_map->get(kNextMapIndex)->IsUndefined());
9615 set_optimized_code_map(Smi::FromInt(0));
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009616}
9617
9618
9619void SharedFunctionInfo::EvictFromOptimizedCodeMap(Code* optimized_code,
9620 const char* reason) {
9621 if (optimized_code_map()->IsSmi()) return;
9622
9623 int i;
9624 bool removed_entry = false;
9625 FixedArray* code_map = FixedArray::cast(optimized_code_map());
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009626 for (i = kEntriesStart; i < code_map->length(); i += kEntryLength) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009627 ASSERT(code_map->get(i)->IsNativeContext());
9628 if (Code::cast(code_map->get(i + 1)) == optimized_code) {
9629 if (FLAG_trace_opt) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009630 PrintF("[evicting entry from optimizing code map (%s) for ", reason);
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009631 ShortPrint();
9632 PrintF("]\n");
9633 }
9634 removed_entry = true;
9635 break;
9636 }
9637 }
9638 while (i < (code_map->length() - kEntryLength)) {
9639 code_map->set(i, code_map->get(i + kEntryLength));
9640 code_map->set(i + 1, code_map->get(i + 1 + kEntryLength));
9641 code_map->set(i + 2, code_map->get(i + 2 + kEntryLength));
9642 i += kEntryLength;
9643 }
9644 if (removed_entry) {
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009645 // Always trim even when array is cleared because of heap verifier.
9646 RightTrimFixedArray<FROM_MUTATOR>(GetHeap(), code_map, kEntryLength);
9647 if (code_map->length() == kEntriesStart) {
9648 ClearOptimizedCodeMap();
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009649 }
9650 }
9651}
9652
9653
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00009654void SharedFunctionInfo::TrimOptimizedCodeMap(int shrink_by) {
9655 FixedArray* code_map = FixedArray::cast(optimized_code_map());
9656 ASSERT(shrink_by % kEntryLength == 0);
9657 ASSERT(shrink_by <= code_map->length() - kEntriesStart);
9658 // Always trim even when array is cleared because of heap verifier.
9659 RightTrimFixedArray<FROM_GC>(GetHeap(), code_map, shrink_by);
9660 if (code_map->length() == kEntriesStart) {
9661 ClearOptimizedCodeMap();
9662 }
9663}
9664
9665
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009666bool JSFunction::CompileLazy(Handle<JSFunction> function,
9667 ClearExceptionFlag flag) {
9668 bool result = true;
9669 if (function->shared()->is_compiled()) {
9670 function->ReplaceCode(function->shared()->code());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009671 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009672 ASSERT(function->shared()->allows_lazy_compilation());
9673 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009674 result = CompileLazyHelper(&info, flag);
9675 ASSERT(!result || function->is_compiled());
9676 }
9677 return result;
9678}
9679
9680
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009681Handle<Code> JSFunction::CompileOsr(Handle<JSFunction> function,
9682 BailoutId osr_ast_id,
9683 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009684 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009685 info.SetOptimizing(osr_ast_id);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009686 if (CompileLazyHelper(&info, flag)) {
9687 // TODO(titzer): don't install the OSR code.
9688 // ASSERT(function->code() != *info.code());
9689 return info.code();
9690 } else {
9691 return Handle<Code>::null();
9692 }
9693}
9694
9695
9696bool JSFunction::CompileOptimized(Handle<JSFunction> function,
9697 ClearExceptionFlag flag) {
9698 CompilationInfoWithZone info(function);
9699 info.SetOptimizing(BailoutId::None());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009700 return CompileLazyHelper(&info, flag);
9701}
9702
9703
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009704bool JSFunction::EnsureCompiled(Handle<JSFunction> function,
9705 ClearExceptionFlag flag) {
9706 return function->is_compiled() || CompileLazy(function, flag);
9707}
9708
9709
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009710bool JSFunction::IsInlineable() {
9711 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009712 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009713 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009714 if (!shared_info->script()->IsScript()) return false;
9715 if (shared_info->optimization_disabled()) return false;
9716 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009717 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
9718 // If we never ran this (unlikely) then lets try to optimize it.
9719 if (code->kind() != Code::FUNCTION) return true;
9720 return code->optimizable();
9721}
9722
9723
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +00009724void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009725 if (object->IsGlobalObject()) return;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009726
9727 // Make sure prototypes are fast objects and their maps have the bit set
9728 // so they remain fast.
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00009729 if (!object->HasFastProperties()) {
9730 TransformToFastProperties(object, 0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009731 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009732}
9733
9734
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009735static MUST_USE_RESULT MaybeObject* CacheInitialJSArrayMaps(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009736 Context* native_context, Map* initial_map) {
9737 // Replace all of the cached initial array maps in the native context with
9738 // the appropriate transitioned elements kind maps.
9739 Heap* heap = native_context->GetHeap();
9740 MaybeObject* maybe_maps =
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009741 heap->AllocateFixedArrayWithHoles(kElementsKindCount, TENURED);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009742 FixedArray* maps;
9743 if (!maybe_maps->To(&maps)) return maybe_maps;
9744
9745 Map* current_map = initial_map;
9746 ElementsKind kind = current_map->elements_kind();
9747 ASSERT(kind == GetInitialFastElementsKind());
9748 maps->set(kind, current_map);
9749 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
9750 i < kFastElementsKindCount; ++i) {
9751 Map* new_map;
9752 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
danno@chromium.orgf005df62013-04-30 16:36:45 +00009753 if (current_map->HasElementsTransition()) {
9754 new_map = current_map->elements_transition_map();
9755 ASSERT(new_map->elements_kind() == next_kind);
9756 } else {
9757 MaybeObject* maybe_new_map =
9758 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
9759 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9760 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009761 maps->set(next_kind, new_map);
9762 current_map = new_map;
9763 }
9764 native_context->set_js_array_maps(maps);
9765 return initial_map;
9766}
9767
9768
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009769Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
9770 Handle<Map> initial_map) {
9771 CALL_HEAP_FUNCTION(native_context->GetIsolate(),
9772 CacheInitialJSArrayMaps(*native_context, *initial_map),
9773 Object);
9774}
9775
9776
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009777void JSFunction::SetInstancePrototype(Handle<JSFunction> function,
9778 Handle<Object> value) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00009779 ASSERT(value->IsJSReceiver());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009780
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00009781 // First some logic for the map of the prototype to make sure it is in fast
9782 // mode.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009783 if (value->IsJSObject()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009784 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009785 }
9786
9787 // Now some logic for the maps of the objects that are created by using this
9788 // function as a constructor.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009789 if (function->has_initial_map()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009790 // If the function has allocated the initial map replace it with a
9791 // copy containing the new prototype. Also complete any in-object
9792 // slack tracking that is in progress at this point because it is
9793 // still tracking the old copy.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009794 if (function->shared()->IsInobjectSlackTrackingInProgress()) {
9795 function->shared()->CompleteInobjectSlackTracking();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009796 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009797 Handle<Map> new_map = Map::Copy(handle(function->initial_map()));
9798 new_map->set_prototype(*value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009799
9800 // If the function is used as the global Array function, cache the
9801 // initial map (and transitioned versions) in the native context.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009802 Context* native_context = function->context()->native_context();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009803 Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX);
9804 if (array_function->IsJSFunction() &&
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009805 *function == JSFunction::cast(array_function)) {
9806 CacheInitialJSArrayMaps(handle(native_context), new_map);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009807 }
9808
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009809 function->set_initial_map(*new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009810 } else {
9811 // Put the value in the initial map field until an initial map is
9812 // needed. At that point, a new initial map is created and the
9813 // prototype is put into the initial map where it belongs.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009814 function->set_prototype_or_initial_map(*value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009815 }
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009816 function->GetHeap()->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009817}
9818
9819
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009820void JSFunction::SetPrototype(Handle<JSFunction> function,
9821 Handle<Object> value) {
9822 ASSERT(function->should_have_prototype());
9823 Handle<Object> construct_prototype = value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009824
danno@chromium.org88aa0582012-03-23 15:11:57 +00009825 // If the value is not a JSReceiver, store the value in the map's
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009826 // constructor field so it can be accessed. Also, set the prototype
9827 // used for constructing objects to the original object prototype.
9828 // See ECMA-262 13.2.2.
danno@chromium.org88aa0582012-03-23 15:11:57 +00009829 if (!value->IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009830 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009831 // Remove map transitions because they point to maps with a
9832 // different prototype.
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009833 Handle<Map> new_map = Map::Copy(handle(function->map()));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00009834
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009835 function->set_map(*new_map);
9836 new_map->set_constructor(*value);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009837 new_map->set_non_instance_prototype(true);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009838 Isolate* isolate = new_map->GetIsolate();
9839 construct_prototype = handle(
9840 isolate->context()->native_context()->initial_object_prototype(),
9841 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842 } else {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009843 function->map()->set_non_instance_prototype(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009844 }
9845
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00009846 return SetInstancePrototype(function, construct_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847}
9848
9849
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009850void JSFunction::RemovePrototype() {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009851 Context* native_context = context()->native_context();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009852 Map* no_prototype_map = shared()->is_classic_mode()
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009853 ? native_context->function_without_prototype_map()
9854 : native_context->strict_mode_function_without_prototype_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009856 if (map() == no_prototype_map) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009857
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009858 ASSERT(map() == (shared()->is_classic_mode()
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009859 ? native_context->function_map()
9860 : native_context->strict_mode_function_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009861
9862 set_map(no_prototype_map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009863 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009864}
9865
9866
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009867void JSFunction::SetInstanceClassName(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009868 shared()->set_instance_class_name(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009869}
9870
9871
whesse@chromium.org023421e2010-12-21 12:19:12 +00009872void JSFunction::PrintName(FILE* out) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009873 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00009874 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009875}
9876
9877
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009878Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
9879 return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
ager@chromium.org236ad962008-09-25 09:45:57 +00009880}
9881
9882
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009883// The filter is a pattern that matches function names in this way:
9884// "*" all; the default
9885// "-" all but the top-level function
9886// "-name" all but the function "name"
9887// "" only the top-level function
9888// "name" only the function "name"
9889// "name*" only functions starting with "name"
9890bool JSFunction::PassesFilter(const char* raw_filter) {
9891 if (*raw_filter == '*') return true;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009892 String* name = shared()->DebugName();
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009893 Vector<const char> filter = CStrVector(raw_filter);
9894 if (filter.length() == 0) return name->length() == 0;
9895 if (filter[0] != '-' && name->IsUtf8EqualTo(filter)) return true;
9896 if (filter[0] == '-' &&
9897 !name->IsUtf8EqualTo(filter.SubVector(1, filter.length()))) {
9898 return true;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009899 }
jkummerow@chromium.org1e8da742013-08-26 17:13:35 +00009900 if (filter[filter.length() - 1] == '*' &&
9901 name->IsUtf8EqualTo(filter.SubVector(0, filter.length() - 1), true)) {
9902 return true;
9903 }
9904 return false;
ulan@chromium.org906e2fb2013-05-14 08:14:38 +00009905}
9906
9907
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00009908MaybeObject* Oddball::Initialize(Heap* heap,
9909 const char* to_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009910 Object* to_number,
9911 byte kind) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009912 String* internalized_to_string;
9913 { MaybeObject* maybe_string =
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00009914 heap->InternalizeUtf8String(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009915 CStrVector(to_string));
9916 if (!maybe_string->To(&internalized_to_string)) return maybe_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009917 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009918 set_to_string(internalized_to_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009919 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009920 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009921 return this;
9922}
9923
9924
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00009925String* SharedFunctionInfo::DebugName() {
9926 Object* n = name();
9927 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
9928 return String::cast(n);
9929}
9930
9931
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932bool SharedFunctionInfo::HasSourceCode() {
9933 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009934 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009935}
9936
9937
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00009938Handle<Object> SharedFunctionInfo::GetSourceCode() {
9939 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
9940 Handle<String> source(String::cast(Script::cast(script())->source()));
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00009941 return GetIsolate()->factory()->NewSubString(
9942 source, start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943}
9944
9945
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009946int SharedFunctionInfo::SourceSize() {
9947 return end_position() - start_position();
9948}
9949
9950
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009951int SharedFunctionInfo::CalculateInstanceSize() {
9952 int instance_size =
9953 JSObject::kHeaderSize +
9954 expected_nof_properties() * kPointerSize;
9955 if (instance_size > JSObject::kMaxInstanceSize) {
9956 instance_size = JSObject::kMaxInstanceSize;
9957 }
9958 return instance_size;
9959}
9960
9961
9962int SharedFunctionInfo::CalculateInObjectProperties() {
9963 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
9964}
9965
9966
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009967// Support function for printing the source code to a StringStream
9968// without any allocation in the heap.
9969void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
9970 int max_length) {
9971 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009972 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009973 accumulator->Add("<No Source>");
9974 return;
9975 }
9976
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009977 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009978 // Don't use String::cast because we don't want more assertion errors while
9979 // we are already creating a stack dump.
9980 String* script_source =
9981 reinterpret_cast<String*>(Script::cast(script())->source());
9982
9983 if (!script_source->LooksValid()) {
9984 accumulator->Add("<Invalid Source>");
9985 return;
9986 }
9987
9988 if (!is_toplevel()) {
9989 accumulator->Add("function ");
9990 Object* name = this->name();
9991 if (name->IsString() && String::cast(name)->length() > 0) {
9992 accumulator->PrintName(name);
9993 }
9994 }
9995
9996 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009997 if (len <= max_length || max_length < 0) {
9998 accumulator->Put(script_source, start_position(), end_position());
9999 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000 accumulator->Put(script_source,
10001 start_position(),
10002 start_position() + max_length);
10003 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 }
10005}
10006
10007
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010008static bool IsCodeEquivalent(Code* code, Code* recompiled) {
10009 if (code->instruction_size() != recompiled->instruction_size()) return false;
10010 ByteArray* code_relocation = code->relocation_info();
10011 ByteArray* recompiled_relocation = recompiled->relocation_info();
10012 int length = code_relocation->length();
10013 if (length != recompiled_relocation->length()) return false;
10014 int compare = memcmp(code_relocation->GetDataStartAddress(),
10015 recompiled_relocation->GetDataStartAddress(),
10016 length);
10017 return compare == 0;
10018}
10019
10020
10021void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
10022 ASSERT(!has_deoptimization_support());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010023 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010024 Code* code = this->code();
10025 if (IsCodeEquivalent(code, recompiled)) {
10026 // Copy the deoptimization data from the recompiled code.
10027 code->set_deoptimization_data(recompiled->deoptimization_data());
10028 code->set_has_deoptimization_support(true);
10029 } else {
10030 // TODO(3025757): In case the recompiled isn't equivalent to the
10031 // old code, we have to replace it. We should try to avoid this
10032 // altogether because it flushes valuable type feedback by
10033 // effectively resetting all IC state.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +000010034 ReplaceCode(recompiled);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010035 }
10036 ASSERT(has_deoptimization_support());
10037}
10038
10039
danno@chromium.org59400602013-08-13 17:09:37 +000010040void SharedFunctionInfo::DisableOptimization(BailoutReason reason) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010041 // Disable optimization for the shared function info and mark the
10042 // code as non-optimizable. The marker on the shared function info
10043 // is there because we flush non-optimized code thereby loosing the
10044 // non-optimizable information for the code. When the code is
10045 // regenerated and set on the shared function info it is marked as
10046 // non-optimizable if optimization is disabled for the shared
10047 // function info.
10048 set_optimization_disabled(true);
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000010049 set_bailout_reason(reason);
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010050 // Code should be the lazy compilation stub or else unoptimized. If the
10051 // latter, disable optimization for the code too.
10052 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
10053 if (code()->kind() == Code::FUNCTION) {
10054 code()->set_optimizable(false);
10055 }
dslomov@chromium.orge97852d2013-09-12 09:02:59 +000010056 PROFILE(GetIsolate(),
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000010057 LogExistingFunction(Handle<SharedFunctionInfo>(this),
10058 Handle<Code>(code())));
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010059 if (FLAG_trace_opt) {
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000010060 PrintF("[disabled optimization for ");
10061 ShortPrint();
danno@chromium.org59400602013-08-13 17:09:37 +000010062 PrintF(", reason: %s]\n", GetBailoutReason(reason));
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010063 }
10064}
10065
10066
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010067bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
10068 ASSERT(!id.IsNone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010069 Code* unoptimized = code();
10070 DeoptimizationOutputData* data =
10071 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
10072 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
10073 USE(ignore);
10074 return true; // Return true if there was no ASSERT.
10075}
10076
10077
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010078void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
10079 ASSERT(!IsInobjectSlackTrackingInProgress());
10080
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010081 if (!FLAG_clever_optimizations) return;
10082
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010083 // Only initiate the tracking the first time.
10084 if (live_objects_may_exist()) return;
10085 set_live_objects_may_exist(true);
10086
10087 // No tracking during the snapshot construction phase.
10088 if (Serializer::enabled()) return;
10089
10090 if (map->unused_property_fields() == 0) return;
10091
10092 // Nonzero counter is a leftover from the previous attempt interrupted
10093 // by GC, keep it.
10094 if (construction_count() == 0) {
10095 set_construction_count(kGenerousAllocationCount);
10096 }
10097 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010098 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010099 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010100 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010101 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010102}
10103
10104
10105// Called from GC, hence reinterpret_cast and unchecked accessors.
10106void SharedFunctionInfo::DetachInitialMap() {
10107 Map* map = reinterpret_cast<Map*>(initial_map());
10108
10109 // Make the map remember to restore the link if it survives the GC.
10110 map->set_bit_field2(
10111 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
10112
10113 // Undo state changes made by StartInobjectTracking (except the
10114 // construction_count). This way if the initial map does not survive the GC
10115 // then StartInobjectTracking will be called again the next time the
10116 // constructor is called. The countdown will continue and (possibly after
10117 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010118 Heap* heap = map->GetHeap();
danno@chromium.org72204d52012-10-31 10:02:10 +000010119 set_initial_map(heap->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010120 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010121 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010122 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010123 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010124 // It is safe to clear the flag: it will be set again if the map is live.
10125 set_live_objects_may_exist(false);
10126}
10127
10128
10129// Called from GC, hence reinterpret_cast and unchecked accessors.
10130void SharedFunctionInfo::AttachInitialMap(Map* map) {
10131 map->set_bit_field2(
10132 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
10133
10134 // Resume inobject slack tracking.
10135 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010136 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010137 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010138 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000010139 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010140 // The map survived the gc, so there may be objects referencing it.
10141 set_live_objects_may_exist(true);
10142}
10143
10144
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010145void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
10146 code()->ClearInlineCaches();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010147 set_ic_age(new_ic_age);
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +000010148 if (code()->kind() == Code::FUNCTION) {
10149 code()->set_profiler_ticks(0);
10150 if (optimization_disabled() &&
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000010151 opt_count() >= FLAG_max_opt_count) {
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +000010152 // Re-enable optimizations if they were disabled due to opt_count limit.
10153 set_optimization_disabled(false);
10154 code()->set_optimizable(true);
10155 }
10156 set_opt_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010157 set_deopt_count(0);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010158 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010159}
10160
10161
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010162static void GetMinInobjectSlack(Map* map, void* data) {
10163 int slack = map->unused_property_fields();
10164 if (*reinterpret_cast<int*>(data) > slack) {
10165 *reinterpret_cast<int*>(data) = slack;
10166 }
10167}
10168
10169
10170static void ShrinkInstanceSize(Map* map, void* data) {
10171 int slack = *reinterpret_cast<int*>(data);
10172 map->set_inobject_properties(map->inobject_properties() - slack);
10173 map->set_unused_property_fields(map->unused_property_fields() - slack);
10174 map->set_instance_size(map->instance_size() - slack * kPointerSize);
10175
10176 // Visitor id might depend on the instance size, recalculate it.
10177 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
10178}
10179
10180
10181void SharedFunctionInfo::CompleteInobjectSlackTracking() {
10182 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
10183 Map* map = Map::cast(initial_map());
10184
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010185 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010186 set_initial_map(heap->undefined_value());
10187 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 construct_stub());
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
10192 int slack = map->unused_property_fields();
10193 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
10194 if (slack != 0) {
10195 // Resize the initial map and all maps in its transition tree.
10196 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010197
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010198 // Give the correct expected_nof_properties to initial maps created later.
10199 ASSERT(expected_nof_properties() >= slack);
10200 set_expected_nof_properties(expected_nof_properties() - slack);
10201 }
10202}
10203
10204
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010205int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context) {
10206 ASSERT(native_context->IsNativeContext());
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +000010207 if (!FLAG_cache_optimized_code) return -1;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010208 Object* value = optimized_code_map();
10209 if (!value->IsSmi()) {
10210 FixedArray* optimized_code_map = FixedArray::cast(value);
10211 int length = optimized_code_map->length();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +000010212 for (int i = kEntriesStart; i < length; i += kEntryLength) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010213 if (optimized_code_map->get(i) == native_context) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010214 return i + 1;
10215 }
10216 }
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000010217 if (FLAG_trace_opt) {
10218 PrintF("[didn't find optimized code in optimized code map for ");
10219 ShortPrint();
10220 PrintF("]\n");
10221 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010222 }
10223 return -1;
10224}
10225
10226
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010227#define DECLARE_TAG(ignore1, name, ignore2) name,
10228const char* const VisitorSynchronization::kTags[
10229 VisitorSynchronization::kNumberOfSyncTags] = {
10230 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10231};
10232#undef DECLARE_TAG
10233
10234
10235#define DECLARE_TAG(ignore1, ignore2, name) name,
10236const char* const VisitorSynchronization::kTagNames[
10237 VisitorSynchronization::kNumberOfSyncTags] = {
10238 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
10239};
10240#undef DECLARE_TAG
10241
10242
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010244 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010245 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
10246 Object* old_target = target;
10247 VisitPointer(&target);
10248 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249}
10250
10251
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010252void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
10253 ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
10254 Object* stub = rinfo->code_age_stub();
10255 if (stub) {
10256 VisitPointer(&stub);
10257 }
10258}
10259
10260
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000010261void ObjectVisitor::VisitCodeEntry(Address entry_address) {
10262 Object* code = Code::GetObjectFromEntryAddress(entry_address);
10263 Object* old_code = code;
10264 VisitPointer(&code);
10265 if (code != old_code) {
10266 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
10267 }
10268}
10269
10270
danno@chromium.org41728482013-06-12 22:31:22 +000010271void ObjectVisitor::VisitCell(RelocInfo* rinfo) {
10272 ASSERT(rinfo->rmode() == RelocInfo::CELL);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010273 Object* cell = rinfo->target_cell();
10274 Object* old_cell = cell;
10275 VisitPointer(&cell);
10276 if (cell != old_cell) {
danno@chromium.org41728482013-06-12 22:31:22 +000010277 rinfo->set_target_cell(reinterpret_cast<Cell*>(cell));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010278 }
10279}
10280
10281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010282void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000010283 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
10284 rinfo->IsPatchedReturnSequence()) ||
10285 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
10286 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010287 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
10288 Object* old_target = target;
10289 VisitPointer(&target);
10290 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010291}
10292
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010293
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010294void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
10295 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
10296 VisitPointer(rinfo->target_object_address());
10297}
10298
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010299
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010300void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
10301 Address* p = rinfo->target_reference_address();
10302 VisitExternalReferences(p, p + 1);
10303}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000010304
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010305
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010306void Code::InvalidateRelocation() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010307 set_relocation_info(GetHeap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010308}
10309
10310
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010311void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010312 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
10313 it.rinfo()->apply(delta);
10314 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010315 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010316}
10317
10318
10319void Code::CopyFrom(const CodeDesc& desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010320 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
10321
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 // copy code
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010323 CopyBytes(instruction_start(), desc.buffer,
10324 static_cast<size_t>(desc.instr_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326 // copy reloc info
danno@chromium.orgc99cd482013-03-21 15:26:42 +000010327 CopyBytes(relocation_start(),
10328 desc.buffer + desc.buffer_size - desc.reloc_size,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010329 static_cast<size_t>(desc.reloc_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010330
10331 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010332 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +000010334 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
danno@chromium.org41728482013-06-12 22:31:22 +000010335 RelocInfo::ModeMask(RelocInfo::CELL) |
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010336 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337 RelocInfo::kApplyMask;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010338 // Needed to find target_object and runtime_entry on X64
10339 Assembler* origin = desc.origin;
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010340 AllowDeferredHandleDereference embedding_raw_address;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010342 RelocInfo::Mode mode = it.rinfo()->rmode();
10343 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010344 Handle<Object> p = it.rinfo()->target_object_handle(origin);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010345 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
danno@chromium.org41728482013-06-12 22:31:22 +000010346 } else if (mode == RelocInfo::CELL) {
10347 Handle<Cell> cell = it.rinfo()->target_cell_handle();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010348 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
ager@chromium.org236ad962008-09-25 09:45:57 +000010349 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010350 // rewrite code handles in inline cache targets to direct
10351 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010352 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353 Code* code = Code::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010354 it.rinfo()->set_target_address(code->instruction_start(),
10355 SKIP_WRITE_BARRIER);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000010356 } else if (RelocInfo::IsRuntimeEntry(mode)) {
10357 Address p = it.rinfo()->target_runtime_entry(origin);
10358 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010359 } else {
10360 it.rinfo()->apply(delta);
10361 }
10362 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010363 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364}
10365
10366
10367// Locate the source position which is closest to the address in the code. This
10368// is using the source position information embedded in the relocation info.
10369// The position returned is relative to the beginning of the script where the
10370// source for this function is found.
10371int Code::SourcePosition(Address pc) {
10372 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +000010373 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010374 // Run through all the relocation info to find the best matching source
10375 // position. All the code needs to be considered as the sequence of the
10376 // instructions in the code does not necessarily follow the same order as the
10377 // source.
10378 RelocIterator it(this, RelocInfo::kPositionMask);
10379 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010380 // Only look at positions after the current pc.
10381 if (it.rinfo()->pc() < pc) {
10382 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010383
10384 int dist = static_cast<int>(pc - it.rinfo()->pc());
10385 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +000010386 // If this position is closer than the current candidate or if it has the
10387 // same distance as the current candidate and the position is higher then
10388 // this position is the new candidate.
10389 if ((dist < distance) ||
10390 (dist == distance && pos > position)) {
10391 position = pos;
10392 distance = dist;
10393 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 }
10395 it.next();
10396 }
10397 return position;
10398}
10399
10400
10401// Same as Code::SourcePosition above except it only looks for statement
10402// positions.
10403int Code::SourceStatementPosition(Address pc) {
10404 // First find the position as close as possible using all position
10405 // information.
10406 int position = SourcePosition(pc);
10407 // Now find the closest statement position before the position.
10408 int statement_position = 0;
10409 RelocIterator it(this, RelocInfo::kPositionMask);
10410 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010411 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010412 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010413 if (statement_position < p && p <= position) {
10414 statement_position = p;
10415 }
10416 }
10417 it.next();
10418 }
10419 return statement_position;
10420}
10421
10422
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010423SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010424 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010425 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010426}
10427
10428
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010429Object* Code::FindNthObject(int n, Map* match_map) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010430 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010431 DisallowHeapAllocation no_allocation;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010432 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10433 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10434 RelocInfo* info = it.rinfo();
10435 Object* object = info->target_object();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010436 if (object->IsHeapObject()) {
10437 if (HeapObject::cast(object)->map() == match_map) {
10438 if (--n == 0) return object;
10439 }
10440 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010441 }
10442 return NULL;
10443}
10444
10445
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010446Map* Code::FindFirstMap() {
10447 Object* result = FindNthObject(1, GetHeap()->meta_map());
10448 return (result != NULL) ? Map::cast(result) : NULL;
10449}
10450
10451
10452void Code::ReplaceNthObject(int n,
10453 Map* match_map,
10454 Object* replace_with) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010455 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010456 DisallowHeapAllocation no_allocation;
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010457 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10458 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10459 RelocInfo* info = it.rinfo();
10460 Object* object = info->target_object();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010461 if (object->IsHeapObject()) {
10462 if (HeapObject::cast(object)->map() == match_map) {
10463 if (--n == 0) {
10464 info->set_target_object(replace_with);
10465 return;
10466 }
10467 }
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010468 }
10469 }
10470 UNREACHABLE();
10471}
10472
10473
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010474void Code::FindAllMaps(MapHandleList* maps) {
10475 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010476 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010477 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10478 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10479 RelocInfo* info = it.rinfo();
10480 Object* object = info->target_object();
10481 if (object->IsMap()) maps->Add(Handle<Map>(Map::cast(object)));
10482 }
10483}
10484
10485
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010486void Code::ReplaceFirstMap(Map* replace_with) {
10487 ReplaceNthObject(1, GetHeap()->meta_map(), replace_with);
10488}
10489
10490
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010491Code* Code::FindFirstHandler() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010492 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010493 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010494 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10495 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10496 RelocInfo* info = it.rinfo();
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010497 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
10498 if (code->kind() == Code::HANDLER) return code;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010499 }
10500 return NULL;
10501}
10502
10503
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010504bool Code::FindHandlers(CodeHandleList* code_list, int length) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010505 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010506 DisallowHeapAllocation no_allocation;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010507 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
10508 int i = 0;
10509 for (RelocIterator it(this, mask); !it.done(); it.next()) {
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010510 if (i == length) return true;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010511 RelocInfo* info = it.rinfo();
10512 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010513 // IC stubs with handlers never contain non-handler code objects before
10514 // handler targets.
10515 if (code->kind() != Code::HANDLER) break;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010516 code_list->Add(Handle<Code>(code));
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010517 i++;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010518 }
jkummerow@chromium.org32aa03c2013-10-01 08:21:50 +000010519 return i == length;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010520}
10521
10522
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010523Name* Code::FindFirstName() {
10524 ASSERT(is_inline_cache_stub());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000010525 DisallowHeapAllocation no_allocation;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000010526 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
10527 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10528 RelocInfo* info = it.rinfo();
10529 Object* object = info->target_object();
10530 if (object->IsName()) return Name::cast(object);
10531 }
10532 return NULL;
10533}
10534
10535
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010536void Code::ReplaceNthCell(int n, Cell* replace_with) {
10537 ASSERT(is_inline_cache_stub());
10538 DisallowHeapAllocation no_allocation;
10539 int mask = RelocInfo::ModeMask(RelocInfo::CELL);
10540 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10541 RelocInfo* info = it.rinfo();
10542 if (--n == 0) {
10543 info->set_target_cell(replace_with);
10544 return;
10545 }
10546 }
10547 UNREACHABLE();
10548}
10549
10550
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010551void Code::ClearInlineCaches() {
10552 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
10553 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
10554 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
10555 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
10556 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10557 RelocInfo* info = it.rinfo();
10558 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
10559 if (target->is_inline_cache_stub()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010560 IC::Clear(this->GetIsolate(), info->pc());
jkummerow@chromium.org1456e702012-03-30 08:38:13 +000010561 }
10562 }
10563}
10564
10565
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010566void Code::ClearTypeFeedbackCells(Heap* heap) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010567 if (kind() != FUNCTION) return;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010568 Object* raw_info = type_feedback_info();
10569 if (raw_info->IsTypeFeedbackInfo()) {
10570 TypeFeedbackCells* type_feedback_cells =
10571 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
10572 for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000010573 Cell* cell = type_feedback_cells->GetCell(i);
danno@chromium.orgbee51992013-07-10 14:57:15 +000010574 // Don't clear AllocationSites
10575 Object* value = cell->value();
10576 if (value == NULL || !value->IsAllocationSite()) {
10577 cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
10578 }
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010579 }
10580 }
10581}
10582
10583
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010584BailoutId Code::TranslatePcOffsetToAstId(uint32_t pc_offset) {
10585 DisallowHeapAllocation no_gc;
10586 ASSERT(kind() == FUNCTION);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010587 BackEdgeTable back_edges(this, &no_gc);
10588 for (uint32_t i = 0; i < back_edges.length(); i++) {
10589 if (back_edges.pc_offset(i) == pc_offset) return back_edges.ast_id(i);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010590 }
10591 return BailoutId::None();
10592}
10593
10594
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010595void Code::MakeCodeAgeSequenceYoung(byte* sequence, Isolate* isolate) {
10596 PatchPlatformCodeAge(isolate, sequence, kNoAge, NO_MARKING_PARITY);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010597}
10598
10599
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010600void Code::MakeOlder(MarkingParity current_parity) {
10601 byte* sequence = FindCodeAgeSequence();
10602 if (sequence != NULL) {
10603 Age age;
10604 MarkingParity code_parity;
10605 GetCodeAgeAndParity(sequence, &age, &code_parity);
10606 if (age != kLastCodeAge && code_parity != current_parity) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010607 PatchPlatformCodeAge(GetIsolate(),
10608 sequence,
10609 static_cast<Age>(age + 1),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010610 current_parity);
10611 }
10612 }
10613}
10614
10615
10616bool Code::IsOld() {
10617 byte* sequence = FindCodeAgeSequence();
10618 if (sequence == NULL) return false;
10619 Age age;
10620 MarkingParity parity;
10621 GetCodeAgeAndParity(sequence, &age, &parity);
10622 return age >= kSexagenarianCodeAge;
10623}
10624
10625
10626byte* Code::FindCodeAgeSequence() {
10627 return FLAG_age_code &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000010628 prologue_offset() != kPrologueOffsetNotSet &&
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010629 (kind() == OPTIMIZED_FUNCTION ||
10630 (kind() == FUNCTION && !has_debug_break_slots()))
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000010631 ? instruction_start() + prologue_offset()
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010632 : NULL;
10633}
10634
10635
danno@chromium.org41728482013-06-12 22:31:22 +000010636int Code::GetAge() {
10637 byte* sequence = FindCodeAgeSequence();
10638 if (sequence == NULL) {
10639 return Code::kNoAge;
10640 }
10641 Age age;
10642 MarkingParity parity;
10643 GetCodeAgeAndParity(sequence, &age, &parity);
10644 return age;
10645}
10646
10647
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010648void Code::GetCodeAgeAndParity(Code* code, Age* age,
10649 MarkingParity* parity) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000010650 Isolate* isolate = code->GetIsolate();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010651 Builtins* builtins = isolate->builtins();
10652 Code* stub = NULL;
10653#define HANDLE_CODE_AGE(AGE) \
10654 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
10655 if (code == stub) { \
10656 *age = k##AGE##CodeAge; \
10657 *parity = EVEN_MARKING_PARITY; \
10658 return; \
10659 } \
10660 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10661 if (code == stub) { \
10662 *age = k##AGE##CodeAge; \
10663 *parity = ODD_MARKING_PARITY; \
10664 return; \
10665 }
10666 CODE_AGE_LIST(HANDLE_CODE_AGE)
10667#undef HANDLE_CODE_AGE
10668 UNREACHABLE();
10669}
10670
10671
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010672Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000010673 Builtins* builtins = isolate->builtins();
10674 switch (age) {
10675#define HANDLE_CODE_AGE(AGE) \
10676 case k##AGE##CodeAge: { \
10677 Code* stub = parity == EVEN_MARKING_PARITY \
10678 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
10679 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10680 return stub; \
10681 }
10682 CODE_AGE_LIST(HANDLE_CODE_AGE)
10683#undef HANDLE_CODE_AGE
10684 default:
10685 UNREACHABLE();
10686 break;
10687 }
10688 return NULL;
10689}
10690
10691
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010692void Code::PrintDeoptLocation(int bailout_id) {
10693 const char* last_comment = NULL;
10694 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
10695 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
10696 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10697 RelocInfo* info = it.rinfo();
10698 if (info->rmode() == RelocInfo::COMMENT) {
10699 last_comment = reinterpret_cast<const char*>(info->data());
danno@chromium.orgaefd6072013-05-14 14:11:47 +000010700 } else if (last_comment != NULL) {
10701 if ((bailout_id == Deoptimizer::GetDeoptimizationId(
10702 GetIsolate(), info->target_address(), Deoptimizer::EAGER)) ||
10703 (bailout_id == Deoptimizer::GetDeoptimizationId(
10704 GetIsolate(), info->target_address(), Deoptimizer::SOFT))) {
10705 CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
10706 PrintF(" %s\n", last_comment);
10707 return;
10708 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010709 }
10710 }
10711}
10712
10713
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000010714bool Code::CanDeoptAt(Address pc) {
10715 DeoptimizationInputData* deopt_data =
10716 DeoptimizationInputData::cast(deoptimization_data());
10717 Address code_start_address = instruction_start();
10718 for (int i = 0; i < deopt_data->DeoptCount(); i++) {
10719 if (deopt_data->Pc(i)->value() == -1) continue;
10720 Address address = code_start_address + deopt_data->Pc(i)->value();
10721 if (address == pc) return true;
10722 }
10723 return false;
10724}
10725
10726
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010727// Identify kind of code.
10728const char* Code::Kind2String(Kind kind) {
10729 switch (kind) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000010730#define CASE(name) case name: return #name;
10731 CODE_KIND_LIST(CASE)
10732#undef CASE
10733 case NUMBER_OF_KINDS: break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010734 }
10735 UNREACHABLE();
10736 return NULL;
10737}
10738
10739
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010740#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010741
whesse@chromium.org023421e2010-12-21 12:19:12 +000010742void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010743 disasm::NameConverter converter;
10744 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +000010745 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010746 if (0 == deopt_count) return;
10747
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010748 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010749 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010750 for (int i = 0; i < deopt_count; i++) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010751 PrintF(out, "%6d %6d %6d %6d",
10752 i,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010753 AstId(i).ToInt(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010754 ArgumentsStackHeight(i)->value(),
10755 Pc(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010756
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010757 if (!FLAG_print_code_verbose) {
10758 PrintF(out, "\n");
10759 continue;
10760 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010761 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010762 int translation_index = TranslationIndex(i)->value();
10763 TranslationIterator iterator(TranslationByteArray(), translation_index);
10764 Translation::Opcode opcode =
10765 static_cast<Translation::Opcode>(iterator.Next());
10766 ASSERT(Translation::BEGIN == opcode);
10767 int frame_count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010768 int jsframe_count = iterator.Next();
10769 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
10770 Translation::StringFor(opcode),
10771 frame_count,
10772 jsframe_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010773
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010774 while (iterator.HasNext() &&
10775 Translation::BEGIN !=
10776 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
10777 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
10778
10779 switch (opcode) {
10780 case Translation::BEGIN:
10781 UNREACHABLE();
10782 break;
10783
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010784 case Translation::JS_FRAME: {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010785 int ast_id = iterator.Next();
10786 int function_id = iterator.Next();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010787 unsigned height = iterator.Next();
fschneider@chromium.org1805e212011-09-05 10:49:12 +000010788 PrintF(out, "{ast_id=%d, function=", ast_id);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010789 if (function_id != Translation::kSelfLiteralId) {
10790 Object* function = LiteralArray()->get(function_id);
10791 JSFunction::cast(function)->PrintName(out);
10792 } else {
10793 PrintF(out, "<self>");
10794 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010795 PrintF(out, ", height=%u}", height);
10796 break;
10797 }
10798
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010799 case Translation::COMPILED_STUB_FRAME: {
10800 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
10801 PrintF(out, "{kind=%d}", stub_kind);
10802 break;
10803 }
10804
ulan@chromium.org967e2702012-02-28 09:49:15 +000010805 case Translation::ARGUMENTS_ADAPTOR_FRAME:
10806 case Translation::CONSTRUCT_STUB_FRAME: {
10807 int function_id = iterator.Next();
10808 JSFunction* function =
10809 JSFunction::cast(LiteralArray()->get(function_id));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010810 unsigned height = iterator.Next();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010811 PrintF(out, "{function=");
10812 function->PrintName(out);
10813 PrintF(out, ", height=%u}", height);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010814 break;
10815 }
10816
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000010817 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010818 case Translation::SETTER_STUB_FRAME: {
10819 int function_id = iterator.Next();
10820 JSFunction* function =
10821 JSFunction::cast(LiteralArray()->get(function_id));
10822 PrintF(out, "{function=");
10823 function->PrintName(out);
10824 PrintF(out, "}");
10825 break;
10826 }
10827
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010828 case Translation::REGISTER: {
10829 int reg_code = iterator.Next();
10830 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
10831 break;
10832 }
10833
10834 case Translation::INT32_REGISTER: {
10835 int reg_code = iterator.Next();
10836 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
10837 break;
10838 }
10839
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010840 case Translation::UINT32_REGISTER: {
10841 int reg_code = iterator.Next();
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010842 PrintF(out, "{input=%s (unsigned)}",
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010843 converter.NameOfCPURegister(reg_code));
10844 break;
10845 }
10846
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010847 case Translation::DOUBLE_REGISTER: {
10848 int reg_code = iterator.Next();
10849 PrintF(out, "{input=%s}",
10850 DoubleRegister::AllocationIndexToString(reg_code));
10851 break;
10852 }
10853
10854 case Translation::STACK_SLOT: {
10855 int input_slot_index = iterator.Next();
10856 PrintF(out, "{input=%d}", input_slot_index);
10857 break;
10858 }
10859
10860 case Translation::INT32_STACK_SLOT: {
10861 int input_slot_index = iterator.Next();
10862 PrintF(out, "{input=%d}", input_slot_index);
10863 break;
10864 }
10865
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010866 case Translation::UINT32_STACK_SLOT: {
10867 int input_slot_index = iterator.Next();
10868 PrintF(out, "{input=%d (unsigned)}", input_slot_index);
10869 break;
10870 }
10871
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010872 case Translation::DOUBLE_STACK_SLOT: {
10873 int input_slot_index = iterator.Next();
10874 PrintF(out, "{input=%d}", input_slot_index);
10875 break;
10876 }
10877
10878 case Translation::LITERAL: {
10879 unsigned literal_index = iterator.Next();
10880 PrintF(out, "{literal_id=%u}", literal_index);
10881 break;
10882 }
10883
danno@chromium.org59400602013-08-13 17:09:37 +000010884 case Translation::DUPLICATED_OBJECT: {
10885 int object_index = iterator.Next();
10886 PrintF(out, "{object_index=%d}", object_index);
10887 break;
10888 }
10889
10890 case Translation::ARGUMENTS_OBJECT:
10891 case Translation::CAPTURED_OBJECT: {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010892 int args_length = iterator.Next();
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000010893 PrintF(out, "{length=%d}", args_length);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010894 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010895 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010896 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010897 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010898 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010899 }
10900}
10901
10902
whesse@chromium.org023421e2010-12-21 12:19:12 +000010903void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
10904 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010905 this->DeoptPoints());
10906 if (this->DeoptPoints() == 0) return;
10907
10908 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
10909 for (int i = 0; i < this->DeoptPoints(); i++) {
10910 int pc_and_state = this->PcAndState(i)->value();
10911 PrintF("%6d %8d %s\n",
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010912 this->AstId(i).ToInt(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010913 FullCodeGenerator::PcField::decode(pc_and_state),
10914 FullCodeGenerator::State2String(
10915 FullCodeGenerator::StateField::decode(pc_and_state)));
10916 }
10917}
10918
whesse@chromium.org7b260152011-06-20 15:33:18 +000010919
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010920const char* Code::ICState2String(InlineCacheState state) {
10921 switch (state) {
10922 case UNINITIALIZED: return "UNINITIALIZED";
10923 case PREMONOMORPHIC: return "PREMONOMORPHIC";
10924 case MONOMORPHIC: return "MONOMORPHIC";
10925 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000010926 case POLYMORPHIC: return "POLYMORPHIC";
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010927 case MEGAMORPHIC: return "MEGAMORPHIC";
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010928 case GENERIC: return "GENERIC";
yangguo@chromium.org9768bf12013-01-11 14:51:07 +000010929 case DEBUG_STUB: return "DEBUG_STUB";
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010930 }
10931 UNREACHABLE();
10932 return NULL;
10933}
10934
10935
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010936const char* Code::StubType2String(StubType type) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010937 switch (type) {
10938 case NORMAL: return "NORMAL";
10939 case FIELD: return "FIELD";
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000010940 case CONSTANT: return "CONSTANT";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010941 case CALLBACKS: return "CALLBACKS";
10942 case INTERCEPTOR: return "INTERCEPTOR";
machenbach@chromium.org528ce022013-09-23 14:09:36 +000010943 case TRANSITION: return "TRANSITION";
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010944 case NONEXISTENT: return "NONEXISTENT";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010945 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010946 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010947 return NULL;
10948}
10949
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010950
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010951void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010952 PrintF(out, "extra_ic_state = ");
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010953 const char* name = NULL;
10954 switch (kind) {
10955 case CALL_IC:
10956 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
10957 name = "STRING_INDEX_OUT_OF_BOUNDS";
10958 }
10959 break;
10960 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010961 case KEYED_STORE_IC:
10962 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010963 name = "STRICT";
10964 }
10965 break;
10966 default:
10967 break;
10968 }
10969 if (name != NULL) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010970 PrintF(out, "%s\n", name);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010971 } else {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010972 PrintF(out, "%d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010973 }
10974}
10975
10976
whesse@chromium.org023421e2010-12-21 12:19:12 +000010977void Code::Disassemble(const char* name, FILE* out) {
10978 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010979 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010980 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000010981 PrintExtraICState(out, kind(), needs_extended_extra_ic_state(kind()) ?
10982 extended_extra_ic_state() : extra_ic_state());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010983 if (ic_state() == MONOMORPHIC) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010984 PrintF(out, "type = %s\n", StubType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010985 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010986 if (is_call_stub() || is_keyed_call_stub()) {
10987 PrintF(out, "argc = %d\n", arguments_count());
10988 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000010989 if (is_compare_ic_stub()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010990 ASSERT(major_key() == CodeStub::CompareIC);
10991 CompareIC::State left_state, right_state, handler_state;
10992 Token::Value op;
10993 ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state,
10994 &handler_state, &op);
10995 PrintF(out, "compare_state = %s*%s -> %s\n",
10996 CompareIC::GetStateName(left_state),
10997 CompareIC::GetStateName(right_state),
10998 CompareIC::GetStateName(handler_state));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010999 PrintF(out, "compare_operation = %s\n", Token::Name(op));
11000 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011001 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011002 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011003 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011004 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011005 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011006 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011007 }
mads.s.ager31e71382008-08-13 09:32:07 +000011008
whesse@chromium.org023421e2010-12-21 12:19:12 +000011009 PrintF(out, "Instructions (size = %d)\n", instruction_size());
11010 Disassembler::Decode(out, this);
11011 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +000011012
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011013 if (kind() == FUNCTION) {
11014 DeoptimizationOutputData* data =
11015 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +000011016 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011017 } else if (kind() == OPTIMIZED_FUNCTION) {
11018 DeoptimizationInputData* data =
11019 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +000011020 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011021 }
11022 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011023
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +000011024 if (is_crankshafted()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011025 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +000011026 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011027 for (unsigned i = 0; i < table.length(); i++) {
11028 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +000011029 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011030 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +000011031 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011032 SafepointEntry entry = table.GetEntry(i);
11033 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
11034 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011035 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000011036 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011037 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011038 if (entry.argument_count() > 0) {
11039 PrintF(out, " argc: %d", entry.argument_count());
11040 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000011041 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011042 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000011043 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011044 } else if (kind() == FUNCTION) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011045 unsigned offset = back_edge_table_offset();
11046 // If there is no back edge table, the "table start" will be at or after
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011047 // (due to alignment) the end of the instruction stream.
11048 if (static_cast<int>(offset) < instruction_size()) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011049 DisallowHeapAllocation no_gc;
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011050 BackEdgeTable back_edges(this, &no_gc);
danno@chromium.org59400602013-08-13 17:09:37 +000011051
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011052 PrintF(out, "Back edges (size = %u)\n", back_edges.length());
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000011053 PrintF(out, "ast_id pc_offset loop_depth\n");
danno@chromium.org59400602013-08-13 17:09:37 +000011054
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011055 for (uint32_t i = 0; i < back_edges.length(); i++) {
11056 PrintF(out, "%6d %9u %10u\n", back_edges.ast_id(i).ToInt(),
11057 back_edges.pc_offset(i),
11058 back_edges.loop_depth(i));
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011059 }
danno@chromium.org59400602013-08-13 17:09:37 +000011060
whesse@chromium.org023421e2010-12-21 12:19:12 +000011061 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011062 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000011063#ifdef OBJECT_PRINT
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +000011064 if (!type_feedback_info()->IsUndefined()) {
11065 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(out);
11066 PrintF(out, "\n");
11067 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000011068#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011069 }
11070
mads.s.ager31e71382008-08-13 09:32:07 +000011071 PrintF("RelocInfo (size = %d)\n", relocation_size());
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000011072 for (RelocIterator it(this); !it.done(); it.next()) {
11073 it.rinfo()->Print(GetIsolate(), out);
11074 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000011075 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +000011076}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000011077#endif // ENABLE_DISASSEMBLER
11078
11079
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011080MaybeObject* JSObject::SetFastElementsCapacityAndLength(
11081 int capacity,
11082 int length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011083 SetFastElementsCapacitySmiMode smi_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011084 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011085 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011086 ASSERT(!HasExternalArrayElements());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011087 ASSERT(!map()->is_observed());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011088
whesse@chromium.org7b260152011-06-20 15:33:18 +000011089 // Allocate a new fast elements backing store.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011090 FixedArray* new_elements;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011091 MaybeObject* maybe = heap->AllocateUninitializedFixedArray(capacity);
11092 if (!maybe->To(&new_elements)) return maybe;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011093
jkummerow@chromium.orgf3eae902012-05-24 16:42:53 +000011094 ElementsKind elements_kind = GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011095 ElementsKind new_elements_kind;
11096 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
11097 // or if it's allowed and the old elements array contained only SMIs.
11098 bool has_fast_smi_elements =
11099 (smi_mode == kForceSmiElements) ||
11100 ((smi_mode == kAllowSmiElements) && HasFastSmiElements());
11101 if (has_fast_smi_elements) {
11102 if (IsHoleyElementsKind(elements_kind)) {
11103 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
11104 } else {
11105 new_elements_kind = FAST_SMI_ELEMENTS;
11106 }
11107 } else {
11108 if (IsHoleyElementsKind(elements_kind)) {
11109 new_elements_kind = FAST_HOLEY_ELEMENTS;
11110 } else {
11111 new_elements_kind = FAST_ELEMENTS;
11112 }
11113 }
11114 FixedArrayBase* old_elements = elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011115 ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011116 MaybeObject* maybe_obj =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011117 accessor->CopyElements(this, new_elements, elements_kind);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011118 if (maybe_obj->IsFailure()) return maybe_obj;
11119
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011120 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011121 Map* new_map = map();
11122 if (new_elements_kind != elements_kind) {
11123 MaybeObject* maybe =
11124 GetElementsTransitionMap(GetIsolate(), new_elements_kind);
11125 if (!maybe->To(&new_map)) return maybe;
11126 }
11127 ValidateElements();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011128 set_map_and_elements(new_map, new_elements);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011129
11130 // Transition through the allocation site as well if present.
11131 maybe_obj = UpdateAllocationSite(new_elements_kind);
11132 if (maybe_obj->IsFailure()) return maybe_obj;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011133 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011134 FixedArray* parameter_map = FixedArray::cast(old_elements);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000011135 parameter_map->set(1, new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011136 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011137
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011138 if (FLAG_trace_elements_transitions) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011139 PrintElementsTransition(stdout, elements_kind, old_elements,
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011140 GetElementsKind(), new_elements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011141 }
11142
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011143 if (IsJSArray()) {
11144 JSArray::cast(this)->set_length(Smi::FromInt(length));
11145 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000011146 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147}
11148
11149
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000011150bool Code::IsWeakEmbeddedObject(Kind kind, Object* object) {
11151 if (kind != Code::OPTIMIZED_FUNCTION) return false;
11152
11153 if (object->IsMap()) {
11154 return Map::cast(object)->CanTransition() &&
11155 FLAG_collect_maps &&
11156 FLAG_weak_embedded_maps_in_optimized_code;
11157 }
11158
11159 if (object->IsJSObject()) {
11160 return FLAG_weak_embedded_objects_in_optimized_code;
11161 }
11162
11163 return false;
11164}
11165
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011166MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
11167 int capacity,
11168 int length) {
11169 Heap* heap = GetHeap();
11170 // We should never end in here with a pixel or external array.
11171 ASSERT(!HasExternalArrayElements());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011172 ASSERT(!map()->is_observed());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011173
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011174 FixedArrayBase* elems;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011175 { MaybeObject* maybe_obj =
11176 heap->AllocateUninitializedFixedDoubleArray(capacity);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011177 if (!maybe_obj->To(&elems)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011178 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011179
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011180 ElementsKind elements_kind = GetElementsKind();
11181 ElementsKind new_elements_kind = elements_kind;
11182 if (IsHoleyElementsKind(elements_kind)) {
11183 new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
11184 } else {
11185 new_elements_kind = FAST_DOUBLE_ELEMENTS;
11186 }
11187
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011188 Map* new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011189 { MaybeObject* maybe_obj =
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011190 GetElementsTransitionMap(heap->isolate(), new_elements_kind);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011191 if (!maybe_obj->To(&new_map)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011192 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011193
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011194 FixedArrayBase* old_elements = elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011195 ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011196 { MaybeObject* maybe_obj =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000011197 accessor->CopyElements(this, elems, elements_kind);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000011198 if (maybe_obj->IsFailure()) return maybe_obj;
11199 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011200 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011201 ValidateElements();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000011202 set_map_and_elements(new_map, elems);
11203 } else {
11204 FixedArray* parameter_map = FixedArray::cast(old_elements);
11205 parameter_map->set(1, elems);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011206 }
11207
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011208 if (FLAG_trace_elements_transitions) {
11209 PrintElementsTransition(stdout, elements_kind, old_elements,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011210 GetElementsKind(), elems);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011211 }
11212
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011213 if (IsJSArray()) {
11214 JSArray::cast(this)->set_length(Smi::FromInt(length));
11215 }
11216
11217 return this;
11218}
11219
11220
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011221MaybeObject* JSArray::Initialize(int capacity, int length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011222 ASSERT(capacity >= 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011223 return GetHeap()->AllocateJSArrayStorage(this, length, capacity,
11224 INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011225}
11226
11227
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011228void JSArray::Expand(int required_size) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011229 GetIsolate()->factory()->SetElementsCapacityAndLength(
11230 Handle<JSArray>(this), required_size, required_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000011231}
11232
11233
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011234// Returns false if the passed-in index is marked non-configurable,
11235// which will cause the ES5 truncation operation to halt, and thus
11236// no further old values need be collected.
11237static bool GetOldValue(Isolate* isolate,
11238 Handle<JSObject> object,
11239 uint32_t index,
11240 List<Handle<Object> >* old_values,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011241 List<uint32_t>* indices) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011242 PropertyAttributes attributes = object->GetLocalElementAttribute(index);
11243 ASSERT(attributes != ABSENT);
11244 if (attributes == DONT_DELETE) return false;
11245 old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011246 ? Object::GetElement(isolate, object, index)
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011247 : Handle<Object>::cast(isolate->factory()->the_hole_value()));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011248 indices->Add(index);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011249 return true;
11250}
11251
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011252static void EnqueueSpliceRecord(Handle<JSArray> object,
11253 uint32_t index,
11254 Handle<JSArray> deleted,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011255 uint32_t add_count) {
11256 Isolate* isolate = object->GetIsolate();
11257 HandleScope scope(isolate);
11258 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011259 Handle<Object> add_count_object =
11260 isolate->factory()->NewNumberFromUint(add_count);
11261
11262 Handle<Object> args[] =
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011263 { object, index_object, deleted, add_count_object };
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011264
11265 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000011266 Execution::Call(isolate,
11267 Handle<JSFunction>(isolate->observers_enqueue_splice()),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011268 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
11269 &threw);
11270 ASSERT(!threw);
11271}
11272
11273
11274static void BeginPerformSplice(Handle<JSArray> object) {
11275 Isolate* isolate = object->GetIsolate();
11276 HandleScope scope(isolate);
11277 Handle<Object> args[] = { object };
11278
11279 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000011280 Execution::Call(isolate,
11281 Handle<JSFunction>(isolate->observers_begin_perform_splice()),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011282 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
11283 &threw);
11284 ASSERT(!threw);
11285}
11286
11287
11288static void EndPerformSplice(Handle<JSArray> object) {
11289 Isolate* isolate = object->GetIsolate();
11290 HandleScope scope(isolate);
11291 Handle<Object> args[] = { object };
11292
11293 bool threw;
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +000011294 Execution::Call(isolate,
11295 Handle<JSFunction>(isolate->observers_end_perform_splice()),
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011296 isolate->factory()->undefined_value(), ARRAY_SIZE(args), args,
11297 &threw);
11298 ASSERT(!threw);
11299}
11300
11301
ricow@chromium.org7ad65222011-12-19 12:13:11 +000011302MaybeObject* JSArray::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011303 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +000011304 ASSERT(AllowsSetElementsLength());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011305 if (!(FLAG_harmony_observation && map()->is_observed()))
11306 return GetElementsAccessor()->SetLength(this, len);
11307
11308 Isolate* isolate = GetIsolate();
11309 HandleScope scope(isolate);
11310 Handle<JSArray> self(this);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011311 List<uint32_t> indices;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011312 List<Handle<Object> > old_values;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011313 Handle<Object> old_length_handle(self->length(), isolate);
11314 Handle<Object> new_length_handle(len, isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011315 uint32_t old_length = 0;
11316 CHECK(old_length_handle->ToArrayIndex(&old_length));
11317 uint32_t new_length = 0;
11318 if (!new_length_handle->ToArrayIndex(&new_length))
11319 return Failure::InternalError();
11320
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000011321 // Observed arrays should always be in dictionary mode;
11322 // if they were in fast mode, the below is slower than necessary
11323 // as it iterates over the array backing store multiple times.
11324 ASSERT(self->HasDictionaryElements());
11325 static const PropertyAttributes kNoAttrFilter = NONE;
11326 int num_elements = self->NumberOfLocalElements(kNoAttrFilter);
11327 if (num_elements > 0) {
11328 if (old_length == static_cast<uint32_t>(num_elements)) {
11329 // Simple case for arrays without holes.
11330 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
11331 if (!GetOldValue(isolate, self, i, &old_values, &indices)) break;
11332 }
11333 } else {
11334 // For sparse arrays, only iterate over existing elements.
11335 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
11336 self->GetLocalElementKeys(*keys, kNoAttrFilter);
11337 while (num_elements-- > 0) {
11338 uint32_t index = NumberToUint32(keys->get(num_elements));
11339 if (index < new_length) break;
11340 if (!GetOldValue(isolate, self, index, &old_values, &indices)) break;
11341 }
11342 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011343 }
11344
11345 MaybeObject* result =
11346 self->GetElementsAccessor()->SetLength(*self, *new_length_handle);
11347 Handle<Object> hresult;
11348 if (!result->ToHandle(&hresult, isolate)) return result;
11349
11350 CHECK(self->length()->ToArrayIndex(&new_length));
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011351 if (old_length == new_length) return *hresult;
11352
11353 BeginPerformSplice(self);
11354
11355 for (int i = 0; i < indices.length(); ++i) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011356 JSObject::EnqueueChangeRecord(
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011357 self, "deleted", isolate->factory()->Uint32ToString(indices[i]),
11358 old_values[i]);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011359 }
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011360 JSObject::EnqueueChangeRecord(
11361 self, "updated", isolate->factory()->length_string(),
11362 old_length_handle);
11363
11364 EndPerformSplice(self);
11365
11366 uint32_t index = Min(old_length, new_length);
11367 uint32_t add_count = new_length > old_length ? new_length - old_length : 0;
11368 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0;
11369 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011370 if (delete_count > 0) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011371 for (int i = indices.length() - 1; i >= 0; i--) {
11372 JSObject::SetElement(deleted, indices[i] - index, old_values[i], NONE,
11373 kNonStrictMode);
11374 }
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011375
11376 SetProperty(deleted, isolate->factory()->length_string(),
11377 isolate->factory()->NewNumberFromUint(delete_count),
11378 NONE, kNonStrictMode);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011379 }
11380
danno@chromium.org1fd77d52013-06-07 16:01:45 +000011381 EnqueueSpliceRecord(self, index, deleted, add_count);
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000011382
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011383 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011384}
11385
11386
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011387Handle<Map> Map::GetPrototypeTransition(Handle<Map> map,
11388 Handle<Object> prototype) {
11389 FixedArray* cache = map->GetPrototypeTransitions();
11390 int number_of_transitions = map->NumberOfProtoTransitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011391 const int proto_offset =
11392 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
11393 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
11394 const int step = kProtoTransitionElementsPerEntry;
11395 for (int i = 0; i < number_of_transitions; i++) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011396 if (cache->get(proto_offset + i * step) == *prototype) {
11397 Object* result = cache->get(map_offset + i * step);
11398 return Handle<Map>(Map::cast(result));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011399 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011400 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011401 return Handle<Map>();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011402}
11403
11404
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011405Handle<Map> Map::PutPrototypeTransition(Handle<Map> map,
11406 Handle<Object> prototype,
11407 Handle<Map> target_map) {
11408 ASSERT(target_map->IsMap());
11409 ASSERT(HeapObject::cast(*prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011410 // Don't cache prototype transition if this map is shared.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011411 if (map->is_shared() || !FLAG_cache_prototype_transitions) return map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011412
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011413 const int step = kProtoTransitionElementsPerEntry;
11414 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011415
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011416 Handle<FixedArray> cache(map->GetPrototypeTransitions());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011417 int capacity = (cache->length() - header) / step;
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011418 int transitions = map->NumberOfProtoTransitions() + 1;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011419
11420 if (transitions > capacity) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011421 if (capacity > kMaxCachedPrototypeTransitions) return map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011422
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011423 // Grow array by factor 2 over and above what we need.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011424 Factory* factory = map->GetIsolate()->factory();
11425 cache = factory->CopySizeFixedArray(cache, transitions * 2 * step + header);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011426
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011427 CALL_AND_RETRY_OR_DIE(map->GetIsolate(),
11428 map->SetPrototypeTransitions(*cache),
11429 break,
11430 return Handle<Map>());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011431 }
11432
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011433 // Reload number of transitions as GC might shrink them.
11434 int last = map->NumberOfProtoTransitions();
11435 int entry = header + last * step;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011436
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011437 cache->set(entry + kProtoTransitionPrototypeOffset, *prototype);
11438 cache->set(entry + kProtoTransitionMapOffset, *target_map);
11439 map->SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011440
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011441 return map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011442}
11443
11444
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011445void Map::ZapTransitions() {
11446 TransitionArray* transition_array = transitions();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000011447 // TODO(mstarzinger): Temporarily use a slower version instead of the faster
11448 // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
11449 Object** data = transition_array->data_start();
11450 Object* the_hole = GetHeap()->the_hole_value();
11451 int length = transition_array->length();
11452 for (int i = 0; i < length; i++) {
11453 data[i] = the_hole;
11454 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000011455}
11456
11457
11458void Map::ZapPrototypeTransitions() {
11459 FixedArray* proto_transitions = GetPrototypeTransitions();
11460 MemsetPointer(proto_transitions->data_start(),
11461 GetHeap()->the_hole_value(),
11462 proto_transitions->length());
11463}
11464
11465
danno@chromium.org41728482013-06-12 22:31:22 +000011466void Map::AddDependentCompilationInfo(DependentCode::DependencyGroup group,
11467 CompilationInfo* info) {
11468 Handle<DependentCode> dep(dependent_code());
11469 Handle<DependentCode> codes =
11470 DependentCode::Insert(dep, group, info->object_wrapper());
11471 if (*codes != dependent_code()) set_dependent_code(*codes);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011472 info->dependencies(group)->Add(Handle<HeapObject>(this), info->zone());
danno@chromium.org41728482013-06-12 22:31:22 +000011473}
11474
11475
11476void Map::AddDependentCode(DependentCode::DependencyGroup group,
11477 Handle<Code> code) {
11478 Handle<DependentCode> codes = DependentCode::Insert(
11479 Handle<DependentCode>(dependent_code()), group, code);
11480 if (*codes != dependent_code()) set_dependent_code(*codes);
11481}
11482
11483
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011484DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
11485 Recompute(entries);
yangguo@chromium.org003650e2013-01-24 16:31:08 +000011486}
11487
11488
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011489void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
11490 start_indexes_[0] = 0;
11491 for (int g = 1; g <= kGroupCount; g++) {
11492 int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
11493 start_indexes_[g] = start_indexes_[g - 1] + count;
11494 }
11495}
11496
11497
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011498DependentCode* DependentCode::ForObject(Handle<HeapObject> object,
11499 DependencyGroup group) {
11500 AllowDeferredHandleDereference dependencies_are_safe;
11501 if (group == DependentCode::kPropertyCellChangedGroup) {
11502 return Handle<PropertyCell>::cast(object)->dependent_code();
11503 }
11504 return Handle<Map>::cast(object)->dependent_code();
11505}
11506
11507
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011508Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
11509 DependencyGroup group,
danno@chromium.org41728482013-06-12 22:31:22 +000011510 Handle<Object> object) {
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011511 GroupStartIndexes starts(*entries);
11512 int start = starts.at(group);
11513 int end = starts.at(group + 1);
11514 int number_of_entries = starts.number_of_entries();
danno@chromium.org41728482013-06-12 22:31:22 +000011515 if (start < end && entries->object_at(end - 1) == *object) {
11516 // Do not append the compilation info if it is already in the array.
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011517 // It is sufficient to just check only the last element because
11518 // we process embedded maps of an optimized code in one batch.
11519 return entries;
11520 }
11521 if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
11522 Factory* factory = entries->GetIsolate()->factory();
11523 int capacity = kCodesStartIndex + number_of_entries + 1;
11524 if (capacity > 5) capacity = capacity * 5 / 4;
11525 Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000011526 factory->CopySizeFixedArray(entries, capacity, TENURED));
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011527 // The number of codes can change after GC.
11528 starts.Recompute(*entries);
11529 start = starts.at(group);
11530 end = starts.at(group + 1);
11531 number_of_entries = starts.number_of_entries();
11532 for (int i = 0; i < number_of_entries; i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000011533 entries->clear_at(i);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011534 }
11535 // If the old fixed array was empty, we need to reset counters of the
11536 // new array.
11537 if (number_of_entries == 0) {
11538 for (int g = 0; g < kGroupCount; g++) {
11539 new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
11540 }
11541 }
11542 entries = new_entries;
11543 }
11544 entries->ExtendGroup(group);
danno@chromium.org41728482013-06-12 22:31:22 +000011545 entries->set_object_at(end, *object);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011546 entries->set_number_of_entries(group, end + 1 - start);
11547 return entries;
11548}
11549
11550
danno@chromium.org41728482013-06-12 22:31:22 +000011551void DependentCode::UpdateToFinishedCode(DependencyGroup group,
11552 CompilationInfo* info,
11553 Code* code) {
11554 DisallowHeapAllocation no_gc;
11555 AllowDeferredHandleDereference get_object_wrapper;
11556 Foreign* info_wrapper = *info->object_wrapper();
11557 GroupStartIndexes starts(this);
11558 int start = starts.at(group);
11559 int end = starts.at(group + 1);
11560 for (int i = start; i < end; i++) {
11561 if (object_at(i) == info_wrapper) {
11562 set_object_at(i, code);
11563 break;
11564 }
11565 }
11566
11567#ifdef DEBUG
11568 for (int i = start; i < end; i++) {
11569 ASSERT(is_code_at(i) || compilation_info_at(i) != info);
11570 }
11571#endif
11572}
11573
11574
11575void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
11576 CompilationInfo* info) {
11577 DisallowHeapAllocation no_allocation;
11578 AllowDeferredHandleDereference get_object_wrapper;
11579 Foreign* info_wrapper = *info->object_wrapper();
11580 GroupStartIndexes starts(this);
11581 int start = starts.at(group);
11582 int end = starts.at(group + 1);
11583 // Find compilation info wrapper.
11584 int info_pos = -1;
11585 for (int i = start; i < end; i++) {
11586 if (object_at(i) == info_wrapper) {
11587 info_pos = i;
11588 break;
11589 }
11590 }
11591 if (info_pos == -1) return; // Not found.
11592 int gap = info_pos;
11593 // Use the last of each group to fill the gap in the previous group.
11594 for (int i = group; i < kGroupCount; i++) {
11595 int last_of_group = starts.at(i + 1) - 1;
11596 ASSERT(last_of_group >= gap);
11597 if (last_of_group == gap) continue;
11598 copy(last_of_group, gap);
11599 gap = last_of_group;
11600 }
11601 ASSERT(gap == starts.number_of_entries() - 1);
11602 clear_at(gap); // Clear last gap.
11603 set_number_of_entries(group, end - start - 1);
11604
11605#ifdef DEBUG
11606 for (int i = start; i < end - 1; i++) {
11607 ASSERT(is_code_at(i) || compilation_info_at(i) != info);
11608 }
11609#endif
11610}
11611
11612
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011613bool DependentCode::Contains(DependencyGroup group, Code* code) {
11614 GroupStartIndexes starts(this);
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +000011615 int start = starts.at(group);
11616 int end = starts.at(group + 1);
11617 for (int i = start; i < end; i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000011618 if (object_at(i) == code) return true;
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000011619 }
11620 return false;
11621}
11622
11623
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011624void DependentCode::DeoptimizeDependentCodeGroup(
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000011625 Isolate* isolate,
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011626 DependentCode::DependencyGroup group) {
danno@chromium.org59400602013-08-13 17:09:37 +000011627 ASSERT(AllowCodeDependencyChange::IsAllowed());
rossberg@chromium.org79e79022013-06-03 15:43:46 +000011628 DisallowHeapAllocation no_allocation_scope;
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011629 DependentCode::GroupStartIndexes starts(this);
11630 int start = starts.at(group);
11631 int end = starts.at(group + 1);
danno@chromium.org41728482013-06-12 22:31:22 +000011632 int code_entries = starts.number_of_entries();
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011633 if (start == end) return;
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000011634
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011635 // Mark all the code that needs to be deoptimized.
11636 bool marked = false;
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011637 for (int i = start; i < end; i++) {
danno@chromium.org41728482013-06-12 22:31:22 +000011638 if (is_code_at(i)) {
11639 Code* code = code_at(i);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011640 if (!code->marked_for_deoptimization()) {
11641 code->set_marked_for_deoptimization(true);
11642 marked = true;
11643 }
danno@chromium.org41728482013-06-12 22:31:22 +000011644 } else {
11645 CompilationInfo* info = compilation_info_at(i);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011646 info->AbortDueToDependencyChange();
danno@chromium.org41728482013-06-12 22:31:22 +000011647 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011648 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011649 // Compact the array by moving all subsequent groups to fill in the new holes.
danno@chromium.org41728482013-06-12 22:31:22 +000011650 for (int src = end, dst = start; src < code_entries; src++, dst++) {
11651 copy(src, dst);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011652 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011653 // Now the holes are at the end of the array, zap them for heap-verifier.
11654 int removed = end - start;
danno@chromium.org41728482013-06-12 22:31:22 +000011655 for (int i = code_entries - removed; i < code_entries; i++) {
11656 clear_at(i);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011657 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011658 set_number_of_entries(group, 0);
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000011659
11660 if (marked) Deoptimizer::DeoptimizeMarkedCode(isolate);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000011661}
11662
11663
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011664Handle<Object> JSObject::SetPrototype(Handle<JSObject> object,
11665 Handle<Object> value,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000011666 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011667#ifdef DEBUG
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011668 int size = object->Size();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000011669#endif
11670
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011671 Isolate* isolate = object->GetIsolate();
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011672 Heap* heap = isolate->heap();
ager@chromium.org5c838252010-02-19 08:53:10 +000011673 // Silently ignore the change if value is not a JSObject or null.
11674 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000011675 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +000011676
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011677 // From 8.6.2 Object Internal Methods
11678 // ...
11679 // In addition, if [[Extensible]] is false the value of the [[Class]] and
11680 // [[Prototype]] internal properties of the object may not be modified.
11681 // ...
11682 // Implementation specific extensions that modify [[Class]], [[Prototype]]
11683 // or [[Extensible]] must not violate the invariants defined in the preceding
11684 // paragraph.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011685 if (!object->map()->is_extensible()) {
11686 Handle<Object> args[] = { object };
11687 Handle<Object> error = isolate->factory()->NewTypeError(
11688 "non_extensible_proto", HandleVector(args, ARRAY_SIZE(args)));
11689 isolate->Throw(*error);
11690 return Handle<Object>();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011691 }
11692
ager@chromium.org5c838252010-02-19 08:53:10 +000011693 // Before we can set the prototype we need to be sure
11694 // prototype cycles are prevented.
11695 // It is sufficient to validate that the receiver is not in the new prototype
11696 // chain.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011697 for (Object* pt = *value;
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011698 pt != heap->null_value();
11699 pt = pt->GetPrototype(isolate)) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011700 if (JSReceiver::cast(pt) == *object) {
ager@chromium.org5c838252010-02-19 08:53:10 +000011701 // Cycle detected.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011702 Handle<Object> error = isolate->factory()->NewError(
11703 "cyclic_proto", HandleVector<Object>(NULL, 0));
11704 isolate->Throw(*error);
11705 return Handle<Object>();
ager@chromium.org5c838252010-02-19 08:53:10 +000011706 }
11707 }
11708
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011709 Handle<JSObject> real_receiver = object;
ager@chromium.org5c838252010-02-19 08:53:10 +000011710
11711 if (skip_hidden_prototypes) {
11712 // Find the first object in the chain whose prototype object is not
11713 // hidden and set the new prototype on that object.
11714 Object* current_proto = real_receiver->GetPrototype();
11715 while (current_proto->IsJSObject() &&
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011716 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
11717 real_receiver = handle(JSObject::cast(current_proto), isolate);
hpayer@chromium.org8432c912013-02-28 15:55:26 +000011718 current_proto = current_proto->GetPrototype(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +000011719 }
11720 }
11721
11722 // Set the new prototype of the object.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011723 Handle<Map> map(real_receiver->map());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011724
11725 // Nothing to do if prototype is already set.
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011726 if (map->prototype() == *value) return value;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011727
mmassi@chromium.org7028c052012-06-13 11:51:58 +000011728 if (value->IsJSObject()) {
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011729 JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
mmassi@chromium.org7028c052012-06-13 11:51:58 +000011730 }
11731
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011732 Handle<Map> new_map = Map::GetPrototypeTransition(map, value);
11733 if (new_map.is_null()) {
11734 new_map = Map::Copy(map);
11735 Map::PutPrototypeTransition(map, value, new_map);
11736 new_map->set_prototype(*value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011737 }
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011738 ASSERT(new_map->prototype() == *value);
11739 real_receiver->set_map(*new_map);
ager@chromium.org5c838252010-02-19 08:53:10 +000011740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011741 heap->ClearInstanceofCache();
machenbach@chromium.orgc1789ee2013-07-05 07:09:57 +000011742 ASSERT(size == object->Size());
ager@chromium.org5c838252010-02-19 08:53:10 +000011743 return value;
11744}
11745
11746
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011747MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
11748 uint32_t first_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011749 uint32_t arg_count,
11750 EnsureElementsMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011751 // Elements in |Arguments| are ordered backwards (because they're on the
11752 // stack), but the method that's called here iterates over them in forward
11753 // direction.
11754 return EnsureCanContainElements(
11755 args->arguments() - first_arg - (arg_count - 1),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011756 arg_count, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011757}
11758
11759
ulan@chromium.org750145a2013-03-07 15:14:13 +000011760AccessorPair* JSObject::GetLocalPropertyAccessorPair(Name* name) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011761 uint32_t index = 0;
11762 if (name->AsArrayIndex(&index)) {
11763 return GetLocalElementAccessorPair(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011765
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011766 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011767 LocalLookupRealNamedProperty(name, &lookup);
11768
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011769 if (lookup.IsPropertyCallbacks() &&
11770 lookup.GetCallbackObject()->IsAccessorPair()) {
11771 return AccessorPair::cast(lookup.GetCallbackObject());
11772 }
11773 return NULL;
11774}
11775
11776
11777AccessorPair* JSObject::GetLocalElementAccessorPair(uint32_t index) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011778 if (IsJSGlobalProxy()) {
11779 Object* proto = GetPrototype();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011780 if (proto->IsNull()) return NULL;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011781 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011782 return JSObject::cast(proto)->GetLocalElementAccessorPair(index);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011783 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011785 // Check for lookup interceptor.
11786 if (HasIndexedInterceptor()) return NULL;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000011787
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011788 return GetElementsAccessor()->GetAccessorPair(this, this, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011789}
11790
11791
lrn@chromium.org303ada72010-10-27 09:33:13 +000011792MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011793 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011794 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011795 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011796 bool check_prototype,
11797 SetPropertyMode set_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011798 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000011799 HandleScope scope(isolate);
11800
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801 // Make sure that the top context does not change when doing
11802 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000011803 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000011804
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
11806 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011808 if (!interceptor->setter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +000011809 v8::IndexedPropertySetterCallback setter =
11810 v8::ToCData<v8::IndexedPropertySetterCallback>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011811 LOG(isolate,
11812 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000011813 PropertyCallbackArguments args(isolate, interceptor->data(), this, this);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011814 v8::Handle<v8::Value> result =
11815 args.Call(setter, index, v8::Utils::ToLocal(value_handle));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011816 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 if (!result.IsEmpty()) return *value_handle;
11818 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011819 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011820 this_handle->SetElementWithoutInterceptor(index,
11821 *value_handle,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011822 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011823 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011824 check_prototype,
11825 set_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011826 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827 return raw_result;
11828}
11829
11830
lrn@chromium.org303ada72010-10-27 09:33:13 +000011831MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
11832 Object* structure,
11833 uint32_t index,
11834 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011835 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000011836 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011837
11838 // api style callbacks.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011839 if (structure->IsExecutableAccessorInfo()) {
11840 Handle<ExecutableAccessorInfo> data(
11841 ExecutableAccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011842 Object* fun_obj = data->getter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +000011843 v8::AccessorGetterCallback call_fun =
11844 v8::ToCData<v8::AccessorGetterCallback>(fun_obj);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011845 if (call_fun == NULL) return isolate->heap()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011846 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011847 Handle<JSObject> self(JSObject::cast(receiver));
11848 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011850 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011851 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000011852 PropertyCallbackArguments
11853 args(isolate, data->data(), *self, *holder_handle);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011854 v8::Handle<v8::Value> result = args.Call(call_fun, v8::Utils::ToLocal(key));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011855 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
11856 if (result.IsEmpty()) return isolate->heap()->undefined_value();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000011857 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
11858 result_internal->VerifyApiCallResultType();
11859 return *result_internal;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011860 }
11861
11862 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011863 if (structure->IsAccessorPair()) {
11864 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011865 if (getter->IsSpecFunction()) {
11866 // TODO(rossberg): nicer would be to cast to some JSCallable here...
11867 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011868 }
11869 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011871 }
11872
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011873 if (structure->IsDeclaredAccessorInfo()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +000011874 return GetDeclaredAccessorProperty(receiver,
11875 DeclaredAccessorInfo::cast(structure),
11876 isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011877 }
11878
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011879 UNREACHABLE();
11880 return NULL;
11881}
11882
11883
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011884Handle<Object> JSObject::SetElementWithCallback(Handle<JSObject> object,
11885 Handle<Object> structure,
11886 uint32_t index,
11887 Handle<Object> value,
11888 Handle<JSObject> holder,
11889 StrictModeFlag strict_mode) {
11890 Isolate* isolate = object->GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011891
11892 // We should never get here to initialize a const with the hole
11893 // value since a const declaration would conflict with the setter.
11894 ASSERT(!value->IsTheHole());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011895
11896 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +000011897 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011898 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +000011899 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011900
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011901 if (structure->IsExecutableAccessorInfo()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011902 // api style callbacks
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011903 Handle<ExecutableAccessorInfo> data =
11904 Handle<ExecutableAccessorInfo>::cast(structure);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011905 Object* call_obj = data->setter();
verwaest@chromium.org662436e2013-08-28 08:41:27 +000011906 v8::AccessorSetterCallback call_fun =
11907 v8::ToCData<v8::AccessorSetterCallback>(call_obj);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011908 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011909 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11910 Handle<String> key(isolate->factory()->NumberToString(number));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011911 LOG(isolate, ApiNamedPropertyAccess("store", *object, *key));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000011912 PropertyCallbackArguments
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011913 args(isolate, data->data(), *object, *holder);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000011914 args.Call(call_fun,
11915 v8::Utils::ToLocal(key),
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011916 v8::Utils::ToLocal(value));
11917 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
11918 return value;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011919 }
11920
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011921 if (structure->IsAccessorPair()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011922 Handle<Object> setter(AccessorPair::cast(*structure)->setter(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011923 if (setter->IsSpecFunction()) {
11924 // TODO(rossberg): nicer would be to cast to some JSCallable here...
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011925 return SetPropertyWithDefinedSetter(
11926 object, Handle<JSReceiver>::cast(setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011927 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000011928 if (strict_mode == kNonStrictMode) {
11929 return value;
11930 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011931 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011932 Handle<Object> args[2] = { key, holder };
11933 Handle<Object> error = isolate->factory()->NewTypeError(
11934 "no_setter_in_callback", HandleVector(args, 2));
11935 isolate->Throw(*error);
11936 return Handle<Object>();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011937 }
11938 }
11939
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011940 // TODO(dcarney): Handle correctly.
11941 if (structure->IsDeclaredAccessorInfo()) return value;
11942
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011943 UNREACHABLE();
machenbach@chromium.org528ce022013-09-23 14:09:36 +000011944 return Handle<Object>();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011945}
11946
11947
whesse@chromium.org7b260152011-06-20 15:33:18 +000011948bool JSObject::HasFastArgumentsElements() {
11949 Heap* heap = GetHeap();
11950 if (!elements()->IsFixedArray()) return false;
11951 FixedArray* elements = FixedArray::cast(this->elements());
11952 if (elements->map() != heap->non_strict_arguments_elements_map()) {
11953 return false;
11954 }
11955 FixedArray* arguments = FixedArray::cast(elements->get(1));
11956 return !arguments->IsDictionary();
11957}
11958
11959
11960bool JSObject::HasDictionaryArgumentsElements() {
11961 Heap* heap = GetHeap();
11962 if (!elements()->IsFixedArray()) return false;
11963 FixedArray* elements = FixedArray::cast(this->elements());
11964 if (elements->map() != heap->non_strict_arguments_elements_map()) {
11965 return false;
11966 }
11967 FixedArray* arguments = FixedArray::cast(elements->get(1));
11968 return arguments->IsDictionary();
11969}
11970
11971
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011972// Adding n elements in fast case is O(n*n).
11973// Note: revisit design to have dual undefined values to capture absent
11974// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011975MaybeObject* JSObject::SetFastElement(uint32_t index,
11976 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011977 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011978 bool check_prototype) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011979 ASSERT(HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011980 HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981
ulan@chromium.org906e2fb2013-05-14 08:14:38 +000011982 // Array optimizations rely on the prototype lookups of Array objects always
11983 // returning undefined. If there is a store to the initial prototype object,
11984 // make sure all of these optimizations are invalidated.
11985 Isolate* isolate(GetIsolate());
11986 if (isolate->is_initial_object_prototype(this) ||
11987 isolate->is_initial_array_prototype(this)) {
11988 HandleScope scope(GetIsolate());
11989 map()->dependent_code()->DeoptimizeDependentCodeGroup(
11990 GetIsolate(),
11991 DependentCode::kElementsCantBeAddedGroup);
11992 }
11993
whesse@chromium.org7b260152011-06-20 15:33:18 +000011994 FixedArray* backing_store = FixedArray::cast(elements());
11995 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
11996 backing_store = FixedArray::cast(backing_store->get(1));
11997 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011998 MaybeObject* maybe = EnsureWritableFastElements();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011999 if (!maybe->To(&backing_store)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012000 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012001 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012002
lrn@chromium.org5d00b602011-01-05 09:51:43 +000012003 if (check_prototype &&
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012004 (index >= capacity || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000012005 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000012006 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
12007 value,
12008 &found,
12009 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000012010 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012011 }
12012
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012013 uint32_t new_capacity = capacity;
12014 // Check if the length property of this object needs to be updated.
12015 uint32_t array_length = 0;
12016 bool must_update_array_length = false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012017 bool introduces_holes = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012018 if (IsJSArray()) {
12019 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012020 introduces_holes = index > array_length;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012021 if (index >= array_length) {
12022 must_update_array_length = true;
12023 array_length = index + 1;
12024 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012025 } else {
12026 introduces_holes = index >= capacity;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012027 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012028
12029 // If the array is growing, and it's not growth by a single element at the
12030 // end, make sure that the ElementsKind is HOLEY.
12031 ElementsKind elements_kind = GetElementsKind();
12032 if (introduces_holes &&
12033 IsFastElementsKind(elements_kind) &&
12034 !IsFastHoleyElementsKind(elements_kind)) {
12035 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12036 MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
12037 if (maybe->IsFailure()) return maybe;
12038 }
12039
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012040 // Check if the capacity of the backing store needs to be increased, or if
12041 // a transition to slow elements is necessary.
12042 if (index >= capacity) {
12043 bool convert_to_slow = true;
12044 if ((index - capacity) < kMaxGap) {
12045 new_capacity = NewElementsCapacity(index + 1);
12046 ASSERT(new_capacity > index);
12047 if (!ShouldConvertToSlowElements(new_capacity)) {
12048 convert_to_slow = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012049 }
12050 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012051 if (convert_to_slow) {
12052 MaybeObject* result = NormalizeElements();
12053 if (result->IsFailure()) return result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012054 return SetDictionaryElement(index, value, NONE, strict_mode,
12055 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012056 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012057 }
12058 // Convert to fast double elements if appropriate.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012059 if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012060 // Consider fixing the boilerplate as well if we have one.
12061 ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
12062 ? FAST_HOLEY_DOUBLE_ELEMENTS
12063 : FAST_DOUBLE_ELEMENTS;
12064
danno@chromium.orgbee51992013-07-10 14:57:15 +000012065 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012066 if (maybe_failure->IsFailure()) return maybe_failure;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012067
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012068 MaybeObject* maybe =
12069 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
12070 if (maybe->IsFailure()) return maybe;
12071 FixedDoubleArray::cast(elements())->set(index, value->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012072 ValidateElements();
ager@chromium.orgbdf2f942008-10-17 07:23:00 +000012073 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012074 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012075 // Change elements kind from Smi-only to generic FAST if necessary.
12076 if (HasFastSmiElements() && !value->IsSmi()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012077 Map* new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012078 ElementsKind kind = HasFastHoleyElements()
12079 ? FAST_HOLEY_ELEMENTS
12080 : FAST_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012081
danno@chromium.orgbee51992013-07-10 14:57:15 +000012082 MaybeObject* maybe_failure = UpdateAllocationSite(kind);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012083 if (maybe_failure->IsFailure()) return maybe_failure;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012084
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012085 MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
12086 kind);
12087 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
12088
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012089 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012090 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012091 // Increase backing store capacity if that's been decided previously.
12092 if (new_capacity != capacity) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012093 FixedArray* new_elements;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012094 SetFastElementsCapacitySmiMode smi_mode =
12095 value->IsSmi() && HasFastSmiElements()
12096 ? kAllowSmiElements
12097 : kDontAllowSmiElements;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012098 { MaybeObject* maybe =
12099 SetFastElementsCapacityAndLength(new_capacity,
12100 array_length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012101 smi_mode);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012102 if (!maybe->To(&new_elements)) return maybe;
12103 }
12104 new_elements->set(index, value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012105 ValidateElements();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012106 return value;
12107 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012108
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012109 // Finally, set the new element and length.
12110 ASSERT(elements()->IsFixedArray());
12111 backing_store->set(index, value);
12112 if (must_update_array_length) {
12113 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
12114 }
12115 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012116}
12117
12118
12119MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012120 Object* value_raw,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012121 PropertyAttributes attributes,
whesse@chromium.org7b260152011-06-20 15:33:18 +000012122 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012123 bool check_prototype,
12124 SetPropertyMode set_mode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012125 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
12126 Isolate* isolate = GetIsolate();
12127 Heap* heap = isolate->heap();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012128 Handle<JSObject> self(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012129 Handle<Object> value(value_raw, isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012130
12131 // Insert element in the dictionary.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012132 Handle<FixedArray> elements(FixedArray::cast(this->elements()));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012133 bool is_arguments =
12134 (elements->map() == heap->non_strict_arguments_elements_map());
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012135 Handle<SeededNumberDictionary> dictionary(is_arguments
12136 ? SeededNumberDictionary::cast(elements->get(1))
12137 : SeededNumberDictionary::cast(*elements));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012138
12139 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012140 if (entry != SeededNumberDictionary::kNotFound) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012141 Handle<Object> element(dictionary->ValueAt(entry), isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012142 PropertyDetails details = dictionary->DetailsAt(entry);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012143 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012144 Handle<Object> result = SetElementWithCallback(self, element, index,
12145 value, self, strict_mode);
12146 RETURN_IF_EMPTY_HANDLE(isolate, result);
12147 return *result;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012148 } else {
12149 dictionary->UpdateMaxNumberKey(index);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000012150 // If a value has not been initialized we allow writing to it even if it
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012151 // is read-only (a declared const that has not been initialized). If a
12152 // value is being defined we skip attribute checks completely.
12153 if (set_mode == DEFINE_PROPERTY) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +000012154 details = PropertyDetails(
12155 attributes, NORMAL, details.dictionary_index());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012156 dictionary->DetailsAtPut(entry, details);
12157 } else if (details.IsReadOnly() && !element->IsTheHole()) {
12158 if (strict_mode == kNonStrictMode) {
12159 return isolate->heap()->undefined_value();
12160 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012161 Handle<Object> holder(this, isolate);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012162 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12163 Handle<Object> args[2] = { number, holder };
12164 Handle<Object> error =
12165 isolate->factory()->NewTypeError("strict_read_only_property",
12166 HandleVector(args, 2));
12167 return isolate->Throw(*error);
12168 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012169 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012170 // Elements of the arguments object in slow mode might be slow aliases.
12171 if (is_arguments && element->IsAliasedArgumentsEntry()) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012172 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(*element);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012173 Context* context = Context::cast(elements->get(0));
12174 int context_index = entry->aliased_context_slot();
12175 ASSERT(!context->get(context_index)->IsTheHole());
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012176 context->set(context_index, *value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012177 // For elements that are still writable we keep slow aliasing.
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012178 if (!details.IsReadOnly()) value = element;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012179 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012180 dictionary->ValueAtPut(entry, *value);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012181 }
12182 } else {
12183 // Index not already used. Look for an accessor in the prototype chain.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012184 // Can cause GC!
whesse@chromium.org7b260152011-06-20 15:33:18 +000012185 if (check_prototype) {
12186 bool found;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012187 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(
12188 index, *value, &found, strict_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012189 if (found) return result;
12190 }
12191 // When we set the is_extensible flag to false we always force the
12192 // element into dictionary mode (and force them to stay there).
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012193 if (!self->map()->is_extensible()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012194 if (strict_mode == kNonStrictMode) {
12195 return isolate->heap()->undefined_value();
12196 } else {
12197 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
12198 Handle<String> name = isolate->factory()->NumberToString(number);
12199 Handle<Object> args[1] = { name };
12200 Handle<Object> error =
12201 isolate->factory()->NewTypeError("object_not_extensible",
12202 HandleVector(args, 1));
12203 return isolate->Throw(*error);
12204 }
12205 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000012206 FixedArrayBase* new_dictionary;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000012207 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012208 MaybeObject* maybe = dictionary->AddNumberEntry(index, *value, details);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012209 if (!maybe->To(&new_dictionary)) return maybe;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012210 if (*dictionary != SeededNumberDictionary::cast(new_dictionary)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012211 if (is_arguments) {
12212 elements->set(1, new_dictionary);
12213 } else {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012214 self->set_elements(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012215 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012216 dictionary =
12217 handle(SeededNumberDictionary::cast(new_dictionary), isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012218 }
12219 }
12220
12221 // Update the array length if this JSObject is an array.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012222 if (self->IsJSArray()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012223 MaybeObject* result =
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012224 JSArray::cast(*self)->JSArrayUpdateLengthFromIndex(index, *value);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012225 if (result->IsFailure()) return result;
12226 }
12227
12228 // Attempt to put this object back in fast case.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012229 if (self->ShouldConvertToFastElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012230 uint32_t new_length = 0;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012231 if (self->IsJSArray()) {
12232 CHECK(JSArray::cast(*self)->length()->ToArrayIndex(&new_length));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012233 } else {
12234 new_length = dictionary->max_number_key() + 1;
12235 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012236 SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays
12237 ? kAllowSmiElements
12238 : kDontAllowSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012239 bool has_smi_only_elements = false;
12240 bool should_convert_to_fast_double_elements =
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012241 self->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012242 if (has_smi_only_elements) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012243 smi_mode = kForceSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012244 }
12245 MaybeObject* result = should_convert_to_fast_double_elements
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012246 ? self->SetFastDoubleElementsCapacityAndLength(new_length, new_length)
12247 : self->SetFastElementsCapacityAndLength(
12248 new_length, new_length, smi_mode);
12249 self->ValidateElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012250 if (result->IsFailure()) return result;
12251#ifdef DEBUG
12252 if (FLAG_trace_normalization) {
12253 PrintF("Object elements are fast case again:\n");
12254 Print();
12255 }
12256#endif
12257 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000012258 return *value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012259}
12260
ricow@chromium.org0b9f8502010-08-18 07:45:01 +000012261
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012262MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
12263 uint32_t index,
12264 Object* value,
12265 StrictModeFlag strict_mode,
12266 bool check_prototype) {
12267 ASSERT(HasFastDoubleElements());
12268
yangguo@chromium.org56454712012-02-16 15:33:53 +000012269 FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
12270 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012271
12272 // If storing to an element that isn't in the array, pass the store request
12273 // up the prototype chain before storing in the receiver's elements.
12274 if (check_prototype &&
yangguo@chromium.org56454712012-02-16 15:33:53 +000012275 (index >= elms_length ||
12276 FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012277 bool found;
12278 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
12279 value,
12280 &found,
12281 strict_mode);
12282 if (found) return result;
12283 }
12284
12285 // If the value object is not a heap number, switch to fast elements and try
12286 // again.
12287 bool value_is_smi = value->IsSmi();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012288 bool introduces_holes = true;
12289 uint32_t length = elms_length;
12290 if (IsJSArray()) {
12291 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
12292 introduces_holes = index > length;
12293 } else {
12294 introduces_holes = index >= elms_length;
12295 }
12296
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012297 if (!value->IsNumber()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012298 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
12299 elms_length,
12300 length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012301 kDontAllowSmiElements);
12302 if (maybe_obj->IsFailure()) return maybe_obj;
12303 maybe_obj = SetFastElement(index, value, strict_mode, check_prototype);
12304 if (maybe_obj->IsFailure()) return maybe_obj;
12305 ValidateElements();
12306 return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012307 }
12308
12309 double double_value = value_is_smi
12310 ? static_cast<double>(Smi::cast(value)->value())
12311 : HeapNumber::cast(value)->value();
12312
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012313 // If the array is growing, and it's not growth by a single element at the
12314 // end, make sure that the ElementsKind is HOLEY.
12315 ElementsKind elements_kind = GetElementsKind();
12316 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
12317 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
12318 MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
12319 if (maybe->IsFailure()) return maybe;
12320 }
12321
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012322 // Check whether there is extra space in the fixed array.
12323 if (index < elms_length) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000012324 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012325 elms->set(index, double_value);
12326 if (IsJSArray()) {
12327 // Update the length of the array if needed.
12328 uint32_t array_length = 0;
12329 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
12330 if (index >= array_length) {
12331 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
12332 }
12333 }
12334 return value;
12335 }
12336
12337 // Allow gap in fast case.
12338 if ((index - elms_length) < kMaxGap) {
12339 // Try allocating extra space.
12340 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +000012341 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012342 ASSERT(static_cast<uint32_t>(new_capacity) > index);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012343 MaybeObject* maybe_obj =
12344 SetFastDoubleElementsCapacityAndLength(new_capacity, index + 1);
12345 if (maybe_obj->IsFailure()) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012346 FixedDoubleArray::cast(elements())->set(index, double_value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012347 ValidateElements();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012348 return value;
12349 }
12350 }
12351
12352 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012353 ASSERT(HasFastDoubleElements());
12354 ASSERT(map()->has_fast_double_elements());
12355 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012356 Object* obj;
12357 { MaybeObject* maybe_obj = NormalizeElements();
12358 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12359 }
12360 ASSERT(HasDictionaryElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012361 return SetElement(index, value, NONE, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012362}
12363
12364
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000012365Handle<Object> JSReceiver::SetElement(Handle<JSReceiver> object,
12366 uint32_t index,
12367 Handle<Object> value,
12368 PropertyAttributes attributes,
12369 StrictModeFlag strict_mode) {
12370 if (object->IsJSProxy()) {
12371 return JSProxy::SetElementWithHandler(
12372 Handle<JSProxy>::cast(object), object, index, value, strict_mode);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012373 }
jkummerow@chromium.org8fa5bd92013-09-02 11:45:09 +000012374 return JSObject::SetElement(
12375 Handle<JSObject>::cast(object), index, value, attributes, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012376}
12377
12378
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012379Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
12380 uint32_t index,
12381 Handle<Object> value,
12382 StrictModeFlag strict_mode) {
12383 ASSERT(!object->HasExternalArrayElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012384 CALL_HEAP_FUNCTION(
12385 object->GetIsolate(),
12386 object->SetElement(index, *value, NONE, strict_mode, false),
12387 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012388}
12389
12390
12391Handle<Object> JSObject::SetElement(Handle<JSObject> object,
12392 uint32_t index,
12393 Handle<Object> value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012394 PropertyAttributes attr,
12395 StrictModeFlag strict_mode,
12396 SetPropertyMode set_mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012397 if (object->HasExternalArrayElements()) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000012398 if (!value->IsNumber() && !value->IsUndefined()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012399 bool has_exception;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +000012400 Handle<Object> number =
12401 Execution::ToNumber(object->GetIsolate(), value, &has_exception);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012402 if (has_exception) return Handle<Object>();
12403 value = number;
12404 }
12405 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012406 CALL_HEAP_FUNCTION(
12407 object->GetIsolate(),
12408 object->SetElement(index, *value, attr, strict_mode, true, set_mode),
12409 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012410}
12411
12412
lrn@chromium.org5d00b602011-01-05 09:51:43 +000012413MaybeObject* JSObject::SetElement(uint32_t index,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012414 Object* value_raw,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012415 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012416 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012417 bool check_prototype,
12418 SetPropertyMode set_mode) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012419 Isolate* isolate = GetIsolate();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012421 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012422 if (IsAccessCheckNeeded()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012423 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
12424 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
danno@chromium.org169691d2013-07-15 08:01:13 +000012425 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012426 return value_raw;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012428 }
12429
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012430 if (IsJSGlobalProxy()) {
12431 Object* proto = GetPrototype();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012432 if (proto->IsNull()) return value_raw;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012433 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012434 return JSObject::cast(proto)->SetElement(index,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012435 value_raw,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012436 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012437 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012438 check_prototype,
12439 set_mode);
12440 }
12441
12442 // Don't allow element properties to be redefined for external arrays.
12443 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012444 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012445 Handle<Object> args[] = { handle(this, isolate), number };
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012446 Handle<Object> error = isolate->factory()->NewTypeError(
12447 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
12448 return isolate->Throw(*error);
12449 }
12450
12451 // Normalize the elements to enable attributes on the property.
12452 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
12453 SeededNumberDictionary* dictionary;
12454 MaybeObject* maybe_object = NormalizeElements();
12455 if (!maybe_object->To(&dictionary)) return maybe_object;
12456 // Make sure that we never go back to fast case.
12457 dictionary->set_requires_slow_elements();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012458 }
12459
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012460 if (!(FLAG_harmony_observation && map()->is_observed())) {
12461 return HasIndexedInterceptor()
12462 ? SetElementWithInterceptor(
12463 index, value_raw, attributes, strict_mode, check_prototype, set_mode)
12464 : SetElementWithoutInterceptor(
12465 index, value_raw, attributes, strict_mode, check_prototype, set_mode);
12466 }
12467
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012468 // From here on, everything has to be handlified.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012469 Handle<JSObject> self(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012470 Handle<Object> value(value_raw, isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012471 PropertyAttributes old_attributes = self->GetLocalElementAttribute(index);
12472 Handle<Object> old_value = isolate->factory()->the_hole_value();
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012473 Handle<Object> old_length_handle;
12474 Handle<Object> new_length_handle;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012475
12476 if (old_attributes != ABSENT) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000012477 if (self->GetLocalElementAccessorPair(index) == NULL)
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000012478 old_value = Object::GetElement(isolate, self, index);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012479 } else if (self->IsJSArray()) {
12480 // Store old array length in case adding an element grows the array.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012481 old_length_handle = handle(Handle<JSArray>::cast(self)->length(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012482 }
12483
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012484 // Check for lookup interceptor
12485 MaybeObject* result = self->HasIndexedInterceptor()
12486 ? self->SetElementWithInterceptor(
12487 index, *value, attributes, strict_mode, check_prototype, set_mode)
12488 : self->SetElementWithoutInterceptor(
12489 index, *value, attributes, strict_mode, check_prototype, set_mode);
12490
12491 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012492 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012493
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012494 Handle<String> name = isolate->factory()->Uint32ToString(index);
12495 PropertyAttributes new_attributes = self->GetLocalElementAttribute(index);
12496 if (old_attributes == ABSENT) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012497 if (self->IsJSArray() &&
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012498 !old_length_handle->SameValue(Handle<JSArray>::cast(self)->length())) {
12499 new_length_handle = handle(Handle<JSArray>::cast(self)->length(),
12500 isolate);
12501 uint32_t old_length = 0;
12502 uint32_t new_length = 0;
12503 CHECK(old_length_handle->ToArrayIndex(&old_length));
12504 CHECK(new_length_handle->ToArrayIndex(&new_length));
12505
12506 BeginPerformSplice(Handle<JSArray>::cast(self));
12507 EnqueueChangeRecord(self, "new", name, old_value);
12508 EnqueueChangeRecord(self, "updated", isolate->factory()->length_string(),
12509 old_length_handle);
12510 EndPerformSplice(Handle<JSArray>::cast(self));
12511 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
danno@chromium.org1fd77d52013-06-07 16:01:45 +000012512 EnqueueSpliceRecord(Handle<JSArray>::cast(self), old_length, deleted,
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000012513 new_length - old_length);
12514 } else {
12515 EnqueueChangeRecord(self, "new", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012516 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012517 } else if (old_value->IsTheHole()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012518 EnqueueChangeRecord(self, "reconfigured", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012519 } else {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000012520 Handle<Object> new_value = Object::GetElement(isolate, self, index);
danno@chromium.orgca29dd82013-04-26 11:59:48 +000012521 bool value_changed = !old_value->SameValue(*new_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000012522 if (old_attributes != new_attributes) {
12523 if (!value_changed) old_value = isolate->factory()->the_hole_value();
12524 EnqueueChangeRecord(self, "reconfigured", name, old_value);
12525 } else if (value_changed) {
12526 EnqueueChangeRecord(self, "updated", name, old_value);
12527 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000012528 }
12529
12530 return *hresult;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012531}
12532
12533
lrn@chromium.org303ada72010-10-27 09:33:13 +000012534MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +000012535 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012536 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012537 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012538 bool check_prototype,
12539 SetPropertyMode set_mode) {
12540 ASSERT(HasDictionaryElements() ||
12541 HasDictionaryArgumentsElements() ||
12542 (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012543 Isolate* isolate = GetIsolate();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000012544 if (FLAG_trace_external_array_abuse &&
12545 IsExternalArrayElementsKind(GetElementsKind())) {
12546 CheckArrayAbuse(this, "external elements write", index);
12547 }
12548 if (FLAG_trace_js_array_abuse &&
12549 !IsExternalArrayElementsKind(GetElementsKind())) {
12550 if (IsJSArray()) {
12551 CheckArrayAbuse(this, "elements write", index, true);
12552 }
12553 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012554 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012555 case FAST_SMI_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012556 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012557 case FAST_HOLEY_SMI_ELEMENTS:
12558 case FAST_HOLEY_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012559 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012560 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012561 case FAST_HOLEY_DOUBLE_ELEMENTS:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012562 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012563 case EXTERNAL_PIXEL_ELEMENTS: {
12564 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012565 return pixels->SetValue(index, value);
12566 }
ager@chromium.org3811b432009-10-28 14:53:37 +000012567 case EXTERNAL_BYTE_ELEMENTS: {
12568 ExternalByteArray* array = ExternalByteArray::cast(elements());
12569 return array->SetValue(index, value);
12570 }
12571 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
12572 ExternalUnsignedByteArray* array =
12573 ExternalUnsignedByteArray::cast(elements());
12574 return array->SetValue(index, value);
12575 }
12576 case EXTERNAL_SHORT_ELEMENTS: {
12577 ExternalShortArray* array = ExternalShortArray::cast(elements());
12578 return array->SetValue(index, value);
12579 }
12580 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
12581 ExternalUnsignedShortArray* array =
12582 ExternalUnsignedShortArray::cast(elements());
12583 return array->SetValue(index, value);
12584 }
12585 case EXTERNAL_INT_ELEMENTS: {
12586 ExternalIntArray* array = ExternalIntArray::cast(elements());
12587 return array->SetValue(index, value);
12588 }
12589 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
12590 ExternalUnsignedIntArray* array =
12591 ExternalUnsignedIntArray::cast(elements());
12592 return array->SetValue(index, value);
12593 }
12594 case EXTERNAL_FLOAT_ELEMENTS: {
12595 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
12596 return array->SetValue(index, value);
12597 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012598 case EXTERNAL_DOUBLE_ELEMENTS: {
12599 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
12600 return array->SetValue(index, value);
12601 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012602 case DICTIONARY_ELEMENTS:
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012603 return SetDictionaryElement(index, value, attr, strict_mode,
12604 check_prototype, set_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012605 case NON_STRICT_ARGUMENTS_ELEMENTS: {
12606 FixedArray* parameter_map = FixedArray::cast(elements());
12607 uint32_t length = parameter_map->length();
12608 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +000012609 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012610 if (probe != NULL && !probe->IsTheHole()) {
12611 Context* context = Context::cast(parameter_map->get(0));
12612 int context_index = Smi::cast(probe)->value();
12613 ASSERT(!context->get(context_index)->IsTheHole());
12614 context->set(context_index, value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012615 // Redefining attributes of an aliased element destroys fast aliasing.
12616 if (set_mode == SET_PROPERTY || attr == NONE) return value;
12617 parameter_map->set_the_hole(index + 2);
12618 // For elements that are still writable we re-establish slow aliasing.
12619 if ((attr & READ_ONLY) == 0) {
12620 MaybeObject* maybe_entry =
12621 isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
12622 if (!maybe_entry->ToObject(&value)) return maybe_entry;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012623 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012624 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000012625 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
12626 if (arguments->IsDictionary()) {
12627 return SetDictionaryElement(index, value, attr, strict_mode,
12628 check_prototype, set_mode);
12629 } else {
12630 return SetFastElement(index, value, strict_mode, check_prototype);
12631 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012632 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012633 }
12634 // All possible cases have been handled above. Add a return to avoid the
12635 // complaints from the compiler.
12636 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012637 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012638}
12639
12640
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012641void JSObject::TransitionElementsKind(Handle<JSObject> object,
12642 ElementsKind to_kind) {
12643 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
12644 object->TransitionElementsKind(to_kind));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012645}
12646
12647
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000012648bool AllocationSite::IsNestedSite() {
12649 ASSERT(FLAG_trace_track_allocation_sites);
12650 Object* current = GetHeap()->allocation_sites_list();
12651 while (current != NULL && current->IsAllocationSite()) {
12652 AllocationSite* current_site = AllocationSite::cast(current);
12653 if (current_site->nested_site() == this) {
12654 return true;
12655 }
12656 current = current_site->weak_next();
12657 }
12658 return false;
12659}
12660
12661
danno@chromium.orgbee51992013-07-10 14:57:15 +000012662MaybeObject* JSObject::UpdateAllocationSite(ElementsKind to_kind) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012663 if (!FLAG_track_allocation_sites || !IsJSArray()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012664 return this;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012665 }
12666
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012667 AllocationMemento* memento = AllocationMemento::FindForJSObject(this);
12668 if (memento == NULL || !memento->IsValid()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012669 return this;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000012670 }
12671
danno@chromium.orgbee51992013-07-10 14:57:15 +000012672 // Walk through to the Allocation Site
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +000012673 AllocationSite* site = memento->GetAllocationSite();
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000012674 if (site->SitePointsToLiteral() &&
12675 site->transition_info()->IsJSArray()) {
danno@chromium.orgbee51992013-07-10 14:57:15 +000012676 JSArray* transition_info = JSArray::cast(site->transition_info());
12677 ElementsKind kind = transition_info->GetElementsKind();
danno@chromium.org169691d2013-07-15 08:01:13 +000012678 // if kind is holey ensure that to_kind is as well.
12679 if (IsHoleyElementsKind(kind)) {
12680 to_kind = GetHoleyElementsKind(to_kind);
12681 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012682 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012683 // If the array is huge, it's not likely to be defined in a local
12684 // function, so we shouldn't make new instances of it very often.
12685 uint32_t length = 0;
danno@chromium.orgbee51992013-07-10 14:57:15 +000012686 CHECK(transition_info->length()->ToArrayIndex(&length));
12687 if (length <= AllocationSite::kMaximumArrayBytesToPretransition) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012688 if (FLAG_trace_track_allocation_sites) {
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000012689 bool is_nested = site->IsNestedSite();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012690 PrintF(
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000012691 "AllocationSite: JSArray %p boilerplate %s updated %s->%s\n",
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012692 reinterpret_cast<void*>(this),
mstarzinger@chromium.orgb4968be2013-10-16 09:00:56 +000012693 is_nested ? "(nested)" : "",
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012694 ElementsKindToString(kind),
12695 ElementsKindToString(to_kind));
12696 }
danno@chromium.orgbee51992013-07-10 14:57:15 +000012697 return transition_info->TransitionElementsKind(to_kind);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012698 }
12699 }
danno@chromium.orgbee51992013-07-10 14:57:15 +000012700 } else {
12701 ElementsKind kind = site->GetElementsKind();
danno@chromium.org169691d2013-07-15 08:01:13 +000012702 // if kind is holey ensure that to_kind is as well.
12703 if (IsHoleyElementsKind(kind)) {
12704 to_kind = GetHoleyElementsKind(to_kind);
12705 }
machenbach@chromium.org528ce022013-09-23 14:09:36 +000012706 if (IsMoreGeneralElementsKindTransition(kind, to_kind)) {
danno@chromium.orgbee51992013-07-10 14:57:15 +000012707 if (FLAG_trace_track_allocation_sites) {
12708 PrintF("AllocationSite: JSArray %p site updated %s->%s\n",
12709 reinterpret_cast<void*>(this),
12710 ElementsKindToString(kind),
12711 ElementsKindToString(to_kind));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012712 }
danno@chromium.orgbee51992013-07-10 14:57:15 +000012713 site->set_transition_info(Smi::FromInt(to_kind));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012714 }
12715 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012716 return this;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012717}
12718
12719
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012720MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000012721 ASSERT(!map()->is_observed());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012722 ElementsKind from_kind = map()->elements_kind();
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012723
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012724 if (IsFastHoleyElementsKind(from_kind)) {
12725 to_kind = GetHoleyElementsKind(to_kind);
12726 }
12727
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000012728 if (from_kind == to_kind) return this;
12729
danno@chromium.orgbee51992013-07-10 14:57:15 +000012730 MaybeObject* maybe_failure = UpdateAllocationSite(to_kind);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012731 if (maybe_failure->IsFailure()) return maybe_failure;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012732
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012733 Isolate* isolate = GetIsolate();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012734 if (elements() == isolate->heap()->empty_fixed_array() ||
12735 (IsFastSmiOrObjectElementsKind(from_kind) &&
12736 IsFastSmiOrObjectElementsKind(to_kind)) ||
12737 (from_kind == FAST_DOUBLE_ELEMENTS &&
12738 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
12739 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
12740 // No change is needed to the elements() buffer, the transition
12741 // only requires a map change.
danno@chromium.orgfa458e42012-02-01 10:48:36 +000012742 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
12743 Map* new_map;
12744 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
12745 set_map(new_map);
12746 if (FLAG_trace_elements_transitions) {
12747 FixedArrayBase* elms = FixedArrayBase::cast(elements());
12748 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
12749 }
12750 return this;
12751 }
12752
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012753 FixedArrayBase* elms = FixedArrayBase::cast(elements());
12754 uint32_t capacity = static_cast<uint32_t>(elms->length());
12755 uint32_t length = capacity;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012756
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012757 if (IsJSArray()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012758 Object* raw_length = JSArray::cast(this)->length();
12759 if (raw_length->IsUndefined()) {
12760 // If length is undefined, then JSArray is being initialized and has no
12761 // elements, assume a length of zero.
12762 length = 0;
12763 } else {
12764 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012765 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012766 }
12767
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012768 if (IsFastSmiElementsKind(from_kind) &&
12769 IsFastDoubleElementsKind(to_kind)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012770 MaybeObject* maybe_result =
12771 SetFastDoubleElementsCapacityAndLength(capacity, length);
12772 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012773 ValidateElements();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012774 return this;
12775 }
12776
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012777 if (IsFastDoubleElementsKind(from_kind) &&
12778 IsFastObjectElementsKind(to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012779 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012780 capacity, length, kDontAllowSmiElements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012781 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012782 ValidateElements();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012783 return this;
12784 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012785
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012786 // This method should never be called for any other case than the ones
12787 // handled above.
12788 UNREACHABLE();
12789 return GetIsolate()->heap()->null_value();
12790}
12791
12792
12793// static
12794bool Map::IsValidElementsTransition(ElementsKind from_kind,
12795 ElementsKind to_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012796 // Transitions can't go backwards.
12797 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
12798 return false;
12799 }
12800
12801 // Transitions from HOLEY -> PACKED are not allowed.
12802 return !IsFastHoleyElementsKind(from_kind) ||
12803 IsFastHoleyElementsKind(to_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012804}
12805
12806
lrn@chromium.org303ada72010-10-27 09:33:13 +000012807MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
12808 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012809 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000012810 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012811 // Check to see if we need to update the length. For now, we make
12812 // sure that the length stays within 32-bits (unsigned).
12813 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012814 Object* len;
12815 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012816 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012817 if (!maybe_len->ToObject(&len)) return maybe_len;
12818 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012819 set_length(len);
12820 }
12821 return value;
12822}
12823
12824
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000012825MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012826 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012827 Isolate* isolate = GetIsolate();
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000012828 HandleScope scope(isolate);
12829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012830 // Make sure that the top context does not change when doing
12831 // callbacks or interceptor calls.
jkummerow@chromium.orgfb7a7c42013-10-02 11:41:02 +000012832 AssertNoContextChange ncc(isolate);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +000012833
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012834 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
12835 Handle<Object> this_handle(receiver, isolate);
12836 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012837 if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +000012838 v8::IndexedPropertyGetterCallback getter =
12839 v8::ToCData<v8::IndexedPropertyGetterCallback>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012840 LOG(isolate,
12841 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000012842 PropertyCallbackArguments
12843 args(isolate, interceptor->data(), receiver, this);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000012844 v8::Handle<v8::Value> result = args.Call(getter, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012845 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012846 if (!result.IsEmpty()) {
12847 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12848 result_internal->VerifyApiCallResultType();
12849 return *result_internal;
12850 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012851 }
12852
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012853 Heap* heap = holder_handle->GetHeap();
12854 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012855 MaybeObject* raw_result = handler->Get(*this_handle,
rossberg@chromium.org28a37082011-08-22 11:03:23 +000012856 *holder_handle,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000012857 index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012858 if (raw_result != heap->the_hole_value()) return raw_result;
12859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012860 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012861
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012862 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012863 if (pt == heap->null_value()) return heap->undefined_value();
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000012864 return pt->GetElementWithReceiver(isolate, *this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012865}
12866
12867
12868bool JSObject::HasDenseElements() {
12869 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012870 int used = 0;
12871 GetElementsCapacityAndUsage(&capacity, &used);
12872 return (capacity == 0) || (used > (capacity / 2));
12873}
12874
12875
12876void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
12877 *capacity = 0;
12878 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012879
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012880 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
12881 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012882 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012883 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012884 backing_store_base =
12885 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
12886 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012887 if (backing_store->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012888 SeededNumberDictionary* dictionary =
12889 SeededNumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012890 *capacity = dictionary->Capacity();
12891 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012892 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012893 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012894 // Fall through.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012895 case FAST_SMI_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +000012896 case FAST_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012897 if (IsJSArray()) {
12898 *capacity = backing_store_base->length();
12899 *used = Smi::cast(JSArray::cast(this)->length())->value();
12900 break;
12901 }
12902 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012903 case FAST_HOLEY_SMI_ELEMENTS:
12904 case FAST_HOLEY_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012905 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012906 *capacity = backing_store->length();
12907 for (int i = 0; i < *capacity; ++i) {
12908 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012909 }
12910 break;
12911 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012912 SeededNumberDictionary* dictionary =
12913 SeededNumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012914 *capacity = dictionary->Capacity();
12915 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012916 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012917 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012918 case FAST_DOUBLE_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012919 if (IsJSArray()) {
12920 *capacity = backing_store_base->length();
12921 *used = Smi::cast(JSArray::cast(this)->length())->value();
12922 break;
12923 }
12924 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012925 case FAST_HOLEY_DOUBLE_ELEMENTS: {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012926 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012927 *capacity = elms->length();
12928 for (int i = 0; i < *capacity; i++) {
12929 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012930 }
12931 break;
12932 }
ager@chromium.org3811b432009-10-28 14:53:37 +000012933 case EXTERNAL_BYTE_ELEMENTS:
12934 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
12935 case EXTERNAL_SHORT_ELEMENTS:
12936 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
12937 case EXTERNAL_INT_ELEMENTS:
12938 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012939 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012940 case EXTERNAL_DOUBLE_ELEMENTS:
12941 case EXTERNAL_PIXEL_ELEMENTS:
12942 // External arrays are considered 100% used.
12943 ExternalArray* external_array = ExternalArray::cast(elements());
12944 *capacity = external_array->length();
12945 *used = external_array->length();
12946 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012947 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012948}
12949
12950
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012951bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012952 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
12953 kMaxUncheckedFastElementsLength);
12954 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
12955 (new_capacity <= kMaxUncheckedFastElementsLength &&
12956 GetHeap()->InNewSpace(this))) {
12957 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012958 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012959 // If the fast-case backing storage takes up roughly three times as
12960 // much space (in machine words) as a dictionary backing storage
12961 // would, the object should have slow elements.
12962 int old_capacity = 0;
12963 int used_elements = 0;
12964 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012965 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
12966 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012967 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012968}
12969
12970
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012971bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012972 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012973 // If the elements are sparse, we should not go back to fast case.
12974 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012975 // An object requiring access checks is never allowed to have fast
12976 // elements. If it had fast elements we would skip security checks.
12977 if (IsAccessCheckNeeded()) return false;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000012978 // Observed objects may not go to fast mode because they rely on map checks,
12979 // and for fast element accesses we sometimes check element kinds only.
12980 if (FLAG_harmony_observation && map()->is_observed()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012981
12982 FixedArray* elements = FixedArray::cast(this->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012983 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012984 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012985 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012986 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012987 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012988 }
12989 // If an element has been added at a very high index in the elements
12990 // dictionary, we cannot go back to fast case.
12991 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012992 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012993 // space (in machine words) as a fast-case backing storage would,
12994 // the object should have fast elements.
12995 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012996 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012997 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012998 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012999 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013000 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013001 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013002 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013003 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013004}
13005
13006
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013007bool JSObject::ShouldConvertToFastDoubleElements(
13008 bool* has_smi_only_elements) {
13009 *has_smi_only_elements = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013010 if (FLAG_unbox_double_arrays) {
13011 ASSERT(HasDictionaryElements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013012 SeededNumberDictionary* dictionary =
13013 SeededNumberDictionary::cast(elements());
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013014 bool found_double = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013015 for (int i = 0; i < dictionary->Capacity(); i++) {
13016 Object* key = dictionary->KeyAt(i);
13017 if (key->IsNumber()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013018 Object* value = dictionary->ValueAt(i);
13019 if (!value->IsNumber()) return false;
13020 if (!value->IsSmi()) {
13021 found_double = true;
13022 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013023 }
13024 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000013025 *has_smi_only_elements = !found_double;
13026 return found_double;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013027 } else {
13028 return false;
13029 }
13030}
13031
13032
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013033// Certain compilers request function template instantiation when they
13034// see the definition of the other template functions in the
13035// class. This requires us to have the template functions put
13036// together, so even though this function belongs in objects-debug.cc,
13037// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +000013038#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013039template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +000013040void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013041 int capacity = HashTable<Shape, Key>::Capacity();
13042 for (int i = 0; i < capacity; i++) {
13043 Object* k = HashTable<Shape, Key>::KeyAt(i);
13044 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000013045 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013046 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000013047 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013048 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000013049 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013050 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000013051 PrintF(out, ": ");
13052 ValueAt(i)->ShortPrint(out);
13053 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013054 }
13055 }
13056}
13057#endif
13058
13059
13060template<typename Shape, typename Key>
13061void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013062 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013063 int capacity = HashTable<Shape, Key>::Capacity();
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013064 DisallowHeapAllocation no_gc;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013065 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013066 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013067 Object* k = Dictionary<Shape, Key>::KeyAt(i);
13068 if (Dictionary<Shape, Key>::IsKey(k)) {
13069 elements->set(pos++, ValueAt(i), mode);
13070 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013071 }
13072 ASSERT(pos == elements->length());
13073}
13074
13075
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013076InterceptorInfo* JSObject::GetNamedInterceptor() {
13077 ASSERT(map()->has_named_interceptor());
13078 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013079 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013080 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013081 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013082 return InterceptorInfo::cast(result);
13083}
13084
13085
13086InterceptorInfo* JSObject::GetIndexedInterceptor() {
13087 ASSERT(map()->has_indexed_interceptor());
13088 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013089 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013090 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013091 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013092 return InterceptorInfo::cast(result);
13093}
13094
13095
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013096Handle<Object> JSObject::GetPropertyPostInterceptor(
13097 Handle<JSObject> object,
13098 Handle<Object> receiver,
13099 Handle<Name> name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013100 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013101 // Check local property in holder, ignore interceptor.
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013102 Isolate* isolate = object->GetIsolate();
13103 LookupResult lookup(isolate);
13104 object->LocalLookupRealNamedProperty(*name, &lookup);
13105 Handle<Object> result;
13106 if (lookup.IsFound()) {
13107 result = GetProperty(object, receiver, &lookup, name, attributes);
13108 } else {
13109 // Continue searching via the prototype chain.
13110 Handle<Object> prototype(object->GetPrototype(), isolate);
13111 *attributes = ABSENT;
13112 if (prototype->IsNull()) return isolate->factory()->undefined_value();
13113 result = GetPropertyWithReceiver(prototype, receiver, name, attributes);
ager@chromium.org5c838252010-02-19 08:53:10 +000013114 }
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013115 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013116}
13117
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013118
lrn@chromium.org303ada72010-10-27 09:33:13 +000013119MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013120 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000013121 Name* name,
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013122 PropertyAttributes* attributes) {
13123 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013124 LookupResult result(GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013125 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000013126 if (result.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +000013127 return GetProperty(receiver, &result, name, attributes);
13128 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013129 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000013130}
13131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013132
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013133Handle<Object> JSObject::GetPropertyWithInterceptor(
13134 Handle<JSObject> object,
13135 Handle<Object> receiver,
13136 Handle<Name> name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000013137 PropertyAttributes* attributes) {
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013138 Isolate* isolate = object->GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +000013139
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013140 // TODO(rossberg): Support symbols in the API.
13141 if (name->IsSymbol()) return isolate->factory()->undefined_value();
13142
13143 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor(), isolate);
13144 Handle<String> name_string = Handle<String>::cast(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013145
13146 if (!interceptor->getter()->IsUndefined()) {
verwaest@chromium.org662436e2013-08-28 08:41:27 +000013147 v8::NamedPropertyGetterCallback getter =
13148 v8::ToCData<v8::NamedPropertyGetterCallback>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013149 LOG(isolate,
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013150 ApiNamedPropertyAccess("interceptor-named-get", *object, *name));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +000013151 PropertyCallbackArguments
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013152 args(isolate, interceptor->data(), *receiver, *object);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000013153 v8::Handle<v8::Value> result =
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013154 args.Call(getter, v8::Utils::ToLocal(name_string));
13155 RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013156 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013157 *attributes = NONE;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000013158 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
13159 result_internal->VerifyApiCallResultType();
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013160 // Rebox handle to escape this scope.
13161 return handle(*result_internal, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013162 }
13163 }
13164
mvstanton@chromium.orgdd6d9ee2013-10-11 10:35:37 +000013165 return GetPropertyPostInterceptor(object, receiver, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013166}
13167
13168
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013169bool JSObject::HasRealNamedProperty(Isolate* isolate, Name* key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013170 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013171 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013172 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
13173 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013174 return false;
13175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013176 }
13177
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013178 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013179 LocalLookupRealNamedProperty(key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000013180 return result.IsFound() && !result.IsInterceptor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013181}
13182
13183
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013184bool JSObject::HasRealElementProperty(Isolate* isolate, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013185 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013186 if (IsAccessCheckNeeded()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013187 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
13188 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013189 return false;
13190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013191 }
13192
danno@chromium.org169691d2013-07-15 08:01:13 +000013193 if (IsJSGlobalProxy()) {
13194 Object* proto = GetPrototype();
13195 if (proto->IsNull()) return false;
13196 ASSERT(proto->IsJSGlobalObject());
13197 return JSObject::cast(proto)->HasRealElementProperty(isolate, index);
13198 }
13199
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013200 return GetElementAttributeWithoutInterceptor(this, index, false) != ABSENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013201}
13202
13203
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000013204bool JSObject::HasRealNamedCallbackProperty(Isolate* isolate, Name* key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013205 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013206 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013207 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
13208 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013209 return false;
13210 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013211 }
13212
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013213 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013214 LocalLookupRealNamedProperty(key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000013215 return result.IsPropertyCallbacks();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013216}
13217
13218
13219int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013220 if (HasFastProperties()) {
13221 Map* map = this->map();
13222 if (filter == NONE) return map->NumberOfOwnDescriptors();
ulan@chromium.org750145a2013-03-07 15:14:13 +000013223 if (filter & DONT_ENUM) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000013224 int result = map->EnumLength();
13225 if (result != Map::kInvalidEnumCache) return result;
13226 }
13227 return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
13228 }
13229 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013230}
13231
13232
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013233void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013234 Object* temp = get(i);
13235 set(i, get(j));
13236 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013237 if (this != numbers) {
13238 temp = numbers->get(i);
erikcorry0ad885c2011-11-21 13:51:57 +000013239 numbers->set(i, Smi::cast(numbers->get(j)));
13240 numbers->set(j, Smi::cast(temp));
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013241 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013242}
13243
13244
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013245static void InsertionSortPairs(FixedArray* content,
13246 FixedArray* numbers,
13247 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013248 for (int i = 1; i < len; i++) {
13249 int j = i;
13250 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013251 (NumberToUint32(numbers->get(j - 1)) >
13252 NumberToUint32(numbers->get(j)))) {
13253 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013254 j--;
13255 }
13256 }
13257}
13258
13259
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013260void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013261 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013262 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013263
13264 // Bottom-up max-heap construction.
13265 for (int i = 1; i < len; ++i) {
13266 int child_index = i;
13267 while (child_index > 0) {
13268 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013269 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
13270 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013271 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013272 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013273 } else {
13274 break;
13275 }
13276 child_index = parent_index;
13277 }
13278 }
13279
13280 // Extract elements and create sorted array.
13281 for (int i = len - 1; i > 0; --i) {
13282 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013283 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013284 // Sift down the new top element.
13285 int parent_index = 0;
13286 while (true) {
13287 int child_index = ((parent_index + 1) << 1) - 1;
13288 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013289 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
13290 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
13291 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013292 if (child_index + 1 >= i || child1_value > child2_value) {
13293 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013294 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013295 parent_index = child_index;
13296 } else {
13297 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013298 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013299 parent_index = child_index + 1;
13300 }
13301 }
13302 }
13303}
13304
13305
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013306// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
13307void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
13308 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013309 // For small arrays, simply use insertion sort.
13310 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013311 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013312 return;
13313 }
13314 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013315 uint32_t min_index = NumberToUint32(numbers->get(0));
13316 uint32_t max_index = min_index;
13317 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013318 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013319 if (NumberToUint32(numbers->get(i)) < min_index) {
13320 min_index = NumberToUint32(numbers->get(i));
13321 } else if (NumberToUint32(numbers->get(i)) > max_index) {
13322 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013323 }
13324 }
13325 if (max_index - min_index + 1 == len) {
13326 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013327 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013328 // avoid hanging in case they are not.
13329 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013330 uint32_t p;
13331 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013332 // While the current element at i is not at its correct position p,
13333 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013334 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013335 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013336 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013337 }
13338 }
13339 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013340 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013341 return;
13342 }
13343}
13344
13345
13346// Fill in the names of local properties into the supplied storage. The main
13347// purpose of this function is to provide reflection information for the object
13348// mirrors.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013349void JSObject::GetLocalPropertyNames(
13350 FixedArray* storage, int index, PropertyAttributes filter) {
13351 ASSERT(storage->length() >= (NumberOfLocalProperties(filter) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013352 if (HasFastProperties()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000013353 int real_size = map()->NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000013354 DescriptorArray* descs = map()->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000013355 for (int i = 0; i < real_size; i++) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013356 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
13357 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
13358 storage->set(index++, descs->GetKey(i));
13359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013361 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013362 property_dictionary()->CopyKeysTo(storage,
13363 index,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013364 filter,
ulan@chromium.org750145a2013-03-07 15:14:13 +000013365 NameDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013366 }
13367}
13368
13369
13370int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
13371 return GetLocalElementKeys(NULL, filter);
13372}
13373
13374
13375int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013376 // Fast case for objects with no elements.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013377 if (!IsJSValue() && HasFastObjectElements()) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013378 uint32_t length = IsJSArray() ?
13379 static_cast<uint32_t>(
13380 Smi::cast(JSArray::cast(this)->length())->value()) :
13381 static_cast<uint32_t>(FixedArray::cast(elements())->length());
13382 if (length == 0) return 0;
13383 }
13384 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013385 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
13386}
13387
13388
13389int JSObject::GetLocalElementKeys(FixedArray* storage,
13390 PropertyAttributes filter) {
13391 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013392 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013393 case FAST_SMI_ELEMENTS:
13394 case FAST_ELEMENTS:
13395 case FAST_HOLEY_SMI_ELEMENTS:
13396 case FAST_HOLEY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013397 int length = IsJSArray() ?
13398 Smi::cast(JSArray::cast(this)->length())->value() :
13399 FixedArray::cast(elements())->length();
13400 for (int i = 0; i < length; i++) {
13401 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
13402 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013403 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013404 }
13405 counter++;
13406 }
13407 }
13408 ASSERT(!storage || storage->length() >= counter);
13409 break;
13410 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013411 case FAST_DOUBLE_ELEMENTS:
13412 case FAST_HOLEY_DOUBLE_ELEMENTS: {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013413 int length = IsJSArray() ?
13414 Smi::cast(JSArray::cast(this)->length())->value() :
13415 FixedDoubleArray::cast(elements())->length();
13416 for (int i = 0; i < length; i++) {
13417 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
13418 if (storage != NULL) {
13419 storage->set(counter, Smi::FromInt(i));
13420 }
13421 counter++;
13422 }
13423 }
13424 ASSERT(!storage || storage->length() >= counter);
13425 break;
13426 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013427 case EXTERNAL_PIXEL_ELEMENTS: {
13428 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013429 while (counter < length) {
13430 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013431 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013432 }
13433 counter++;
13434 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013435 ASSERT(!storage || storage->length() >= counter);
13436 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013437 }
ager@chromium.org3811b432009-10-28 14:53:37 +000013438 case EXTERNAL_BYTE_ELEMENTS:
13439 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
13440 case EXTERNAL_SHORT_ELEMENTS:
13441 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
13442 case EXTERNAL_INT_ELEMENTS:
13443 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013444 case EXTERNAL_FLOAT_ELEMENTS:
13445 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000013446 int length = ExternalArray::cast(elements())->length();
13447 while (counter < length) {
13448 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013449 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +000013450 }
13451 counter++;
13452 }
13453 ASSERT(!storage || storage->length() >= counter);
13454 break;
13455 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013456 case DICTIONARY_ELEMENTS: {
13457 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013458 element_dictionary()->CopyKeysTo(storage,
13459 filter,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013460 SeededNumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013461 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013462 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013463 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013464 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013465 case NON_STRICT_ARGUMENTS_ELEMENTS: {
13466 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013467 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +000013468 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
13469 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013470 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
13471 // will insert in storage starting at index 0.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013472 SeededNumberDictionary* dictionary =
13473 SeededNumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013474 if (storage != NULL) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013475 dictionary->CopyKeysTo(
13476 storage, filter, SeededNumberDictionary::UNSORTED);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013477 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013478 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013479 for (int i = 0; i < mapped_length; ++i) {
13480 if (!parameter_map->get(i + 2)->IsTheHole()) {
13481 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +000013482 ++counter;
13483 }
13484 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013485 if (storage != NULL) storage->SortPairs(storage, counter);
13486
13487 } else {
13488 int backing_length = arguments->length();
13489 int i = 0;
13490 for (; i < mapped_length; ++i) {
13491 if (!parameter_map->get(i + 2)->IsTheHole()) {
13492 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13493 ++counter;
13494 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
13495 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13496 ++counter;
13497 }
13498 }
13499 for (; i < backing_length; ++i) {
13500 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
13501 ++counter;
13502 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000013503 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013504 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +000013505 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013506 }
13507
13508 if (this->IsJSValue()) {
13509 Object* val = JSValue::cast(this)->value();
13510 if (val->IsString()) {
13511 String* str = String::cast(val);
13512 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013513 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013514 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013515 }
13516 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000013517 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013518 }
13519 }
13520 ASSERT(!storage || storage->length() == counter);
13521 return counter;
13522}
13523
13524
13525int JSObject::GetEnumElementKeys(FixedArray* storage) {
13526 return GetLocalElementKeys(storage,
13527 static_cast<PropertyAttributes>(DONT_ENUM));
13528}
13529
13530
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013531// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000013532class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013533 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013534 explicit StringKey(String* string) :
13535 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013536 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013537
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013538 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013539 // We know that all entries in a hash table had their hash keys created.
13540 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013541 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013542 return false;
13543 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013544 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013545 }
13546
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013547 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013548
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013549 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013550
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013551 Object* AsObject(Heap* heap) { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013552
13553 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013554 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013555};
13556
ager@chromium.org381abbb2009-02-25 13:23:22 +000013557
13558// StringSharedKeys are used as keys in the eval cache.
13559class StringSharedKey : public HashTableKey {
13560 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013561 StringSharedKey(String* source,
13562 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013563 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013564 int scope_position)
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013565 : source_(source),
13566 shared_(shared),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013567 language_mode_(language_mode),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013568 scope_position_(scope_position) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +000013569
13570 bool IsMatch(Object* other) {
13571 if (!other->IsFixedArray()) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013572 FixedArray* other_array = FixedArray::cast(other);
13573 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
ager@chromium.org381abbb2009-02-25 13:23:22 +000013574 if (shared != shared_) return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013575 int language_unchecked = Smi::cast(other_array->get(2))->value();
13576 ASSERT(language_unchecked == CLASSIC_MODE ||
13577 language_unchecked == STRICT_MODE ||
13578 language_unchecked == EXTENDED_MODE);
13579 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
13580 if (language_mode != language_mode_) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013581 int scope_position = Smi::cast(other_array->get(3))->value();
13582 if (scope_position != scope_position_) return false;
13583 String* source = String::cast(other_array->get(1));
ager@chromium.org381abbb2009-02-25 13:23:22 +000013584 return source->Equals(source_);
13585 }
13586
ager@chromium.org381abbb2009-02-25 13:23:22 +000013587 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013588 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013589 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013590 int scope_position) {
ager@chromium.org381abbb2009-02-25 13:23:22 +000013591 uint32_t hash = source->Hash();
13592 if (shared->HasSourceCode()) {
13593 // Instead of using the SharedFunctionInfo pointer in the hash
13594 // code computation, we use a combination of the hash of the
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013595 // script source code and the start position of the calling scope.
13596 // We do this to ensure that the cache entries can survive garbage
ager@chromium.org381abbb2009-02-25 13:23:22 +000013597 // collection.
13598 Script* script = Script::cast(shared->script());
13599 hash ^= String::cast(script->source())->Hash();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013600 if (language_mode == STRICT_MODE) hash ^= 0x8000;
13601 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013602 hash += scope_position;
ager@chromium.org381abbb2009-02-25 13:23:22 +000013603 }
13604 return hash;
13605 }
13606
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013607 uint32_t Hash() {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013608 return StringSharedHashHelper(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013609 source_, shared_, language_mode_, scope_position_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013610 }
13611
13612 uint32_t HashForObject(Object* obj) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013613 FixedArray* other_array = FixedArray::cast(obj);
13614 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
13615 String* source = String::cast(other_array->get(1));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013616 int language_unchecked = Smi::cast(other_array->get(2))->value();
13617 ASSERT(language_unchecked == CLASSIC_MODE ||
13618 language_unchecked == STRICT_MODE ||
13619 language_unchecked == EXTENDED_MODE);
13620 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013621 int scope_position = Smi::cast(other_array->get(3))->value();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013622 return StringSharedHashHelper(
13623 source, shared, language_mode, scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013624 }
13625
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013626 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013627 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013628 { MaybeObject* maybe_obj = heap->AllocateFixedArray(4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013629 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13630 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013631 FixedArray* other_array = FixedArray::cast(obj);
13632 other_array->set(0, shared_);
13633 other_array->set(1, source_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013634 other_array->set(2, Smi::FromInt(language_mode_));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013635 other_array->set(3, Smi::FromInt(scope_position_));
13636 return other_array;
ager@chromium.org381abbb2009-02-25 13:23:22 +000013637 }
13638
ager@chromium.org381abbb2009-02-25 13:23:22 +000013639 private:
13640 String* source_;
13641 SharedFunctionInfo* shared_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013642 LanguageMode language_mode_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013643 int scope_position_;
ager@chromium.org381abbb2009-02-25 13:23:22 +000013644};
13645
13646
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013647// RegExpKey carries the source and flags of a regular expression as key.
13648class RegExpKey : public HashTableKey {
13649 public:
13650 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000013651 : string_(string),
13652 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013653
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000013654 // Rather than storing the key in the hash table, a pointer to the
13655 // stored value is stored where the key should be. IsMatch then
13656 // compares the search key to the found object, rather than comparing
13657 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013658 bool IsMatch(Object* obj) {
13659 FixedArray* val = FixedArray::cast(obj);
13660 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
13661 && (flags_ == val->get(JSRegExp::kFlagsIndex));
13662 }
13663
13664 uint32_t Hash() { return RegExpHash(string_, flags_); }
13665
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013666 Object* AsObject(Heap* heap) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013667 // Plain hash maps, which is where regexp keys are used, don't
13668 // use this function.
13669 UNREACHABLE();
13670 return NULL;
13671 }
13672
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013673 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013674 FixedArray* val = FixedArray::cast(obj);
13675 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
13676 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
13677 }
13678
13679 static uint32_t RegExpHash(String* string, Smi* flags) {
13680 return string->Hash() + flags->value();
13681 }
13682
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013683 String* string_;
13684 Smi* flags_;
13685};
13686
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000013687
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013688// Utf8StringKey carries a vector of chars as key.
13689class Utf8StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013690 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013691 explicit Utf8StringKey(Vector<const char> string, uint32_t seed)
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013692 : string_(string), hash_field_(0), seed_(seed) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013693
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013694 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013695 return String::cast(string)->IsUtf8EqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013696 }
13697
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013698 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013699 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013700 hash_field_ = StringHasher::ComputeUtf8Hash(string_, seed_, &chars_);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013701 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000013702 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
13703 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013704 }
13705
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013706 uint32_t HashForObject(Object* other) {
13707 return String::cast(other)->Hash();
13708 }
13709
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013710 MaybeObject* AsObject(Heap* heap) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013711 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013712 return heap->AllocateInternalizedStringFromUtf8(string_,
13713 chars_,
13714 hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013715 }
13716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013717 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013718 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013719 int chars_; // Caches the number of characters when computing the hash code.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013720 uint32_t seed_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013721};
13722
13723
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013724template <typename Char>
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013725class SequentialStringKey : public HashTableKey {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013726 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013727 explicit SequentialStringKey(Vector<const Char> string, uint32_t seed)
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013728 : string_(string), hash_field_(0), seed_(seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013729
13730 uint32_t Hash() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013731 hash_field_ = StringHasher::HashSequentialString<Char>(string_.start(),
13732 string_.length(),
13733 seed_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013734
13735 uint32_t result = hash_field_ >> String::kHashShift;
13736 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
13737 return result;
13738 }
13739
13740
13741 uint32_t HashForObject(Object* other) {
13742 return String::cast(other)->Hash();
13743 }
13744
13745 Vector<const Char> string_;
13746 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013747 uint32_t seed_;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013748};
13749
13750
13751
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013752class OneByteStringKey : public SequentialStringKey<uint8_t> {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013753 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013754 OneByteStringKey(Vector<const uint8_t> str, uint32_t seed)
13755 : SequentialStringKey<uint8_t>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013756
13757 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013758 return String::cast(string)->IsOneByteEqualTo(string_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013759 }
13760
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013761 MaybeObject* AsObject(Heap* heap) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013762 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013763 return heap->AllocateOneByteInternalizedString(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013764 }
13765};
13766
13767
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013768class SubStringOneByteStringKey : public HashTableKey {
danno@chromium.org40cb8782011-05-25 07:58:50 +000013769 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013770 explicit SubStringOneByteStringKey(Handle<SeqOneByteString> string,
13771 int from,
13772 int length)
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000013773 : string_(string), from_(from), length_(length) { }
danno@chromium.org40cb8782011-05-25 07:58:50 +000013774
13775 uint32_t Hash() {
13776 ASSERT(length_ >= 0);
13777 ASSERT(from_ + length_ <= string_->length());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013778 uint8_t* chars = string_->GetChars() + from_;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013779 hash_field_ = StringHasher::HashSequentialString(
13780 chars, length_, string_->GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000013781 uint32_t result = hash_field_ >> String::kHashShift;
13782 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
13783 return result;
13784 }
13785
13786
13787 uint32_t HashForObject(Object* other) {
13788 return String::cast(other)->Hash();
13789 }
13790
13791 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013792 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
13793 return String::cast(string)->IsOneByteEqualTo(chars);
danno@chromium.org40cb8782011-05-25 07:58:50 +000013794 }
13795
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013796 MaybeObject* AsObject(Heap* heap) {
danno@chromium.org40cb8782011-05-25 07:58:50 +000013797 if (hash_field_ == 0) Hash();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013798 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013799 return heap->AllocateOneByteInternalizedString(chars, hash_field_);
danno@chromium.org40cb8782011-05-25 07:58:50 +000013800 }
13801
13802 private:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000013803 Handle<SeqOneByteString> string_;
danno@chromium.org40cb8782011-05-25 07:58:50 +000013804 int from_;
13805 int length_;
13806 uint32_t hash_field_;
13807};
13808
13809
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013810class TwoByteStringKey : public SequentialStringKey<uc16> {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013811 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013812 explicit TwoByteStringKey(Vector<const uc16> str, uint32_t seed)
13813 : SequentialStringKey<uc16>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013814
13815 bool IsMatch(Object* string) {
13816 return String::cast(string)->IsTwoByteEqualTo(string_);
13817 }
13818
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013819 MaybeObject* AsObject(Heap* heap) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013820 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013821 return heap->AllocateTwoByteInternalizedString(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013822 }
13823};
13824
13825
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013826// InternalizedStringKey carries a string/internalized-string object as key.
13827class InternalizedStringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013828 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013829 explicit InternalizedStringKey(String* string)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013830 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013831
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013832 bool IsMatch(Object* string) {
13833 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013834 }
13835
13836 uint32_t Hash() { return string_->Hash(); }
13837
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013838 uint32_t HashForObject(Object* other) {
13839 return String::cast(other)->Hash();
13840 }
13841
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013842 MaybeObject* AsObject(Heap* heap) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013843 // Attempt to flatten the string, so that internalized strings will most
13844 // often be flat strings.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000013845 string_ = string_->TryFlattenGetString();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013846 // Internalize the string if possible.
13847 Map* map = heap->InternalizedStringMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013848 if (map != NULL) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000013849 string_->set_map_no_write_barrier(map);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013850 ASSERT(string_->IsInternalizedString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013851 return string_;
13852 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013853 // Otherwise allocate a new internalized string.
13854 return heap->AllocateInternalizedStringImpl(
13855 string_, string_->length(), string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013856 }
13857
13858 static uint32_t StringHash(Object* obj) {
13859 return String::cast(obj)->Hash();
13860 }
13861
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013862 String* string_;
13863};
13864
13865
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013866template<typename Shape, typename Key>
13867void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013868 IteratePointers(v, 0, kElementsStartOffset);
13869}
13870
13871
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013872template<typename Shape, typename Key>
13873void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013874 IteratePointers(v,
13875 kElementsStartOffset,
13876 kHeaderSize + length() * kPointerSize);
13877}
13878
13879
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013880template<typename Shape, typename Key>
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013881MaybeObject* HashTable<Shape, Key>::Allocate(Heap* heap,
13882 int at_least_space_for,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000013883 MinimumCapacity capacity_option,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013884 PretenureFlag pretenure) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000013885 ASSERT(!capacity_option || IS_POWER_OF_TWO(at_least_space_for));
13886 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
13887 ? at_least_space_for
13888 : ComputeCapacity(at_least_space_for);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013889 if (capacity > HashTable::kMaxCapacity) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013890 return Failure::OutOfMemoryException(0x10);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013891 }
13892
lrn@chromium.org303ada72010-10-27 09:33:13 +000013893 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013894 { MaybeObject* maybe_obj =
13895 heap-> AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013896 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013897 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000013898 HashTable::cast(obj)->SetNumberOfElements(0);
13899 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
13900 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013901 return obj;
13902}
13903
13904
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013905// Find entry for key otherwise return kNotFound.
ulan@chromium.org750145a2013-03-07 15:14:13 +000013906int NameDictionary::FindEntry(Name* key) {
13907 if (!key->IsUniqueName()) {
13908 return HashTable<NameDictionaryShape, Name*>::FindEntry(key);
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013909 }
13910
ulan@chromium.org750145a2013-03-07 15:14:13 +000013911 // Optimized for unique names. Knowledge of the key type allows:
13912 // 1. Move the check if the key is unique out of the loop.
13913 // 2. Avoid comparing hash codes in unique-to-unique comparison.
13914 // 3. Detect a case when a dictionary key is not unique but the key is.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013915 // In case of positive result the dictionary key may be replaced by the
13916 // internalized string with minimal performance penalty. It gives a chance
13917 // to perform further lookups in code stubs (and significant performance
13918 // boost a certain style of code).
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013919
13920 // EnsureCapacity will guarantee the hash table is never full.
13921 uint32_t capacity = Capacity();
13922 uint32_t entry = FirstProbe(key->Hash(), capacity);
13923 uint32_t count = 1;
13924
13925 while (true) {
13926 int index = EntryToIndex(entry);
13927 Object* element = get(index);
13928 if (element->IsUndefined()) break; // Empty entry.
13929 if (key == element) return entry;
ulan@chromium.org750145a2013-03-07 15:14:13 +000013930 if (!element->IsUniqueName() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013931 !element->IsTheHole() &&
ulan@chromium.org750145a2013-03-07 15:14:13 +000013932 Name::cast(element)->Equals(key)) {
13933 // Replace a key that is a non-internalized string by the equivalent
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013934 // internalized string for faster further lookups.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013935 set(index, key);
13936 return entry;
13937 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000013938 ASSERT(element->IsTheHole() || !Name::cast(element)->Equals(key));
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013939 entry = NextProbe(entry, count++, capacity);
13940 }
13941 return kNotFound;
13942}
13943
13944
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013945template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000013946MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
13947 ASSERT(NumberOfElements() < new_table->Capacity());
13948
rossberg@chromium.org79e79022013-06-03 15:43:46 +000013949 DisallowHeapAllocation no_gc;
ager@chromium.org04921a82011-06-27 13:21:41 +000013950 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
13951
13952 // Copy prefix to new array.
13953 for (int i = kPrefixStartIndex;
13954 i < kPrefixStartIndex + Shape::kPrefixSize;
13955 i++) {
13956 new_table->set(i, get(i), mode);
13957 }
13958
13959 // Rehash the elements.
13960 int capacity = Capacity();
13961 for (int i = 0; i < capacity; i++) {
13962 uint32_t from_index = EntryToIndex(i);
13963 Object* k = get(from_index);
13964 if (IsKey(k)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013965 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
ager@chromium.org04921a82011-06-27 13:21:41 +000013966 uint32_t insertion_index =
13967 EntryToIndex(new_table->FindInsertionEntry(hash));
13968 for (int j = 0; j < Shape::kEntrySize; j++) {
13969 new_table->set(insertion_index + j, get(from_index + j), mode);
13970 }
13971 }
13972 }
13973 new_table->SetNumberOfElements(NumberOfElements());
13974 new_table->SetNumberOfDeletedElements(0);
13975 return new_table;
13976}
13977
13978
13979template<typename Shape, typename Key>
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000013980uint32_t HashTable<Shape, Key>::EntryForProbe(Key key,
13981 Object* k,
13982 int probe,
13983 uint32_t expected) {
13984 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
13985 uint32_t capacity = Capacity();
13986 uint32_t entry = FirstProbe(hash, capacity);
13987 for (int i = 1; i < probe; i++) {
13988 if (entry == expected) return expected;
13989 entry = NextProbe(entry, i, capacity);
13990 }
13991 return entry;
13992}
13993
13994
13995template<typename Shape, typename Key>
13996void HashTable<Shape, Key>::Swap(uint32_t entry1,
13997 uint32_t entry2,
13998 WriteBarrierMode mode) {
13999 int index1 = EntryToIndex(entry1);
14000 int index2 = EntryToIndex(entry2);
14001 Object* temp[Shape::kEntrySize];
14002 for (int j = 0; j < Shape::kEntrySize; j++) {
14003 temp[j] = get(index1 + j);
14004 }
14005 for (int j = 0; j < Shape::kEntrySize; j++) {
14006 set(index1 + j, get(index2 + j), mode);
14007 }
14008 for (int j = 0; j < Shape::kEntrySize; j++) {
14009 set(index2 + j, temp[j], mode);
14010 }
14011}
14012
14013
14014template<typename Shape, typename Key>
14015void HashTable<Shape, Key>::Rehash(Key key) {
14016 DisallowHeapAllocation no_gc;
14017 WriteBarrierMode mode = GetWriteBarrierMode(no_gc);
14018 uint32_t capacity = Capacity();
14019 bool done = false;
14020 for (int probe = 1; !done; probe++) {
14021 // All elements at entries given by one of the first _probe_ probes
14022 // are placed correctly. Other elements might need to be moved.
14023 done = true;
14024 for (uint32_t current = 0; current < capacity; current++) {
14025 Object* current_key = get(EntryToIndex(current));
14026 if (IsKey(current_key)) {
14027 uint32_t target = EntryForProbe(key, current_key, probe, current);
14028 if (current == target) continue;
14029 Object* target_key = get(EntryToIndex(target));
14030 if (!IsKey(target_key) ||
14031 EntryForProbe(key, target_key, probe, target) != target) {
14032 // Put the current element into the correct position.
14033 Swap(current, target, mode);
14034 // The other element will be processed on the next iteration.
14035 current--;
14036 } else {
14037 // The place for the current element is occupied. Leave the element
14038 // for the next probe.
14039 done = false;
14040 }
14041 }
14042 }
14043 }
14044}
14045
14046
14047template<typename Shape, typename Key>
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014048MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n,
14049 Key key,
14050 PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014051 int capacity = Capacity();
14052 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000014053 int nod = NumberOfDeletedElements();
14054 // Return if:
14055 // 50% is still free after adding n elements and
14056 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014057 if (nod <= (capacity - nof) >> 1) {
14058 int needed_free = nof >> 1;
14059 if (nof + needed_free <= capacity) return this;
14060 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014061
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014062 const int kMinCapacityForPretenure = 256;
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014063 bool should_pretenure = pretenure == TENURED ||
14064 ((capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this));
lrn@chromium.org303ada72010-10-27 09:33:13 +000014065 Object* obj;
14066 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014067 Allocate(GetHeap(),
14068 nof * 2,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014069 USE_DEFAULT_MINIMUM_CAPACITY,
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014070 should_pretenure ? TENURED : NOT_TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014071 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14072 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014073
ager@chromium.org04921a82011-06-27 13:21:41 +000014074 return Rehash(HashTable::cast(obj), key);
14075}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014076
ager@chromium.org04921a82011-06-27 13:21:41 +000014077
14078template<typename Shape, typename Key>
14079MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
14080 int capacity = Capacity();
14081 int nof = NumberOfElements();
14082
14083 // Shrink to fit the number of elements if only a quarter of the
14084 // capacity is filled with elements.
14085 if (nof > (capacity >> 2)) return this;
14086 // Allocate a new dictionary with room for at least the current
14087 // number of elements. The allocation method will make sure that
14088 // there is extra room in the dictionary for additions. Don't go
14089 // lower than room for 16 elements.
14090 int at_least_room_for = nof;
14091 if (at_least_room_for < 16) return this;
14092
14093 const int kMinCapacityForPretenure = 256;
14094 bool pretenure =
14095 (at_least_room_for > kMinCapacityForPretenure) &&
14096 !GetHeap()->InNewSpace(this);
14097 Object* obj;
14098 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014099 Allocate(GetHeap(),
14100 at_least_room_for,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014101 USE_DEFAULT_MINIMUM_CAPACITY,
14102 pretenure ? TENURED : NOT_TENURED);
ager@chromium.org04921a82011-06-27 13:21:41 +000014103 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014104 }
ager@chromium.org04921a82011-06-27 13:21:41 +000014105
14106 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014107}
14108
14109
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014110template<typename Shape, typename Key>
14111uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014112 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014113 uint32_t entry = FirstProbe(hash, capacity);
14114 uint32_t count = 1;
14115 // EnsureCapacity will guarantee the hash table is never full.
14116 while (true) {
14117 Object* element = KeyAt(entry);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014118 if (element->IsUndefined() || element->IsTheHole()) break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014119 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014120 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014121 return entry;
14122}
14123
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014124
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014125// Force instantiation of template instances class.
14126// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014127
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014128template class HashTable<StringTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014129
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014130template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014131
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014132template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014133
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014134template class HashTable<ObjectHashTableShape<1>, Object*>;
14135
14136template class HashTable<ObjectHashTableShape<2>, Object*>;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014137
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000014138template class HashTable<WeakHashTableShape<2>, Object*>;
14139
ulan@chromium.org750145a2013-03-07 15:14:13 +000014140template class Dictionary<NameDictionaryShape, Name*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014141
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014142template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014143
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014144template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
14145
14146template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014147 Allocate(Heap* heap, int at_least_space_for, PretenureFlag pretenure);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014148
14149template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014150 Allocate(Heap* heap, int at_least_space_for, PretenureFlag pretenure);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014151
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014152template MaybeObject* Dictionary<NameDictionaryShape, Name*>::
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000014153 Allocate(Heap* heap, int n, PretenureFlag pretenure);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014154
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014155template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014156 uint32_t, Object*);
14157
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014158template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
14159 AtPut(uint32_t, Object*);
14160
ulan@chromium.org65a89c22012-02-14 11:46:07 +000014161template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14162 SlowReverseLookup(Object* value);
14163
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014164template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
14165 SlowReverseLookup(Object* value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014166
ulan@chromium.org750145a2013-03-07 15:14:13 +000014167template Object* Dictionary<NameDictionaryShape, Name*>::SlowReverseLookup(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014168 Object*);
14169
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014170template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014171 FixedArray*,
14172 PropertyAttributes,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014173 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014174
ulan@chromium.org750145a2013-03-07 15:14:13 +000014175template Object* Dictionary<NameDictionaryShape, Name*>::DeleteProperty(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014176 int, JSObject::DeleteMode);
14177
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014178template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14179 DeleteProperty(int, JSObject::DeleteMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014180
ulan@chromium.org750145a2013-03-07 15:14:13 +000014181template MaybeObject* Dictionary<NameDictionaryShape, Name*>::Shrink(Name* n);
ager@chromium.org04921a82011-06-27 13:21:41 +000014182
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014183template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
ager@chromium.org04921a82011-06-27 13:21:41 +000014184 uint32_t);
14185
ulan@chromium.org750145a2013-03-07 15:14:13 +000014186template void Dictionary<NameDictionaryShape, Name*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014187 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000014188 int,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014189 PropertyAttributes,
ulan@chromium.org750145a2013-03-07 15:14:13 +000014190 Dictionary<NameDictionaryShape, Name*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014191
14192template int
ulan@chromium.org750145a2013-03-07 15:14:13 +000014193Dictionary<NameDictionaryShape, Name*>::NumberOfElementsFilterAttributes(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014194 PropertyAttributes);
14195
ulan@chromium.org750145a2013-03-07 15:14:13 +000014196template MaybeObject* Dictionary<NameDictionaryShape, Name*>::Add(
14197 Name*, Object*, PropertyDetails);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014198
lrn@chromium.org303ada72010-10-27 09:33:13 +000014199template MaybeObject*
ulan@chromium.org750145a2013-03-07 15:14:13 +000014200Dictionary<NameDictionaryShape, Name*>::GenerateNewEnumerationIndices();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014201
14202template int
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014203Dictionary<SeededNumberDictionaryShape, uint32_t>::
14204 NumberOfElementsFilterAttributes(PropertyAttributes);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014205
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014206template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014207 uint32_t, Object*, PropertyDetails);
14208
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014209template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
14210 uint32_t, Object*, PropertyDetails);
14211
14212template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14213 EnsureCapacity(int, uint32_t);
14214
14215template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
lrn@chromium.org303ada72010-10-27 09:33:13 +000014216 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014217
ulan@chromium.org750145a2013-03-07 15:14:13 +000014218template MaybeObject* Dictionary<NameDictionaryShape, Name*>::
14219 EnsureCapacity(int, Name*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014220
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014221template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
14222 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
14223
14224template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
14225 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014226
ulan@chromium.org750145a2013-03-07 15:14:13 +000014227template MaybeObject* Dictionary<NameDictionaryShape, Name*>::AddEntry(
14228 Name*, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014229
14230template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014231int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014232
14233template
ulan@chromium.org750145a2013-03-07 15:14:13 +000014234int Dictionary<NameDictionaryShape, Name*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014235
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014236template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014237int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000014238
14239
ager@chromium.org5ec48922009-05-05 07:25:34 +000014240// Collates undefined and unexisting elements below limit from position
14241// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014242MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014243 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000014244 // Must stay in dictionary mode, either because of requires_slow_elements,
14245 // or because we are not going to sort (and therefore compact) all of the
14246 // elements.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014247 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014248 HeapNumber* result_double = NULL;
14249 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
14250 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014251 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014252 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014253 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
14254 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014255 result_double = HeapNumber::cast(new_double);
14256 }
14257
lrn@chromium.org303ada72010-10-27 09:33:13 +000014258 Object* obj;
14259 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014260 SeededNumberDictionary::Allocate(GetHeap(), dict->NumberOfElements());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014261 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14262 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014263 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014264
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014265 DisallowHeapAllocation no_alloc;
ager@chromium.org5ec48922009-05-05 07:25:34 +000014266
ager@chromium.org5ec48922009-05-05 07:25:34 +000014267 uint32_t pos = 0;
14268 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014269 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014270 for (int i = 0; i < capacity; i++) {
14271 Object* k = dict->KeyAt(i);
14272 if (dict->IsKey(k)) {
14273 ASSERT(k->IsNumber());
14274 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
14275 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
14276 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
14277 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000014278 PropertyDetails details = dict->DetailsAt(i);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014279 if (details.type() == CALLBACKS || details.IsReadOnly()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000014280 // Bail out and do the sorting of undefineds and array holes in JS.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000014281 // Also bail out if the element is not supposed to be moved.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000014282 return Smi::FromInt(-1);
14283 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014284 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014285 // In the following we assert that adding the entry to the new dictionary
14286 // does not cause GC. This is the case because we made sure to allocate
14287 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000014288 if (key < limit) {
14289 if (value->IsUndefined()) {
14290 undefs++;
14291 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014292 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14293 // Adding an entry with the key beyond smi-range requires
14294 // allocation. Bailout.
14295 return Smi::FromInt(-1);
14296 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000014297 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014298 pos++;
14299 }
14300 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014301 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
14302 // Adding an entry with the key beyond smi-range requires
14303 // allocation. Bailout.
14304 return Smi::FromInt(-1);
14305 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000014306 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014307 }
14308 }
14309 }
14310
14311 uint32_t result = pos;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014312 PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014313 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014314 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000014315 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
14316 // Adding an entry with the key beyond smi-range requires
14317 // allocation. Bailout.
14318 return Smi::FromInt(-1);
14319 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014320 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000014321 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014322 pos++;
14323 undefs--;
14324 }
14325
14326 set_elements(new_dict);
14327
14328 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
14329 return Smi::FromInt(static_cast<int>(result));
14330 }
14331
14332 ASSERT_NE(NULL, result_double);
14333 result_double->set_value(static_cast<double>(result));
14334 return result_double;
14335}
14336
14337
14338// Collects all defined (non-hole) and non-undefined (array) elements at
14339// the start of the elements array.
14340// If the object is in dictionary mode, it is converted to fast elements
14341// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014342MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014343 Heap* heap = GetHeap();
14344
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +000014345 ASSERT(!map()->is_observed());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014346 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000014347 // Convert to fast elements containing only the existing properties.
14348 // Ordering is irrelevant, since we are going to sort anyway.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014349 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000014350 if (IsJSArray() || dict->requires_slow_elements() ||
jkummerow@chromium.orgc1184022013-05-28 16:58:15 +000014351 dict->max_number_key() >= limit) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000014352 return PrepareSlowElementsForSort(limit);
14353 }
14354 // Convert to fast elements.
14355
lrn@chromium.org303ada72010-10-27 09:33:13 +000014356 Object* obj;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014357 MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
14358 FAST_HOLEY_ELEMENTS);
14359 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000014360 Map* new_map = Map::cast(obj);
14361
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014362 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000014363 Object* new_array;
14364 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014365 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014366 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
14367 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014368 FixedArray* fast_elements = FixedArray::cast(new_array);
14369 dict->CopyValuesTo(fast_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014370 ValidateElements();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000014371
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014372 set_map_and_elements(new_map, fast_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000014373 } else if (HasExternalArrayElements()) {
14374 // External arrays cannot have holes or undefined elements.
14375 return Smi::FromInt(ExternalArray::cast(elements())->length());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014376 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000014377 Object* obj;
14378 { MaybeObject* maybe_obj = EnsureWritableFastElements();
14379 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14380 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014381 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000014382 ASSERT(HasFastSmiOrObjectElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000014383
14384 // Collect holes at the end, undefined before that and the rest at the
14385 // start, and return the number of non-hole, non-undefined values.
14386
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014387 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
14388 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000014389 if (limit > elements_length) {
14390 limit = elements_length ;
14391 }
14392 if (limit == 0) {
14393 return Smi::FromInt(0);
14394 }
14395
14396 HeapNumber* result_double = NULL;
14397 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
14398 // Pessimistically allocate space for return value before
14399 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014400 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014401 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014402 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
14403 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014404 result_double = HeapNumber::cast(new_double);
14405 }
14406
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014407 uint32_t result = 0;
14408 if (elements_base->map() == heap->fixed_double_array_map()) {
14409 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
14410 // Split elements into defined and the_hole, in that order.
14411 unsigned int holes = limit;
14412 // Assume most arrays contain no holes and undefined values, so minimize the
14413 // number of stores of non-undefined, non-the-hole values.
14414 for (unsigned int i = 0; i < holes; i++) {
14415 if (elements->is_the_hole(i)) {
14416 holes--;
14417 } else {
14418 continue;
14419 }
14420 // Position i needs to be filled.
14421 while (holes > i) {
14422 if (elements->is_the_hole(holes)) {
14423 holes--;
14424 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000014425 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014426 break;
14427 }
14428 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014429 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014430 result = holes;
14431 while (holes < limit) {
14432 elements->set_the_hole(holes);
14433 holes++;
14434 }
14435 } else {
14436 FixedArray* elements = FixedArray::cast(elements_base);
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014437 DisallowHeapAllocation no_gc;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014438
14439 // Split elements into defined, undefined and the_hole, in that order. Only
14440 // count locations for undefined and the hole, and fill them afterwards.
rossberg@chromium.org79e79022013-06-03 15:43:46 +000014441 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_gc);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014442 unsigned int undefs = limit;
14443 unsigned int holes = limit;
14444 // Assume most arrays contain no holes and undefined values, so minimize the
14445 // number of stores of non-undefined, non-the-hole values.
14446 for (unsigned int i = 0; i < undefs; i++) {
14447 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000014448 if (current->IsTheHole()) {
14449 holes--;
14450 undefs--;
14451 } else if (current->IsUndefined()) {
14452 undefs--;
14453 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014454 continue;
14455 }
14456 // Position i needs to be filled.
14457 while (undefs > i) {
14458 current = elements->get(undefs);
14459 if (current->IsTheHole()) {
14460 holes--;
14461 undefs--;
14462 } else if (current->IsUndefined()) {
14463 undefs--;
14464 } else {
14465 elements->set(i, current, write_barrier);
14466 break;
14467 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014468 }
14469 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000014470 result = undefs;
14471 while (undefs < holes) {
14472 elements->set_undefined(undefs);
14473 undefs++;
14474 }
14475 while (holes < limit) {
14476 elements->set_the_hole(holes);
14477 holes++;
14478 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000014479 }
14480
14481 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
14482 return Smi::FromInt(static_cast<int>(result));
14483 }
14484 ASSERT_NE(NULL, result_double);
14485 result_double->set_value(static_cast<double>(result));
14486 return result_double;
14487}
14488
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014489
danno@chromium.orgf005df62013-04-30 16:36:45 +000014490ExternalArrayType JSTypedArray::type() {
14491 switch (elements()->map()->instance_type()) {
14492 case EXTERNAL_BYTE_ARRAY_TYPE:
14493 return kExternalByteArray;
14494 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
14495 return kExternalUnsignedByteArray;
14496 case EXTERNAL_SHORT_ARRAY_TYPE:
14497 return kExternalShortArray;
14498 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
14499 return kExternalUnsignedShortArray;
14500 case EXTERNAL_INT_ARRAY_TYPE:
14501 return kExternalIntArray;
14502 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
14503 return kExternalUnsignedIntArray;
14504 case EXTERNAL_FLOAT_ARRAY_TYPE:
14505 return kExternalFloatArray;
14506 case EXTERNAL_DOUBLE_ARRAY_TYPE:
14507 return kExternalDoubleArray;
14508 case EXTERNAL_PIXEL_ARRAY_TYPE:
14509 return kExternalPixelArray;
14510 default:
14511 return static_cast<ExternalArrayType>(-1);
14512 }
14513}
14514
ager@chromium.org5ec48922009-05-05 07:25:34 +000014515
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014516size_t JSTypedArray::element_size() {
14517 switch (elements()->map()->instance_type()) {
14518 case EXTERNAL_BYTE_ARRAY_TYPE:
14519 return 1;
14520 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
14521 return 1;
14522 case EXTERNAL_SHORT_ARRAY_TYPE:
14523 return 2;
14524 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
14525 return 2;
14526 case EXTERNAL_INT_ARRAY_TYPE:
14527 return 4;
14528 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
14529 return 4;
14530 case EXTERNAL_FLOAT_ARRAY_TYPE:
14531 return 4;
14532 case EXTERNAL_DOUBLE_ARRAY_TYPE:
14533 return 8;
14534 case EXTERNAL_PIXEL_ARRAY_TYPE:
14535 return 1;
14536 default:
14537 UNREACHABLE();
14538 return 0;
14539 }
14540}
14541
14542
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000014543Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014544 uint8_t clamped_value = 0;
14545 if (index < static_cast<uint32_t>(length())) {
14546 if (value->IsSmi()) {
14547 int int_value = Smi::cast(value)->value();
14548 if (int_value < 0) {
14549 clamped_value = 0;
14550 } else if (int_value > 255) {
14551 clamped_value = 255;
14552 } else {
14553 clamped_value = static_cast<uint8_t>(int_value);
14554 }
14555 } else if (value->IsHeapNumber()) {
14556 double double_value = HeapNumber::cast(value)->value();
14557 if (!(double_value > 0)) {
14558 // NaN and less than zero clamp to zero.
14559 clamped_value = 0;
14560 } else if (double_value > 255) {
14561 // Greater than 255 clamp to 255.
14562 clamped_value = 255;
14563 } else {
14564 // Other doubles are rounded to the nearest integer.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014565 clamped_value = static_cast<uint8_t>(lrint(double_value));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000014566 }
14567 } else {
14568 // Clamp undefined to zero (default). All other types have been
14569 // converted to a number type further up in the call chain.
14570 ASSERT(value->IsUndefined());
14571 }
14572 set(index, clamped_value);
14573 }
14574 return Smi::FromInt(clamped_value);
14575}
14576
14577
ager@chromium.org3811b432009-10-28 14:53:37 +000014578template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014579static MaybeObject* ExternalArrayIntSetter(Heap* heap,
14580 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000014581 uint32_t index,
14582 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014583 ValueType cast_value = 0;
14584 if (index < static_cast<uint32_t>(receiver->length())) {
14585 if (value->IsSmi()) {
14586 int int_value = Smi::cast(value)->value();
14587 cast_value = static_cast<ValueType>(int_value);
14588 } else if (value->IsHeapNumber()) {
14589 double double_value = HeapNumber::cast(value)->value();
14590 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
14591 } else {
14592 // Clamp undefined to zero (default). All other types have been
14593 // converted to a number type further up in the call chain.
14594 ASSERT(value->IsUndefined());
14595 }
14596 receiver->set(index, cast_value);
14597 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014598 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014599}
14600
14601
lrn@chromium.org303ada72010-10-27 09:33:13 +000014602MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014603 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014604 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014605}
14606
14607
lrn@chromium.org303ada72010-10-27 09:33:13 +000014608MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
14609 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014610 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014611 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014612}
14613
14614
lrn@chromium.org303ada72010-10-27 09:33:13 +000014615MaybeObject* ExternalShortArray::SetValue(uint32_t index,
14616 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014617 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014618 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014619}
14620
14621
lrn@chromium.org303ada72010-10-27 09:33:13 +000014622MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
14623 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014624 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014625 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014626}
14627
14628
lrn@chromium.org303ada72010-10-27 09:33:13 +000014629MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014630 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014631 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014632}
14633
14634
lrn@chromium.org303ada72010-10-27 09:33:13 +000014635MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000014636 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014637 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000014638 if (index < static_cast<uint32_t>(length())) {
14639 if (value->IsSmi()) {
14640 int int_value = Smi::cast(value)->value();
14641 cast_value = static_cast<uint32_t>(int_value);
14642 } else if (value->IsHeapNumber()) {
14643 double double_value = HeapNumber::cast(value)->value();
14644 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
14645 } else {
14646 // Clamp undefined to zero (default). All other types have been
14647 // converted to a number type further up in the call chain.
14648 ASSERT(value->IsUndefined());
14649 }
14650 set(index, cast_value);
14651 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014652 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014653}
14654
14655
lrn@chromium.org303ada72010-10-27 09:33:13 +000014656MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014657 float cast_value = static_cast<float>(OS::nan_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014658 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000014659 if (index < static_cast<uint32_t>(length())) {
14660 if (value->IsSmi()) {
14661 int int_value = Smi::cast(value)->value();
14662 cast_value = static_cast<float>(int_value);
14663 } else if (value->IsHeapNumber()) {
14664 double double_value = HeapNumber::cast(value)->value();
14665 cast_value = static_cast<float>(double_value);
14666 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014667 // Clamp undefined to NaN (default). All other types have been
ager@chromium.org3811b432009-10-28 14:53:37 +000014668 // converted to a number type further up in the call chain.
14669 ASSERT(value->IsUndefined());
14670 }
14671 set(index, cast_value);
14672 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014673 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000014674}
14675
14676
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014677MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014678 double double_value = OS::nan_value();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014679 Heap* heap = GetHeap();
14680 if (index < static_cast<uint32_t>(length())) {
14681 if (value->IsSmi()) {
14682 int int_value = Smi::cast(value)->value();
14683 double_value = static_cast<double>(int_value);
14684 } else if (value->IsHeapNumber()) {
14685 double_value = HeapNumber::cast(value)->value();
14686 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000014687 // Clamp undefined to NaN (default). All other types have been
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000014688 // converted to a number type further up in the call chain.
14689 ASSERT(value->IsUndefined());
14690 }
14691 set(index, double_value);
14692 }
14693 return heap->AllocateHeapNumber(double_value);
14694}
14695
14696
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000014697PropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014698 ASSERT(!HasFastProperties());
14699 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000014700 return PropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014701}
14702
14703
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014704Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
14705 Handle<GlobalObject> global,
14706 Handle<Name> name) {
14707 ASSERT(!global->HasFastProperties());
14708 int entry = global->property_dictionary()->FindEntry(*name);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014709 if (entry == NameDictionary::kNotFound) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014710 Isolate* isolate = global->GetIsolate();
14711 Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
14712 isolate->factory()->the_hole_value());
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014713 PropertyDetails details(NONE, NORMAL, 0);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014714 details = details.AsDeleted();
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014715 Handle<NameDictionary> dictionary = NameDictionaryAdd(
14716 handle(global->property_dictionary()), name, cell, details);
14717 global->set_properties(*dictionary);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014718 return cell;
14719 } else {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014720 Object* value = global->property_dictionary()->ValueAt(entry);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000014721 ASSERT(value->IsPropertyCell());
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014722 return handle(PropertyCell::cast(value));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014723 }
14724}
14725
14726
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014727MaybeObject* StringTable::LookupString(String* string, Object** s) {
14728 InternalizedStringKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014729 return LookupKey(&key, s);
14730}
14731
14732
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014733// This class is used for looking up two character strings in the string table.
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014734// If we don't have a hit we don't want to waste much time so we unroll the
14735// string hash calculation loop here for speed. Doesn't work if the two
14736// characters form a decimal integer, since such strings have a different hash
14737// algorithm.
14738class TwoCharHashTableKey : public HashTableKey {
14739 public:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014740 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014741 : c1_(c1), c2_(c2) {
14742 // Char 1.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000014743 uint32_t hash = seed;
14744 hash += c1;
14745 hash += hash << 10;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014746 hash ^= hash >> 6;
14747 // Char 2.
14748 hash += c2;
14749 hash += hash << 10;
14750 hash ^= hash >> 6;
14751 // GetHash.
14752 hash += hash << 3;
14753 hash ^= hash >> 11;
14754 hash += hash << 15;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000014755 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014756 hash_ = hash;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014757#ifdef DEBUG
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014758 // If this assert fails then we failed to reproduce the two-character
14759 // version of the string hashing algorithm above. One reason could be
14760 // that we were passed two digits as characters, since the hash
14761 // algorithm is different in that case.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014762 uint16_t chars[2] = {c1, c2};
14763 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
14764 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
14765 ASSERT_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014766#endif
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014767 }
14768
14769 bool IsMatch(Object* o) {
14770 if (!o->IsString()) return false;
14771 String* other = String::cast(o);
14772 if (other->length() != 2) return false;
14773 if (other->Get(0) != c1_) return false;
14774 return other->Get(1) == c2_;
14775 }
14776
14777 uint32_t Hash() { return hash_; }
14778 uint32_t HashForObject(Object* key) {
14779 if (!key->IsString()) return 0;
14780 return String::cast(key)->Hash();
14781 }
14782
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014783 Object* AsObject(Heap* heap) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014784 // The TwoCharHashTableKey is only used for looking in the string
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014785 // table, not for adding to it.
14786 UNREACHABLE();
14787 return NULL;
14788 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000014789
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014790 private:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014791 uint16_t c1_;
14792 uint16_t c2_;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014793 uint32_t hash_;
14794};
14795
14796
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014797bool StringTable::LookupStringIfExists(String* string, String** result) {
14798 InternalizedStringKey key(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +000014799 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014800 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000014801 return false;
14802 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014803 *result = String::cast(KeyAt(entry));
14804 ASSERT(StringShape(*result).IsInternalized());
ager@chromium.org7c537e22008-10-16 08:43:32 +000014805 return true;
14806 }
14807}
14808
14809
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014810bool StringTable::LookupTwoCharsStringIfExists(uint16_t c1,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014811 uint16_t c2,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014812 String** result) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014813 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014814 int entry = FindEntry(&key);
14815 if (entry == kNotFound) {
14816 return false;
14817 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014818 *result = String::cast(KeyAt(entry));
14819 ASSERT(StringShape(*result).IsInternalized());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000014820 return true;
14821 }
14822}
14823
14824
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014825MaybeObject* StringTable::LookupUtf8String(Vector<const char> str,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014826 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014827 Utf8StringKey key(str, GetHeap()->HashSeed());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014828 return LookupKey(&key, s);
14829}
14830
14831
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014832MaybeObject* StringTable::LookupOneByteString(Vector<const uint8_t> str,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000014833 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014834 OneByteStringKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014835 return LookupKey(&key, s);
14836}
14837
14838
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014839MaybeObject* StringTable::LookupSubStringOneByteString(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000014840 Handle<SeqOneByteString> str,
14841 int from,
14842 int length,
14843 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014844 SubStringOneByteStringKey key(str, from, length);
danno@chromium.org40cb8782011-05-25 07:58:50 +000014845 return LookupKey(&key, s);
14846}
14847
14848
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014849MaybeObject* StringTable::LookupTwoByteString(Vector<const uc16> str,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014850 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014851 TwoByteStringKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000014852 return LookupKey(&key, s);
14853}
14854
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000014855
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014856MaybeObject* StringTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014857 int entry = FindEntry(key);
14858
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014859 // String already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014860 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014861 *s = KeyAt(entry);
14862 return this;
14863 }
14864
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014865 // Adding new string. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014866 Object* obj;
14867 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
14868 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14869 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014870
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014871 // Create string object.
14872 Object* string;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014873 { MaybeObject* maybe_string = key->AsObject(GetHeap());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014874 if (!maybe_string->ToObject(&string)) return maybe_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000014875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014876
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014877 // If the string table grew as part of EnsureCapacity, obj is not
14878 // the current string table and therefore we cannot use
14879 // StringTable::cast here.
14880 StringTable* table = reinterpret_cast<StringTable*>(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014881
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014882 // Add the new string and return it along with the string table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014883 entry = table->FindInsertionEntry(key->Hash());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014884 table->set(EntryToIndex(entry), string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014885 table->ElementAdded();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014886 *s = string;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014887 return table;
14888}
14889
14890
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014891// The key for the script compilation cache is dependent on the mode flags,
14892// because they change the global language mode and thus binding behaviour.
14893// If flags change at some point, we must ensure that we do not hit the cache
14894// for code compiled with different settings.
14895static LanguageMode CurrentGlobalLanguageMode() {
14896 return FLAG_use_strict
14897 ? (FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE)
14898 : CLASSIC_MODE;
14899}
14900
14901
14902Object* CompilationCacheTable::Lookup(String* src, Context* context) {
14903 SharedFunctionInfo* shared = context->closure()->shared();
14904 StringSharedKey key(src,
14905 shared,
14906 CurrentGlobalLanguageMode(),
14907 RelocInfo::kNoPosition);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014908 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014909 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014910 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014911}
14912
14913
ricow@chromium.org83aa5492011-02-07 12:42:56 +000014914Object* CompilationCacheTable::LookupEval(String* src,
14915 Context* context,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000014916 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000014917 int scope_position) {
14918 StringSharedKey key(src,
14919 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000014920 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000014921 scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000014922 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014923 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000014924 return get(EntryToIndex(entry) + 1);
14925}
14926
14927
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014928Object* CompilationCacheTable::LookupRegExp(String* src,
14929 JSRegExp::Flags flags) {
14930 RegExpKey key(src, flags);
14931 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014932 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014933 return get(EntryToIndex(entry) + 1);
14934}
14935
14936
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014937MaybeObject* CompilationCacheTable::Put(String* src,
14938 Context* context,
14939 Object* value) {
14940 SharedFunctionInfo* shared = context->closure()->shared();
14941 StringSharedKey key(src,
14942 shared,
14943 CurrentGlobalLanguageMode(),
14944 RelocInfo::kNoPosition);
14945 CompilationCacheTable* cache;
14946 MaybeObject* maybe_cache = EnsureCapacity(1, &key);
14947 if (!maybe_cache->To(&cache)) return maybe_cache;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014948
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014949 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014950 MaybeObject* maybe_k = key.AsObject(GetHeap());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014951 if (!maybe_k->To(&k)) return maybe_k;
14952
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014953 int entry = cache->FindInsertionEntry(key.Hash());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014954 cache->set(EntryToIndex(entry), k);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014955 cache->set(EntryToIndex(entry) + 1, value);
14956 cache->ElementAdded();
14957 return cache;
14958}
14959
14960
lrn@chromium.org303ada72010-10-27 09:33:13 +000014961MaybeObject* CompilationCacheTable::PutEval(String* src,
14962 Context* context,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000014963 SharedFunctionInfo* value,
14964 int scope_position) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +000014965 StringSharedKey key(src,
14966 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000014967 value->language_mode(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000014968 scope_position);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014969 Object* obj;
14970 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
14971 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14972 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000014973
14974 CompilationCacheTable* cache =
14975 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014976 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000014977
lrn@chromium.org303ada72010-10-27 09:33:13 +000014978 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014979 { MaybeObject* maybe_k = key.AsObject(GetHeap());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014980 if (!maybe_k->ToObject(&k)) return maybe_k;
14981 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000014982
14983 cache->set(EntryToIndex(entry), k);
14984 cache->set(EntryToIndex(entry) + 1, value);
14985 cache->ElementAdded();
14986 return cache;
14987}
14988
14989
lrn@chromium.org303ada72010-10-27 09:33:13 +000014990MaybeObject* CompilationCacheTable::PutRegExp(String* src,
14991 JSRegExp::Flags flags,
14992 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014993 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014994 Object* obj;
14995 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
14996 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14997 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014998
14999 CompilationCacheTable* cache =
15000 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015001 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000015002 // We store the value in the key slot, and compare the search key
15003 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000015004 cache->set(EntryToIndex(entry), value);
15005 cache->set(EntryToIndex(entry) + 1, value);
15006 cache->ElementAdded();
15007 return cache;
15008}
15009
15010
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015011void CompilationCacheTable::Remove(Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015012 Object* the_hole_value = GetHeap()->the_hole_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015013 for (int entry = 0, size = Capacity(); entry < size; entry++) {
15014 int entry_index = EntryToIndex(entry);
15015 int value_index = entry_index + 1;
15016 if (get(value_index) == value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015017 NoWriteBarrierSet(this, entry_index, the_hole_value);
15018 NoWriteBarrierSet(this, value_index, the_hole_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015019 ElementRemoved();
15020 }
15021 }
15022 return;
15023}
15024
15025
ulan@chromium.org750145a2013-03-07 15:14:13 +000015026// StringsKey used for HashTable where key is array of internalized strings.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015027class StringsKey : public HashTableKey {
ager@chromium.org236ad962008-09-25 09:45:57 +000015028 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015029 explicit StringsKey(FixedArray* strings) : strings_(strings) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000015030
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015031 bool IsMatch(Object* strings) {
15032 FixedArray* o = FixedArray::cast(strings);
15033 int len = strings_->length();
ager@chromium.org236ad962008-09-25 09:45:57 +000015034 if (o->length() != len) return false;
15035 for (int i = 0; i < len; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015036 if (o->get(i) != strings_->get(i)) return false;
ager@chromium.org236ad962008-09-25 09:45:57 +000015037 }
15038 return true;
15039 }
15040
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015041 uint32_t Hash() { return HashForObject(strings_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000015042
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015043 uint32_t HashForObject(Object* obj) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015044 FixedArray* strings = FixedArray::cast(obj);
15045 int len = strings->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015046 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000015047 for (int i = 0; i < len; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015048 hash ^= String::cast(strings->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000015049 }
15050 return hash;
15051 }
15052
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015053 Object* AsObject(Heap* heap) { return strings_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000015054
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015055 private:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015056 FixedArray* strings_;
ager@chromium.org236ad962008-09-25 09:45:57 +000015057};
15058
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015059
ager@chromium.org236ad962008-09-25 09:45:57 +000015060Object* MapCache::Lookup(FixedArray* array) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015061 StringsKey key(array);
ager@chromium.org236ad962008-09-25 09:45:57 +000015062 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015063 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015064 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000015065}
15066
15067
lrn@chromium.org303ada72010-10-27 09:33:13 +000015068MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000015069 StringsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015070 Object* obj;
15071 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
15072 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15073 }
ager@chromium.org236ad962008-09-25 09:45:57 +000015074
15075 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015076 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000015077 cache->set(EntryToIndex(entry), array);
15078 cache->set(EntryToIndex(entry) + 1, value);
15079 cache->ElementAdded();
15080 return cache;
15081}
15082
15083
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015084template<typename Shape, typename Key>
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015085MaybeObject* Dictionary<Shape, Key>::Allocate(Heap* heap,
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000015086 int at_least_space_for,
15087 PretenureFlag pretenure) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000015088 Object* obj;
15089 { MaybeObject* maybe_obj =
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +000015090 HashTable<Shape, Key>::Allocate(
15091 heap,
15092 at_least_space_for,
15093 HashTable<Shape, Key>::USE_DEFAULT_MINIMUM_CAPACITY,
15094 pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015095 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015096 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000015097 // Initialize the next enumeration index.
15098 Dictionary<Shape, Key>::cast(obj)->
15099 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015100 return obj;
15101}
15102
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015103
ulan@chromium.org750145a2013-03-07 15:14:13 +000015104void NameDictionary::DoGenerateNewEnumerationIndices(
15105 Handle<NameDictionary> dictionary) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015106 CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
15107 dictionary->GenerateNewEnumerationIndices());
15108}
15109
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015110template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015111MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015112 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015113 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015114
15115 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015116 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015117 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015118 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15119 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015120 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015121 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000015122 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015123 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015124
15125 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015126 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015127 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15128 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015129 FixedArray* enumeration_order = FixedArray::cast(obj);
15130
15131 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015132 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015133 int pos = 0;
15134 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015135 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000015136 int index = DetailsAt(i).dictionary_index();
15137 enumeration_order->set(pos++, Smi::FromInt(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015138 }
15139 }
15140
15141 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000015142 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015143
15144 // Overwrite the enumeration_order with the enumeration indices.
15145 for (int i = 0; i < length; i++) {
15146 int index = Smi::cast(iteration_order->get(i))->value();
15147 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000015148 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015149 }
15150
15151 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015152 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015153 pos = 0;
15154 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015155 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015156 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
15157 PropertyDetails details = DetailsAt(i);
danno@chromium.orgf005df62013-04-30 16:36:45 +000015158 PropertyDetails new_details = PropertyDetails(
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015159 details.attributes(), details.type(), enum_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015160 DetailsAtPut(i, new_details);
15161 }
15162 }
15163
15164 // Set the next enumeration index.
15165 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
15166 return this;
15167}
15168
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015169template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015170MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000015171 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015172 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015173 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
15174 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015175 Object* result;
15176 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
15177 if (!maybe_result->ToObject(&result)) return maybe_result;
15178 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015179 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015180 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015181}
15182
15183
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015184template<typename Shape, typename Key>
15185Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000015186 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015187 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015188 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000015189 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000015190 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015191 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000015192 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015193 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015194 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015195 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015196}
15197
15198
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015199template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000015200MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
15201 return HashTable<Shape, Key>::Shrink(key);
15202}
15203
15204
15205template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015206MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000015207 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015208
15209 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015210 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015211 ValueAtPut(entry, value);
15212 return this;
15213 }
15214
15215 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015216 Object* obj;
15217 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15218 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15219 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015220
lrn@chromium.org303ada72010-10-27 09:33:13 +000015221 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015222 { MaybeObject* maybe_k = Shape::AsObject(this->GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015223 if (!maybe_k->ToObject(&k)) return maybe_k;
15224 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015225 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015226
15227 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
15228 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015229}
15230
15231
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015232template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015233MaybeObject* Dictionary<Shape, Key>::Add(Key key,
15234 Object* value,
15235 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015236 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000015237 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015238 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015239 Object* obj;
15240 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15241 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15242 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015243
15244 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
15245 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015246}
15247
15248
15249// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015250template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000015251MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
15252 Object* value,
15253 PropertyDetails details,
15254 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015255 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000015256 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015257 { MaybeObject* maybe_k = Shape::AsObject(this->GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015258 if (!maybe_k->ToObject(&k)) return maybe_k;
15259 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015260
15261 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015262 // Insert element at empty or deleted entry
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015263 if (!details.IsDeleted() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000015264 details.dictionary_index() == 0 &&
15265 Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015266 // Assign an enumeration index to the property and update
15267 // SetNextEnumerationIndex.
15268 int index = NextEnumerationIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015269 details = PropertyDetails(details.attributes(), details.type(), index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015270 SetNextEnumerationIndex(index + 1);
15271 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015272 SetEntry(entry, k, value, details);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015273 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() ||
15274 Dictionary<Shape, Key>::KeyAt(entry)->IsName()));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015275 HashTable<Shape, Key>::ElementAdded();
15276 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015277}
15278
15279
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015280void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015281 // If the dictionary requires slow elements an element has already
15282 // been added at a high index.
15283 if (requires_slow_elements()) return;
15284 // Check if this index is high enough that we should require slow
15285 // elements.
15286 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000015287 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015288 return;
15289 }
15290 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000015291 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015292 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015293 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000015294 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015295 }
15296}
15297
15298
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015299MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
15300 Object* value,
15301 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015302 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000015303 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015304 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015305}
15306
15307
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015308MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
15309 Object* value) {
15310 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015311 return Add(key, value, PropertyDetails(NONE, NORMAL, 0));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015312}
15313
15314
15315MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015316 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015317 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015318}
15319
15320
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015321MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
15322 Object* value) {
15323 return AtPut(key, value);
15324}
15325
15326
15327Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
15328 Handle<SeededNumberDictionary> dictionary,
15329 uint32_t index,
15330 Handle<Object> value,
15331 PropertyDetails details) {
15332 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
15333 dictionary->Set(index, *value, details),
15334 SeededNumberDictionary);
15335}
15336
15337
15338Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
15339 Handle<UnseededNumberDictionary> dictionary,
15340 uint32_t index,
15341 Handle<Object> value) {
15342 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
15343 dictionary->Set(index, *value),
15344 UnseededNumberDictionary);
15345}
15346
15347
15348MaybeObject* SeededNumberDictionary::Set(uint32_t key,
15349 Object* value,
15350 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015351 int entry = FindEntry(key);
15352 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015353 // Preserve enumeration index.
15354 details = PropertyDetails(details.attributes(),
15355 details.type(),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015356 DetailsAt(entry).dictionary_index());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015357 MaybeObject* maybe_object_key =
15358 SeededNumberDictionaryShape::AsObject(GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000015359 Object* object_key;
15360 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000015361 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015362 return this;
15363}
15364
15365
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015366MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
15367 Object* value) {
15368 int entry = FindEntry(key);
15369 if (entry == kNotFound) return AddNumberEntry(key, value);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000015370 MaybeObject* maybe_object_key =
15371 UnseededNumberDictionaryShape::AsObject(GetHeap(), key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000015372 Object* object_key;
15373 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
15374 SetEntry(entry, object_key, value);
15375 return this;
15376}
15377
15378
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000015379
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015380template<typename Shape, typename Key>
15381int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
15382 PropertyAttributes filter) {
15383 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015384 int result = 0;
15385 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015386 Object* k = HashTable<Shape, Key>::KeyAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015387 if (HashTable<Shape, Key>::IsKey(k) &&
15388 ((filter & SYMBOLIC) == 0 || !k->IsSymbol())) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015389 PropertyDetails details = DetailsAt(i);
15390 if (details.IsDeleted()) continue;
15391 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015392 if ((attr & filter) == 0) result++;
15393 }
15394 }
15395 return result;
15396}
15397
15398
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015399template<typename Shape, typename Key>
15400int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015401 return NumberOfElementsFilterAttributes(
15402 static_cast<PropertyAttributes>(DONT_ENUM));
15403}
15404
15405
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015406template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015407void Dictionary<Shape, Key>::CopyKeysTo(
15408 FixedArray* storage,
15409 PropertyAttributes filter,
15410 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015411 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015412 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015413 int index = 0;
15414 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015415 Object* k = HashTable<Shape, Key>::KeyAt(i);
15416 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015417 PropertyDetails details = DetailsAt(i);
15418 if (details.IsDeleted()) continue;
15419 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015420 if ((attr & filter) == 0) storage->set(index++, k);
15421 }
15422 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015423 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
15424 storage->SortPairs(storage, index);
15425 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015426 ASSERT(storage->length() >= index);
15427}
15428
15429
ulan@chromium.org750145a2013-03-07 15:14:13 +000015430FixedArray* NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015431 int length = storage->length();
15432 ASSERT(length >= NumberOfEnumElements());
15433 Heap* heap = GetHeap();
15434 Object* undefined_value = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015435 int capacity = Capacity();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015436 int properties = 0;
15437
15438 // Fill in the enumeration array by assigning enumerable keys at their
15439 // enumeration index. This will leave holes in the array if there are keys
15440 // that are deleted or not enumerable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015441 for (int i = 0; i < capacity; i++) {
15442 Object* k = KeyAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015443 if (IsKey(k) && !k->IsSymbol()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015444 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015445 if (details.IsDeleted() || details.IsDontEnum()) continue;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015446 properties++;
15447 storage->set(details.dictionary_index() - 1, k);
15448 if (properties == length) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015449 }
15450 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015451
15452 // There are holes in the enumeration array if less properties were assigned
15453 // than the length of the array. If so, crunch all the existing properties
15454 // together by shifting them to the left (maintaining the enumeration order),
15455 // and trimming of the right side of the array.
15456 if (properties < length) {
15457 if (properties == 0) return heap->empty_fixed_array();
15458 properties = 0;
15459 for (int i = 0; i < length; ++i) {
15460 Object* value = storage->get(i);
15461 if (value != undefined_value) {
15462 storage->set(properties, value);
15463 ++properties;
15464 }
15465 }
15466 RightTrimFixedArray<FROM_MUTATOR>(heap, storage, length - properties);
15467 }
15468 return storage;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015469}
15470
15471
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015472template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015473void Dictionary<Shape, Key>::CopyKeysTo(
15474 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000015475 int index,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000015476 PropertyAttributes filter,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015477 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015478 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
15479 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015480 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015481 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015482 Object* k = HashTable<Shape, Key>::KeyAt(i);
15483 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000015484 PropertyDetails details = DetailsAt(i);
15485 if (details.IsDeleted()) continue;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000015486 PropertyAttributes attr = details.attributes();
15487 if ((attr & filter) == 0) storage->set(index++, k);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015488 }
15489 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000015490 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
15491 storage->SortPairs(storage, index);
15492 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015493 ASSERT(storage->length() >= index);
15494}
15495
15496
15497// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015498template<typename Shape, typename Key>
15499Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
15500 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015501 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015502 Object* k = HashTable<Shape, Key>::KeyAt(i);
15503 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000015504 Object* e = ValueAt(i);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000015505 if (e->IsPropertyCell()) {
15506 e = PropertyCell::cast(e)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000015507 }
15508 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015509 }
15510 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015511 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015512 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015513}
15514
15515
ulan@chromium.org750145a2013-03-07 15:14:13 +000015516MaybeObject* NameDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015517 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015518 // Make sure we preserve dictionary representation if there are too many
15519 // descriptors.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015520 int number_of_elements = NumberOfElements();
15521 if (number_of_elements > DescriptorArray::kMaxNumberOfDescriptors) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015522
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000015523 if (number_of_elements != NextEnumerationIndex()) {
15524 MaybeObject* maybe_result = GenerateNewEnumerationIndices();
15525 if (maybe_result->IsFailure()) return maybe_result;
15526 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015527
15528 int instance_descriptor_length = 0;
15529 int number_of_fields = 0;
15530
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015531 Heap* heap = GetHeap();
15532
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015533 // Compute the length of the instance descriptor.
15534 int capacity = Capacity();
15535 for (int i = 0; i < capacity; i++) {
15536 Object* k = KeyAt(i);
15537 if (IsKey(k)) {
15538 Object* value = ValueAt(i);
15539 PropertyType type = DetailsAt(i).type();
15540 ASSERT(type != FIELD);
15541 instance_descriptor_length++;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000015542 if (type == NORMAL && !value->IsJSFunction()) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000015543 number_of_fields += 1;
15544 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015545 }
15546 }
15547
yangguo@chromium.org304cc332012-07-24 07:59:48 +000015548 int inobject_props = obj->map()->inobject_properties();
15549
15550 // Allocate new map.
15551 Map* new_map;
15552 MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
15553 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +000015554 new_map->set_dictionary_map(false);
yangguo@chromium.org304cc332012-07-24 07:59:48 +000015555
15556 if (instance_descriptor_length == 0) {
15557 ASSERT_LE(unused_property_fields, inobject_props);
15558 // Transform the object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000015559 new_map->set_unused_property_fields(inobject_props);
yangguo@chromium.org304cc332012-07-24 07:59:48 +000015560 obj->set_map(new_map);
15561 obj->set_properties(heap->empty_fixed_array());
15562 // Check that it really works.
15563 ASSERT(obj->HasFastProperties());
15564 return obj;
15565 }
15566
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015567 // Allocate the instance descriptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015568 DescriptorArray* descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015569 MaybeObject* maybe_descriptors =
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000015570 DescriptorArray::Allocate(GetIsolate(), instance_descriptor_length);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015571 if (!maybe_descriptors->To(&descriptors)) {
15572 return maybe_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +000015573 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015574
ulan@chromium.org56c14af2012-09-20 12:51:09 +000015575 DescriptorArray::WhitenessWitness witness(descriptors);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015576
ager@chromium.org32912102009-01-16 10:38:43 +000015577 int number_of_allocated_fields =
15578 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000015579 if (number_of_allocated_fields < 0) {
15580 // There is enough inobject space for all fields (including unused).
15581 number_of_allocated_fields = 0;
15582 unused_property_fields = inobject_props - number_of_fields;
15583 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015584
15585 // Allocate the fixed array for the fields.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015586 FixedArray* fields;
15587 MaybeObject* maybe_fields =
15588 heap->AllocateFixedArray(number_of_allocated_fields);
15589 if (!maybe_fields->To(&fields)) return maybe_fields;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015590
15591 // Fill in the instance descriptor and the fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015592 int current_offset = 0;
15593 for (int i = 0; i < capacity; i++) {
15594 Object* k = KeyAt(i);
15595 if (IsKey(k)) {
15596 Object* value = ValueAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015597 Name* key;
15598 if (k->IsSymbol()) {
15599 key = Symbol::cast(k);
15600 } else {
15601 // Ensure the key is a unique name before writing into the
15602 // instance descriptor.
15603 MaybeObject* maybe_key = heap->InternalizeString(String::cast(k));
15604 if (!maybe_key->To(&key)) return maybe_key;
15605 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015606
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015607 PropertyDetails details = DetailsAt(i);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015608 int enumeration_index = details.dictionary_index();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015609 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000015610
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000015611 if (value->IsJSFunction()) {
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000015612 ConstantDescriptor d(key, value, details.attributes());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015613 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015614 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000015615 if (current_offset < inobject_props) {
15616 obj->InObjectPropertyAtPut(current_offset,
15617 value,
15618 UPDATE_WRITE_BARRIER);
15619 } else {
15620 int offset = current_offset - inobject_props;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015621 fields->set(offset, value);
ager@chromium.org32912102009-01-16 10:38:43 +000015622 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015623 FieldDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015624 current_offset++,
15625 details.attributes(),
danno@chromium.orgf005df62013-04-30 16:36:45 +000015626 // TODO(verwaest): value->OptimalRepresentation();
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015627 Representation::Tagged());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015628 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015629 } else if (type == CALLBACKS) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015630 CallbacksDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015631 value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +000015632 details.attributes());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015633 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015634 } else {
15635 UNREACHABLE();
15636 }
15637 }
15638 }
15639 ASSERT(current_offset == number_of_fields);
15640
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000015641 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015642
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000015643 new_map->InitializeDescriptors(descriptors);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000015644 new_map->set_unused_property_fields(unused_property_fields);
15645
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015646 // Transform the object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000015647 obj->set_map(new_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000015648
verwaest@chromium.org753aee42012-07-17 16:15:42 +000015649 obj->set_properties(fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015650 ASSERT(obj->IsJSObject());
15651
ager@chromium.org32912102009-01-16 10:38:43 +000015652 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015653 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000015654
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015655 return obj;
15656}
15657
15658
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015659bool ObjectHashSet::Contains(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015660 ASSERT(IsKey(key));
15661
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015662 // If the object does not have an identity hash, it was never used as a key.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015663 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
15664 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
15665 }
15666 return (FindEntry(key) != kNotFound);
15667}
15668
15669
15670MaybeObject* ObjectHashSet::Add(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015671 ASSERT(IsKey(key));
15672
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015673 // Make sure the key object has an identity hash code.
15674 int hash;
15675 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
15676 if (maybe_hash->IsFailure()) return maybe_hash;
rossberg@chromium.org92597162013-08-23 13:28:00 +000015677 ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015678 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
15679 }
15680 int entry = FindEntry(key);
15681
15682 // Check whether key is already present.
15683 if (entry != kNotFound) return this;
15684
15685 // Check whether the hash set should be extended and add entry.
15686 Object* obj;
15687 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15688 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15689 }
15690 ObjectHashSet* table = ObjectHashSet::cast(obj);
15691 entry = table->FindInsertionEntry(hash);
15692 table->set(EntryToIndex(entry), key);
15693 table->ElementAdded();
15694 return table;
15695}
15696
15697
15698MaybeObject* ObjectHashSet::Remove(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015699 ASSERT(IsKey(key));
15700
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015701 // If the object does not have an identity hash, it was never used as a key.
15702 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
15703 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
15704 }
15705 int entry = FindEntry(key);
15706
15707 // Check whether key is actually present.
15708 if (entry == kNotFound) return this;
15709
15710 // Remove entry and try to shrink this hash set.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015711 set_the_hole(EntryToIndex(entry));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015712 ElementRemoved();
15713 return Shrink(key);
15714}
15715
15716
15717Object* ObjectHashTable::Lookup(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015718 ASSERT(IsKey(key));
15719
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015720 // If the object does not have an identity hash, it was never used as a key.
15721 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
15722 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000015723 return GetHeap()->the_hole_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015724 }
15725 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015726 int entry = FindEntry(key);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000015727 if (entry == kNotFound) return GetHeap()->the_hole_value();
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015728 return get(EntryToIndex(entry) + 1);
15729}
15730
15731
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015732MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015733 ASSERT(IsKey(key));
15734
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015735 // Make sure the key object has an identity hash code.
15736 int hash;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015737 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015738 if (maybe_hash->IsFailure()) return maybe_hash;
rossberg@chromium.org92597162013-08-23 13:28:00 +000015739 ASSERT(key->GetHash(OMIT_CREATION) == maybe_hash);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015740 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
15741 }
15742 int entry = FindEntry(key);
15743
15744 // Check whether to perform removal operation.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000015745 if (value->IsTheHole()) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015746 if (entry == kNotFound) return this;
15747 RemoveEntry(entry);
15748 return Shrink(key);
15749 }
15750
15751 // Key is already in table, just overwrite value.
15752 if (entry != kNotFound) {
15753 set(EntryToIndex(entry) + 1, value);
15754 return this;
15755 }
15756
15757 // Check whether the hash table should be extended.
15758 Object* obj;
15759 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
15760 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15761 }
15762 ObjectHashTable* table = ObjectHashTable::cast(obj);
15763 table->AddEntry(table->FindInsertionEntry(hash), key, value);
15764 return table;
15765}
15766
15767
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000015768void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015769 set(EntryToIndex(entry), key);
15770 set(EntryToIndex(entry) + 1, value);
15771 ElementAdded();
15772}
15773
15774
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000015775void ObjectHashTable::RemoveEntry(int entry) {
15776 set_the_hole(EntryToIndex(entry));
15777 set_the_hole(EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000015778 ElementRemoved();
15779}
15780
15781
jkummerow@chromium.org25b0e212013-10-04 15:38:52 +000015782Object* WeakHashTable::Lookup(Object* key) {
15783 ASSERT(IsKey(key));
15784 int entry = FindEntry(key);
15785 if (entry == kNotFound) return GetHeap()->the_hole_value();
15786 return get(EntryToValueIndex(entry));
15787}
15788
15789
15790MaybeObject* WeakHashTable::Put(Object* key, Object* value) {
15791 ASSERT(IsKey(key));
15792 int entry = FindEntry(key);
15793 // Key is already in table, just overwrite value.
15794 if (entry != kNotFound) {
15795 set(EntryToValueIndex(entry), value);
15796 return this;
15797 }
15798
15799 // Check whether the hash table should be extended.
15800 Object* obj;
15801 { MaybeObject* maybe_obj = EnsureCapacity(1, key, TENURED);
15802 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
15803 }
15804 WeakHashTable* table = WeakHashTable::cast(obj);
15805 table->AddEntry(table->FindInsertionEntry(Hash(key)), key, value);
15806 return table;
15807}
15808
15809
15810void WeakHashTable::AddEntry(int entry, Object* key, Object* value) {
15811 set(EntryToIndex(entry), key);
15812 set(EntryToValueIndex(entry), value);
15813 ElementAdded();
15814}
15815
15816
ulan@chromium.org750145a2013-03-07 15:14:13 +000015817DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
15818 DeclaredAccessorDescriptor* descriptor)
15819 : array_(descriptor->serialized_data()->GetDataStartAddress()),
15820 length_(descriptor->serialized_data()->length()),
15821 offset_(0) {
15822}
15823
15824
15825const DeclaredAccessorDescriptorData*
15826 DeclaredAccessorDescriptorIterator::Next() {
15827 ASSERT(offset_ < length_);
15828 uint8_t* ptr = &array_[offset_];
15829 ASSERT(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
15830 const DeclaredAccessorDescriptorData* data =
15831 reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
15832 offset_ += sizeof(*data);
15833 ASSERT(offset_ <= length_);
15834 return data;
15835}
15836
15837
15838Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
15839 Isolate* isolate,
15840 const DeclaredAccessorDescriptorData& descriptor,
15841 Handle<DeclaredAccessorDescriptor> previous) {
15842 int previous_length =
15843 previous.is_null() ? 0 : previous->serialized_data()->length();
15844 int length = sizeof(descriptor) + previous_length;
15845 Handle<ByteArray> serialized_descriptor =
15846 isolate->factory()->NewByteArray(length);
15847 Handle<DeclaredAccessorDescriptor> value =
15848 isolate->factory()->NewDeclaredAccessorDescriptor();
15849 value->set_serialized_data(*serialized_descriptor);
15850 // Copy in the data.
15851 {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000015852 DisallowHeapAllocation no_allocation;
ulan@chromium.org750145a2013-03-07 15:14:13 +000015853 uint8_t* array = serialized_descriptor->GetDataStartAddress();
15854 if (previous_length != 0) {
15855 uint8_t* previous_array =
15856 previous->serialized_data()->GetDataStartAddress();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000015857 OS::MemCopy(array, previous_array, previous_length);
ulan@chromium.org750145a2013-03-07 15:14:13 +000015858 array += previous_length;
15859 }
15860 ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
15861 DeclaredAccessorDescriptorData* data =
15862 reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
15863 *data = descriptor;
15864 }
15865 return value;
15866}
15867
15868
ager@chromium.org65dad4b2009-04-23 08:48:43 +000015869#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015870// Check if there is a break point at this code position.
15871bool DebugInfo::HasBreakPoint(int code_position) {
15872 // Get the break point info object for this code position.
15873 Object* break_point_info = GetBreakPointInfo(code_position);
15874
15875 // If there is no break point info object or no break points in the break
15876 // point info object there is no break point at this code position.
15877 if (break_point_info->IsUndefined()) return false;
15878 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
15879}
15880
15881
15882// Get the break point info object for this code position.
15883Object* DebugInfo::GetBreakPointInfo(int code_position) {
15884 // Find the index of the break point info object for this code position.
15885 int index = GetBreakPointInfoIndex(code_position);
15886
15887 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015888 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015889 return BreakPointInfo::cast(break_points()->get(index));
15890}
15891
15892
15893// Clear a break point at the specified code position.
15894void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
15895 int code_position,
15896 Handle<Object> break_point_object) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000015897 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000015898 debug_info->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015899 if (break_point_info->IsUndefined()) return;
15900 BreakPointInfo::ClearBreakPoint(
15901 Handle<BreakPointInfo>::cast(break_point_info),
15902 break_point_object);
15903}
15904
15905
15906void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
15907 int code_position,
15908 int source_position,
15909 int statement_position,
15910 Handle<Object> break_point_object) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000015911 Isolate* isolate = debug_info->GetIsolate();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000015912 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
15913 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015914 if (!break_point_info->IsUndefined()) {
15915 BreakPointInfo::SetBreakPoint(
15916 Handle<BreakPointInfo>::cast(break_point_info),
15917 break_point_object);
15918 return;
15919 }
15920
15921 // Adding a new break point for a code position which did not have any
15922 // break points before. Try to find a free slot.
15923 int index = kNoBreakPointInfo;
15924 for (int i = 0; i < debug_info->break_points()->length(); i++) {
15925 if (debug_info->break_points()->get(i)->IsUndefined()) {
15926 index = i;
15927 break;
15928 }
15929 }
15930 if (index == kNoBreakPointInfo) {
15931 // No free slot - extend break point info array.
15932 Handle<FixedArray> old_break_points =
15933 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015934 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015935 isolate->factory()->NewFixedArray(
15936 old_break_points->length() +
15937 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000015938
15939 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015940 for (int i = 0; i < old_break_points->length(); i++) {
15941 new_break_points->set(i, old_break_points->get(i));
15942 }
15943 index = old_break_points->length();
15944 }
15945 ASSERT(index != kNoBreakPointInfo);
15946
15947 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015948 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
15949 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015950 new_break_point_info->set_code_position(Smi::FromInt(code_position));
15951 new_break_point_info->set_source_position(Smi::FromInt(source_position));
15952 new_break_point_info->
15953 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015954 new_break_point_info->set_break_point_objects(
15955 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015956 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
15957 debug_info->break_points()->set(index, *new_break_point_info);
15958}
15959
15960
15961// Get the break point objects for a code position.
15962Object* DebugInfo::GetBreakPointObjects(int code_position) {
15963 Object* break_point_info = GetBreakPointInfo(code_position);
15964 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015965 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015966 }
15967 return BreakPointInfo::cast(break_point_info)->break_point_objects();
15968}
15969
15970
15971// Get the total number of break points.
15972int DebugInfo::GetBreakPointCount() {
15973 if (break_points()->IsUndefined()) return 0;
15974 int count = 0;
15975 for (int i = 0; i < break_points()->length(); i++) {
15976 if (!break_points()->get(i)->IsUndefined()) {
15977 BreakPointInfo* break_point_info =
15978 BreakPointInfo::cast(break_points()->get(i));
15979 count += break_point_info->GetBreakPointCount();
15980 }
15981 }
15982 return count;
15983}
15984
15985
15986Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
15987 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015988 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015989 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015990 for (int i = 0; i < debug_info->break_points()->length(); i++) {
15991 if (!debug_info->break_points()->get(i)->IsUndefined()) {
15992 Handle<BreakPointInfo> break_point_info =
15993 Handle<BreakPointInfo>(BreakPointInfo::cast(
15994 debug_info->break_points()->get(i)));
15995 if (BreakPointInfo::HasBreakPointObject(break_point_info,
15996 break_point_object)) {
15997 return *break_point_info;
15998 }
15999 }
16000 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016001 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016002}
16003
16004
16005// Find the index of the break point info object for the specified code
16006// position.
16007int DebugInfo::GetBreakPointInfoIndex(int code_position) {
16008 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
16009 for (int i = 0; i < break_points()->length(); i++) {
16010 if (!break_points()->get(i)->IsUndefined()) {
16011 BreakPointInfo* break_point_info =
16012 BreakPointInfo::cast(break_points()->get(i));
16013 if (break_point_info->code_position()->value() == code_position) {
16014 return i;
16015 }
16016 }
16017 }
16018 return kNoBreakPointInfo;
16019}
16020
16021
16022// Remove the specified break point object.
16023void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
16024 Handle<Object> break_point_object) {
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +000016025 Isolate* isolate = break_point_info->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016026 // If there are no break points just ignore.
16027 if (break_point_info->break_point_objects()->IsUndefined()) return;
16028 // If there is a single break point clear it if it is the same.
16029 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16030 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016031 break_point_info->set_break_point_objects(
16032 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016033 }
16034 return;
16035 }
16036 // If there are multiple break points shrink the array
16037 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
16038 Handle<FixedArray> old_array =
16039 Handle<FixedArray>(
16040 FixedArray::cast(break_point_info->break_point_objects()));
16041 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000016042 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016043 int found_count = 0;
16044 for (int i = 0; i < old_array->length(); i++) {
16045 if (old_array->get(i) == *break_point_object) {
16046 ASSERT(found_count == 0);
16047 found_count++;
16048 } else {
16049 new_array->set(i - found_count, old_array->get(i));
16050 }
16051 }
16052 // If the break point was found in the list change it.
16053 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
16054}
16055
16056
16057// Add the specified break point object.
16058void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
16059 Handle<Object> break_point_object) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000016060 Isolate* isolate = break_point_info->GetIsolate();
16061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016062 // If there was no break point objects before just set it.
16063 if (break_point_info->break_point_objects()->IsUndefined()) {
16064 break_point_info->set_break_point_objects(*break_point_object);
16065 return;
16066 }
16067 // If the break point object is the same as before just ignore.
16068 if (break_point_info->break_point_objects() == *break_point_object) return;
16069 // If there was one break point object before replace with array.
16070 if (!break_point_info->break_point_objects()->IsFixedArray()) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000016071 Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016072 array->set(0, break_point_info->break_point_objects());
16073 array->set(1, *break_point_object);
16074 break_point_info->set_break_point_objects(*array);
16075 return;
16076 }
16077 // If there was more than one break point before extend array.
16078 Handle<FixedArray> old_array =
16079 Handle<FixedArray>(
16080 FixedArray::cast(break_point_info->break_point_objects()));
16081 Handle<FixedArray> new_array =
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +000016082 isolate->factory()->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016083 for (int i = 0; i < old_array->length(); i++) {
16084 // If the break point was there before just ignore.
16085 if (old_array->get(i) == *break_point_object) return;
16086 new_array->set(i, old_array->get(i));
16087 }
16088 // Add the new break point.
16089 new_array->set(old_array->length(), *break_point_object);
16090 break_point_info->set_break_point_objects(*new_array);
16091}
16092
16093
16094bool BreakPointInfo::HasBreakPointObject(
16095 Handle<BreakPointInfo> break_point_info,
16096 Handle<Object> break_point_object) {
16097 // No break point.
16098 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000016099 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016100 if (!break_point_info->break_point_objects()->IsFixedArray()) {
16101 return break_point_info->break_point_objects() == *break_point_object;
16102 }
16103 // Multiple break points.
16104 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
16105 for (int i = 0; i < array->length(); i++) {
16106 if (array->get(i) == *break_point_object) {
16107 return true;
16108 }
16109 }
16110 return false;
16111}
16112
16113
16114// Get the number of break points.
16115int BreakPointInfo::GetBreakPointCount() {
16116 // No break point.
16117 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000016118 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016119 if (!break_point_objects()->IsFixedArray()) return 1;
16120 // Multiple break points.
16121 return FixedArray::cast(break_point_objects())->length();
16122}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000016123#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016124
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000016125
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000016126Object* JSDate::GetField(Object* object, Smi* index) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000016127 return JSDate::cast(object)->DoGetField(
16128 static_cast<FieldIndex>(index->value()));
16129}
16130
16131
16132Object* JSDate::DoGetField(FieldIndex index) {
16133 ASSERT(index != kDateValue);
16134
16135 DateCache* date_cache = GetIsolate()->date_cache();
16136
16137 if (index < kFirstUncachedField) {
16138 Object* stamp = cache_stamp();
16139 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
16140 // Since the stamp is not NaN, the value is also not NaN.
16141 int64_t local_time_ms =
16142 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
16143 SetLocalFields(local_time_ms, date_cache);
16144 }
16145 switch (index) {
16146 case kYear: return year();
16147 case kMonth: return month();
16148 case kDay: return day();
16149 case kWeekday: return weekday();
16150 case kHour: return hour();
16151 case kMinute: return min();
16152 case kSecond: return sec();
16153 default: UNREACHABLE();
16154 }
16155 }
16156
16157 if (index >= kFirstUTCField) {
16158 return GetUTCField(index, value()->Number(), date_cache);
16159 }
16160
16161 double time = value()->Number();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000016162 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000016163
16164 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
16165 int days = DateCache::DaysFromTime(local_time_ms);
16166
16167 if (index == kDays) return Smi::FromInt(days);
16168
16169 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16170 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
16171 ASSERT(index == kTimeInDay);
16172 return Smi::FromInt(time_in_day_ms);
16173}
16174
16175
16176Object* JSDate::GetUTCField(FieldIndex index,
16177 double value,
16178 DateCache* date_cache) {
16179 ASSERT(index >= kFirstUTCField);
16180
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000016181 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000016182
16183 int64_t time_ms = static_cast<int64_t>(value);
16184
16185 if (index == kTimezoneOffset) {
16186 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
16187 }
16188
16189 int days = DateCache::DaysFromTime(time_ms);
16190
16191 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
16192
16193 if (index <= kDayUTC) {
16194 int year, month, day;
16195 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16196 if (index == kYearUTC) return Smi::FromInt(year);
16197 if (index == kMonthUTC) return Smi::FromInt(month);
16198 ASSERT(index == kDayUTC);
16199 return Smi::FromInt(day);
16200 }
16201
16202 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
16203 switch (index) {
16204 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
16205 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
16206 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
16207 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
16208 case kDaysUTC: return Smi::FromInt(days);
16209 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
16210 default: UNREACHABLE();
16211 }
16212
16213 UNREACHABLE();
16214 return NULL;
16215}
16216
16217
16218void JSDate::SetValue(Object* value, bool is_value_nan) {
16219 set_value(value);
16220 if (is_value_nan) {
16221 HeapNumber* nan = GetIsolate()->heap()->nan_value();
16222 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
16223 set_year(nan, SKIP_WRITE_BARRIER);
16224 set_month(nan, SKIP_WRITE_BARRIER);
16225 set_day(nan, SKIP_WRITE_BARRIER);
16226 set_hour(nan, SKIP_WRITE_BARRIER);
16227 set_min(nan, SKIP_WRITE_BARRIER);
16228 set_sec(nan, SKIP_WRITE_BARRIER);
16229 set_weekday(nan, SKIP_WRITE_BARRIER);
16230 } else {
16231 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
16232 }
16233}
16234
16235
16236void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
16237 int days = DateCache::DaysFromTime(local_time_ms);
16238 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
16239 int year, month, day;
16240 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
16241 int weekday = date_cache->Weekday(days);
16242 int hour = time_in_day_ms / (60 * 60 * 1000);
16243 int min = (time_in_day_ms / (60 * 1000)) % 60;
16244 int sec = (time_in_day_ms / 1000) % 60;
16245 set_cache_stamp(date_cache->stamp());
16246 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
16247 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
16248 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
16249 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
16250 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
16251 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
16252 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
16253}
16254
danno@chromium.org1fd77d52013-06-07 16:01:45 +000016255
16256void JSArrayBuffer::Neuter() {
16257 ASSERT(is_external());
16258 set_backing_store(NULL);
16259 set_byte_length(Smi::FromInt(0));
16260}
16261
16262
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000016263void JSArrayBufferView::NeuterView() {
danno@chromium.org1fd77d52013-06-07 16:01:45 +000016264 set_byte_offset(Smi::FromInt(0));
16265 set_byte_length(Smi::FromInt(0));
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000016266}
16267
16268
16269void JSDataView::Neuter() {
16270 NeuterView();
16271}
16272
16273
16274void JSTypedArray::Neuter() {
16275 NeuterView();
danno@chromium.org1fd77d52013-06-07 16:01:45 +000016276 set_length(Smi::FromInt(0));
16277 set_elements(GetHeap()->EmptyExternalArrayForMap(map()));
16278}
16279
danno@chromium.org41728482013-06-12 22:31:22 +000016280
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000016281Type* PropertyCell::type() {
danno@chromium.org41728482013-06-12 22:31:22 +000016282 return static_cast<Type*>(type_raw());
16283}
16284
16285
dslomov@chromium.orgb752d402013-06-18 11:54:54 +000016286void PropertyCell::set_type(Type* type, WriteBarrierMode ignored) {
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016287 ASSERT(IsPropertyCell());
danno@chromium.org41728482013-06-12 22:31:22 +000016288 set_type_raw(type, ignored);
16289}
16290
16291
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016292Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
16293 Handle<Object> value) {
16294 Isolate* isolate = cell->GetIsolate();
16295 Handle<Type> old_type(cell->type(), isolate);
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +000016296 // TODO(2803): Do not track ConsString as constant because they cannot be
16297 // embedded into code.
yangguo@chromium.orgc73d55b2013-07-24 08:18:28 +000016298 Handle<Type> new_type(value->IsConsString() || value->IsTheHole()
16299 ? Type::Any()
16300 : Type::Constant(value, isolate), isolate);
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016301
16302 if (new_type->Is(old_type)) {
16303 return *old_type;
16304 }
16305
16306 cell->dependent_code()->DeoptimizeDependentCodeGroup(
16307 isolate, DependentCode::kPropertyCellChangedGroup);
16308
16309 if (old_type->Is(Type::None()) || old_type->Is(Type::Undefined())) {
16310 return *new_type;
16311 }
16312
16313 return Type::Any();
16314}
16315
16316
machenbach@chromium.org528ce022013-09-23 14:09:36 +000016317void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
16318 Handle<Object> value,
16319 WriteBarrierMode mode) {
16320 CALL_HEAP_FUNCTION_VOID(cell->GetIsolate(),
16321 cell->SetValueInferType(*value, mode));
16322}
16323
16324
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016325MaybeObject* PropertyCell::SetValueInferType(Object* value,
16326 WriteBarrierMode ignored) {
16327 set_value(value, ignored);
16328 if (!Type::Any()->Is(type())) {
16329 IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
16330 MaybeObject* maybe_type = trampoline.CallWithReturnValue(
16331 &PropertyCell::UpdateType,
16332 Handle<PropertyCell>(this),
16333 Handle<Object>(value, GetIsolate()));
danno@chromium.orgbee51992013-07-10 14:57:15 +000016334 Type* new_type = NULL;
16335 if (!maybe_type->To(&new_type)) return maybe_type;
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +000016336 set_type(new_type);
16337 }
16338 return value;
16339}
16340
16341
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000016342void PropertyCell::AddDependentCompilationInfo(CompilationInfo* info) {
16343 Handle<DependentCode> dep(dependent_code());
16344 Handle<DependentCode> codes =
16345 DependentCode::Insert(dep, DependentCode::kPropertyCellChangedGroup,
16346 info->object_wrapper());
16347 if (*codes != dependent_code()) set_dependent_code(*codes);
16348 info->dependencies(DependentCode::kPropertyCellChangedGroup)->Add(
16349 Handle<HeapObject>(this), info->zone());
16350}
16351
16352
16353void PropertyCell::AddDependentCode(Handle<Code> code) {
16354 Handle<DependentCode> codes = DependentCode::Insert(
16355 Handle<DependentCode>(dependent_code()),
16356 DependentCode::kPropertyCellChangedGroup, code);
16357 if (*codes != dependent_code()) set_dependent_code(*codes);
16358}
16359
16360
danno@chromium.org59400602013-08-13 17:09:37 +000016361const char* GetBailoutReason(BailoutReason reason) {
16362 ASSERT(reason < kLastErrorMessage);
16363#define ERROR_MESSAGES_TEXTS(C, T) T,
16364 static const char* error_messages_[] = {
16365 ERROR_MESSAGES_LIST(ERROR_MESSAGES_TEXTS)
16366 };
16367#undef ERROR_MESSAGES_TEXTS
16368 return error_messages_[reason];
16369}
16370
16371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016372} } // namespace v8::internal