blob: d127d1bb8a095bd8d9c9ac6adbcf2572e30989fe [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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000031#include "api.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000032#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000033#include "bootstrapper.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000034#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "deoptimizer.h"
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000037#include "date.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000038#include "elements.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000040#include "full-codegen.h"
41#include "hydrogen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000043#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044#include "objects-visiting-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "macro-assembler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000046#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000047#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000049#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
mads.s.ager31e71382008-08-13 09:32:07 +000052#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000054#include "disassembler.h"
55#endif
56
kasperl@chromium.org71affb52009-05-26 05:44:31 +000057namespace v8 {
58namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000060
lrn@chromium.org303ada72010-10-27 09:33:13 +000061MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
62 Object* value) {
63 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000064 { MaybeObject* maybe_result =
65 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +000066 if (!maybe_result->ToObject(&result)) return maybe_result;
67 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068 JSValue::cast(result)->set_value(value);
69 return result;
70}
71
72
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000073MaybeObject* Object::ToObject(Context* native_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074 if (IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000075 return CreateJSValue(native_context->number_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000076 } else if (IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000077 return CreateJSValue(native_context->boolean_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 } else if (IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000079 return CreateJSValue(native_context->string_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000080 }
81 ASSERT(IsJSObject());
82 return this;
83}
84
85
lrn@chromium.org303ada72010-10-27 09:33:13 +000086MaybeObject* Object::ToObject() {
lrn@chromium.org34e60782011-09-15 07:25:40 +000087 if (IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000088 return this;
89 } else if (IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000090 Isolate* isolate = Isolate::Current();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000091 Context* native_context = isolate->context()->native_context();
92 return CreateJSValue(native_context->number_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093 } else if (IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000094 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000095 Context* native_context = isolate->context()->native_context();
96 return CreateJSValue(native_context->boolean_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 } else if (IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000098 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
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()) {
102 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
103 Context* native_context = isolate->context()->native_context();
104 return CreateJSValue(native_context->symbol_function(), this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000105 }
106
107 // Throw a type error.
108 return Failure::InternalError();
109}
110
111
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +0000112bool Object::BooleanValue() {
113 if (IsBoolean()) return IsTrue();
114 if (IsSmi()) return Smi::cast(this)->value() != 0;
115 if (IsUndefined() || IsNull()) return false;
116 if (IsUndetectableObject()) return false; // Undetectable object is false.
117 if (IsString()) return String::cast(this)->length() != 0;
118 if (IsHeapNumber()) return HeapNumber::cast(this)->HeapNumberBooleanValue();
119 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120}
121
122
ulan@chromium.org750145a2013-03-07 15:14:13 +0000123void Object::Lookup(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000124 Object* holder = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000125 if (IsJSReceiver()) {
126 holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000127 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000128 Context* native_context = result->isolate()->context()->native_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000129 if (IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000130 holder = native_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000131 } else if (IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000132 holder = native_context->string_function()->instance_prototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000133 } else if (IsSymbol()) {
134 holder = native_context->symbol_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000135 } else if (IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000136 holder = native_context->boolean_function()->instance_prototype();
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000137 } else {
138 Isolate::Current()->PushStackTraceAndDie(
139 0xDEAD0000, this, JSReceiver::cast(this)->map(), 0xDEAD0001);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000142 ASSERT(holder != NULL); // Cannot handle null or undefined.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000143 JSReceiver::cast(holder)->Lookup(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000144}
145
146
lrn@chromium.org303ada72010-10-27 09:33:13 +0000147MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000148 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000149 PropertyAttributes* attributes) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000150 LookupResult result(name->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000152 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000153 ASSERT(*attributes <= ABSENT);
154 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155}
156
157
ulan@chromium.org750145a2013-03-07 15:14:13 +0000158template<typename To>
159static inline To* CheckedCast(void *from) {
160 uintptr_t temp = reinterpret_cast<uintptr_t>(from);
161 ASSERT(temp % sizeof(To) == 0);
162 return reinterpret_cast<To*>(temp);
163}
164
165
166static MaybeObject* PerformCompare(const BitmaskCompareDescriptor& descriptor,
167 char* ptr,
168 Heap* heap) {
169 uint32_t bitmask = descriptor.bitmask;
170 uint32_t compare_value = descriptor.compare_value;
171 uint32_t value;
172 switch (descriptor.size) {
173 case 1:
174 value = static_cast<uint32_t>(*CheckedCast<uint8_t>(ptr));
175 compare_value &= 0xff;
176 bitmask &= 0xff;
177 break;
178 case 2:
179 value = static_cast<uint32_t>(*CheckedCast<uint16_t>(ptr));
180 compare_value &= 0xffff;
181 bitmask &= 0xffff;
182 break;
183 case 4:
184 value = *CheckedCast<uint32_t>(ptr);
185 break;
186 default:
187 UNREACHABLE();
188 return NULL;
189 }
190 return heap->ToBoolean((bitmask & value) == (bitmask & compare_value));
191}
192
193
194static MaybeObject* PerformCompare(const PointerCompareDescriptor& descriptor,
195 char* ptr,
196 Heap* heap) {
197 uintptr_t compare_value =
198 reinterpret_cast<uintptr_t>(descriptor.compare_value);
199 uintptr_t value = *CheckedCast<uintptr_t>(ptr);
200 return heap->ToBoolean(compare_value == value);
201}
202
203
204static MaybeObject* GetPrimitiveValue(
205 const PrimitiveValueDescriptor& descriptor,
206 char* ptr,
207 Heap* heap) {
208 int32_t int32_value = 0;
209 switch (descriptor.data_type) {
210 case kDescriptorInt8Type:
211 int32_value = *CheckedCast<int8_t>(ptr);
212 break;
213 case kDescriptorUint8Type:
214 int32_value = *CheckedCast<uint8_t>(ptr);
215 break;
216 case kDescriptorInt16Type:
217 int32_value = *CheckedCast<int16_t>(ptr);
218 break;
219 case kDescriptorUint16Type:
220 int32_value = *CheckedCast<uint16_t>(ptr);
221 break;
222 case kDescriptorInt32Type:
223 int32_value = *CheckedCast<int32_t>(ptr);
224 break;
225 case kDescriptorUint32Type: {
226 uint32_t value = *CheckedCast<uint32_t>(ptr);
227 return heap->NumberFromUint32(value);
228 }
229 case kDescriptorBoolType: {
230 uint8_t byte = *CheckedCast<uint8_t>(ptr);
231 return heap->ToBoolean(byte & (0x1 << descriptor.bool_offset));
232 }
233 case kDescriptorFloatType: {
234 float value = *CheckedCast<float>(ptr);
235 return heap->NumberFromDouble(value);
236 }
237 case kDescriptorDoubleType: {
238 double value = *CheckedCast<double>(ptr);
239 return heap->NumberFromDouble(value);
240 }
241 }
242 return heap->NumberFromInt32(int32_value);
243}
244
245
246static MaybeObject* GetDeclaredAccessorProperty(Object* receiver,
247 DeclaredAccessorInfo* info,
248 Isolate* isolate) {
249 char* current = reinterpret_cast<char*>(receiver);
250 DeclaredAccessorDescriptorIterator iterator(info->descriptor());
251 while (true) {
252 const DeclaredAccessorDescriptorData* data = iterator.Next();
253 switch (data->type) {
254 case kDescriptorReturnObject: {
255 ASSERT(iterator.Complete());
256 current = *CheckedCast<char*>(current);
257 return *CheckedCast<Object*>(current);
258 }
259 case kDescriptorPointerDereference:
260 ASSERT(!iterator.Complete());
261 current = *reinterpret_cast<char**>(current);
262 break;
263 case kDescriptorPointerShift:
264 ASSERT(!iterator.Complete());
265 current += data->pointer_shift_descriptor.byte_offset;
266 break;
267 case kDescriptorObjectDereference: {
268 ASSERT(!iterator.Complete());
269 Object* object = CheckedCast<Object>(current);
270 int field = data->object_dereference_descriptor.internal_field;
271 Object* smi = JSObject::cast(object)->GetInternalField(field);
272 ASSERT(smi->IsSmi());
273 current = reinterpret_cast<char*>(smi);
274 break;
275 }
276 case kDescriptorBitmaskCompare:
277 ASSERT(iterator.Complete());
278 return PerformCompare(data->bitmask_compare_descriptor,
279 current,
280 isolate->heap());
281 case kDescriptorPointerCompare:
282 ASSERT(iterator.Complete());
283 return PerformCompare(data->pointer_compare_descriptor,
284 current,
285 isolate->heap());
286 case kDescriptorPrimitiveValue:
287 ASSERT(iterator.Complete());
288 return GetPrimitiveValue(data->primitive_value_descriptor,
289 current,
290 isolate->heap());
291 }
292 }
293 UNREACHABLE();
294 return NULL;
295}
296
297
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000298MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
299 Object* structure,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000300 Name* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000301 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000303 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000304 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000305 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000306 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000307 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000308 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000309 MaybeObject* value = (callback->getter)(receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000311 return value;
312 }
313
314 // api style callbacks.
ulan@chromium.org750145a2013-03-07 15:14:13 +0000315 if (structure->IsAccessorInfo()) {
316 if (!AccessorInfo::cast(structure)->IsCompatibleReceiver(receiver)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000317 Handle<Object> name_handle(name, isolate);
318 Handle<Object> receiver_handle(receiver, isolate);
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000319 Handle<Object> args[2] = { name_handle, receiver_handle };
320 Handle<Object> error =
321 isolate->factory()->NewTypeError("incompatible_method_receiver",
322 HandleVector(args,
323 ARRAY_SIZE(args)));
324 return isolate->Throw(*error);
325 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000326 // TODO(rossberg): Handling symbols in the API requires changing the API,
327 // so we do not support it for now.
328 if (name->IsSymbol()) return isolate->heap()->undefined_value();
329 if (structure->IsDeclaredAccessorInfo()) {
330 return GetDeclaredAccessorProperty(receiver,
331 DeclaredAccessorInfo::cast(structure),
332 isolate);
333 }
334 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 Object* fun_obj = data->getter();
336 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000337 if (call_fun == NULL) return isolate->heap()->undefined_value();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000338 HandleScope scope(isolate);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000339 JSObject* self = JSObject::cast(receiver);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000340 Handle<String> key(String::cast(name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000342 CustomArguments args(isolate, data->data(), self, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000343 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344 v8::Handle<v8::Value> result;
345 {
346 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +0000347 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000348 result = call_fun(v8::Utils::ToLocal(key), info);
349 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
351 if (result.IsEmpty()) {
352 return isolate->heap()->undefined_value();
353 }
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000354 Object* return_value = *v8::Utils::OpenHandle(*result);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +0000355 return_value->VerifyApiCallResultType();
jkummerow@chromium.org67255be2012-09-05 16:44:50 +0000356 return return_value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357 }
358
359 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000360 if (structure->IsAccessorPair()) {
361 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000362 if (getter->IsSpecFunction()) {
363 // TODO(rossberg): nicer would be to cast to some JSCallable here...
364 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 }
366 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000367 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 }
369
370 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000371 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372}
373
374
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000375MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000376 Name* name_raw) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000377 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000378 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000379 Handle<Object> receiver(receiver_raw, isolate);
380 Handle<Object> name(name_raw, isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000381
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000382 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
383 if (name->IsSymbol()) return isolate->heap()->undefined_value();
384
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000385 Handle<Object> args[] = { receiver, name };
386 Handle<Object> result = CallTrap(
387 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000388 if (isolate->has_pending_exception()) return Failure::Exception();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000389
390 return *result;
391}
392
393
ulan@chromium.org750145a2013-03-07 15:14:13 +0000394Handle<Object> Object::GetProperty(Handle<Object> object, Handle<Name> name) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000395 // TODO(rossberg): The index test should not be here but in the GetProperty
396 // method (or somewhere else entirely). Needs more global clean-up.
397 uint32_t index;
ulan@chromium.org750145a2013-03-07 15:14:13 +0000398 if (name->AsArrayIndex(&index))
399 return GetElement(object, index);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000400 Isolate* isolate = object->IsHeapObject()
401 ? Handle<HeapObject>::cast(object)->GetIsolate()
402 : Isolate::Current();
403 CALL_HEAP_FUNCTION(isolate, object->GetProperty(*name), Object);
404}
405
406
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000407Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
408 Isolate* isolate = object->IsHeapObject()
409 ? Handle<HeapObject>::cast(object)->GetIsolate()
410 : Isolate::Current();
411 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
412}
413
414
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000415MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
416 uint32_t index) {
417 String* name;
418 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
419 if (!maybe->To<String>(&name)) return maybe;
420 return GetPropertyWithHandler(receiver, name);
421}
422
423
verwaest@chromium.org37141392012-05-31 13:27:02 +0000424MaybeObject* JSProxy::SetElementWithHandler(JSReceiver* receiver,
425 uint32_t index,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000426 Object* value,
427 StrictModeFlag strict_mode) {
428 String* name;
429 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
430 if (!maybe->To<String>(&name)) return maybe;
verwaest@chromium.org37141392012-05-31 13:27:02 +0000431 return SetPropertyWithHandler(receiver, name, value, NONE, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000432}
433
434
435bool JSProxy::HasElementWithHandler(uint32_t index) {
436 String* name;
437 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
438 if (!maybe->To<String>(&name)) return maybe;
439 return HasPropertyWithHandler(name);
440}
441
442
lrn@chromium.org303ada72010-10-27 09:33:13 +0000443MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000444 JSReceiver* getter) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000445 Isolate* isolate = getter->GetIsolate();
446 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000447 Handle<JSReceiver> fun(getter);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000448 Handle<Object> self(receiver, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000449#ifdef ENABLE_DEBUGGER_SUPPORT
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000450 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000451 // Handle stepping into a getter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000452 // TODO(rossberg): should this apply to getters that are function proxies?
453 if (debug->StepInActive() && fun->IsJSFunction()) {
454 debug->HandleStepIn(
455 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000456 }
457#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000458
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000459 bool has_pending_exception;
460 Handle<Object> result =
rossberg@chromium.org2c067b12012-03-19 11:01:52 +0000461 Execution::Call(fun, self, 0, NULL, &has_pending_exception, true);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000462 // Check for pending exception and return the result.
463 if (has_pending_exception) return Failure::Exception();
464 return *result;
465}
466
467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468// Only deal with CALLBACKS and INTERCEPTOR
lrn@chromium.org303ada72010-10-27 09:33:13 +0000469MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000470 Object* receiver,
471 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000472 Name* name,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000473 PropertyAttributes* attributes) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000474 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000475 switch (result->type()) {
476 case CALLBACKS: {
477 // Only allow API accessors.
478 Object* obj = result->GetCallbackObject();
479 if (obj->IsAccessorInfo()) {
480 AccessorInfo* info = AccessorInfo::cast(obj);
481 if (info->all_can_read()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000482 *attributes = result->GetAttributes();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000483 return result->holder()->GetPropertyWithCallback(
484 receiver, result->GetCallbackObject(), name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000485 }
486 }
487 break;
488 }
489 case NORMAL:
490 case FIELD:
491 case CONSTANT_FUNCTION: {
492 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000493 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000494 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000495 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000496 return GetPropertyWithFailedAccessCheck(receiver,
497 &r,
498 name,
499 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500 }
501 break;
502 }
503 case INTERCEPTOR: {
504 // If the object has an interceptor, try real named properties.
505 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000506 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000507 result->holder()->LookupRealNamedProperty(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000508 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000509 return GetPropertyWithFailedAccessCheck(receiver,
510 &r,
511 name,
512 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000513 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000514 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000516 default:
517 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 }
519 }
520
ager@chromium.org8bb60582008-12-11 12:02:20 +0000521 // No accessible property found.
522 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000523 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
525 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000526}
527
528
ager@chromium.org870a0b62008-11-04 11:43:05 +0000529PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
530 Object* receiver,
531 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000532 Name* name,
ager@chromium.org870a0b62008-11-04 11:43:05 +0000533 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000534 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000535 switch (result->type()) {
536 case CALLBACKS: {
537 // Only allow API accessors.
538 Object* obj = result->GetCallbackObject();
539 if (obj->IsAccessorInfo()) {
540 AccessorInfo* info = AccessorInfo::cast(obj);
541 if (info->all_can_read()) {
542 return result->GetAttributes();
543 }
544 }
545 break;
546 }
547
548 case NORMAL:
549 case FIELD:
550 case CONSTANT_FUNCTION: {
551 if (!continue_search) break;
552 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000553 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000554 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000555 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000556 return GetPropertyAttributeWithFailedAccessCheck(receiver,
557 &r,
558 name,
559 continue_search);
560 }
561 break;
562 }
563
564 case INTERCEPTOR: {
565 // If the object has an interceptor, try real named properties.
566 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000567 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000568 if (continue_search) {
569 result->holder()->LookupRealNamedProperty(name, &r);
570 } else {
571 result->holder()->LocalLookupRealNamedProperty(name, &r);
572 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000573 if (!r.IsFound()) break;
574 return GetPropertyAttributeWithFailedAccessCheck(receiver,
575 &r,
576 name,
577 continue_search);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000578 }
579
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000580 case HANDLER:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000581 case TRANSITION:
yangguo@chromium.orgde0db002012-06-22 13:44:28 +0000582 case NONEXISTENT:
ager@chromium.org5c838252010-02-19 08:53:10 +0000583 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000584 }
585 }
586
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000587 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000588 return ABSENT;
589}
590
591
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000592Object* JSObject::GetNormalizedProperty(LookupResult* result) {
593 ASSERT(!HasFastProperties());
594 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
595 if (IsGlobalObject()) {
596 value = JSGlobalPropertyCell::cast(value)->value();
597 }
598 ASSERT(!value->IsJSGlobalPropertyCell());
599 return value;
600}
601
602
603Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
604 ASSERT(!HasFastProperties());
605 if (IsGlobalObject()) {
606 JSGlobalPropertyCell* cell =
607 JSGlobalPropertyCell::cast(
608 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
609 cell->set_value(value);
610 } else {
611 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
612 }
613 return value;
614}
615
616
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000617Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000618 Handle<Name> key,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000619 Handle<Object> value,
620 PropertyDetails details) {
621 CALL_HEAP_FUNCTION(object->GetIsolate(),
622 object->SetNormalizedProperty(*key, *value, details),
623 Object);
624}
625
626
ulan@chromium.org750145a2013-03-07 15:14:13 +0000627MaybeObject* JSObject::SetNormalizedProperty(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000628 Object* value,
629 PropertyDetails details) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000630 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000631 int entry = property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000632 if (entry == NameDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000633 Object* store_value = value;
634 if (IsGlobalObject()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000635 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000636 MaybeObject* maybe_store_value =
637 heap->AllocateJSGlobalPropertyCell(value);
638 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000639 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000640 Object* dict;
641 { MaybeObject* maybe_dict =
642 property_dictionary()->Add(name, store_value, details);
643 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
644 }
ulan@chromium.org750145a2013-03-07 15:14:13 +0000645 set_properties(NameDictionary::cast(dict));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000646 return value;
647 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +0000648
649 PropertyDetails original_details = property_dictionary()->DetailsAt(entry);
650 int enumeration_index;
651 // Preserve the enumeration index unless the property was deleted.
652 if (original_details.IsDeleted()) {
653 enumeration_index = property_dictionary()->NextEnumerationIndex();
654 property_dictionary()->SetNextEnumerationIndex(enumeration_index + 1);
655 } else {
656 enumeration_index = original_details.dictionary_index();
657 ASSERT(enumeration_index > 0);
658 }
659
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000660 details = PropertyDetails(
661 details.attributes(), details.type(), enumeration_index);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000662
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000663 if (IsGlobalObject()) {
664 JSGlobalPropertyCell* cell =
665 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
666 cell->set_value(value);
667 // Please note we have to update the property details.
668 property_dictionary()->DetailsAtPut(entry, details);
669 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000670 property_dictionary()->SetEntry(entry, name, value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000671 }
672 return value;
673}
674
675
ulan@chromium.org750145a2013-03-07 15:14:13 +0000676MaybeObject* JSObject::DeleteNormalizedProperty(Name* name, DeleteMode mode) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000677 ASSERT(!HasFastProperties());
ulan@chromium.org750145a2013-03-07 15:14:13 +0000678 NameDictionary* dictionary = property_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000679 int entry = dictionary->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +0000680 if (entry != NameDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000681 // If we have a global object set the cell to the hole.
682 if (IsGlobalObject()) {
683 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000684 if (details.IsDontDelete()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000685 if (mode != FORCE_DELETION) return GetHeap()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000686 // When forced to delete global properties, we have to make a
687 // map change to invalidate any ICs that think they can load
688 // from the DontDelete cell without checking if it contains
689 // the hole value.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000690 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000691 MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
692 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
693
erik.corry@gmail.com88767242012-08-08 14:43:45 +0000694 ASSERT(new_map->is_dictionary_map());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +0000695 set_map(new_map);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000696 }
697 JSGlobalPropertyCell* cell =
698 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000699 cell->set_value(cell->GetHeap()->the_hole_value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000700 dictionary->DetailsAtPut(entry, details.AsDeleted());
701 } else {
ager@chromium.org04921a82011-06-27 13:21:41 +0000702 Object* deleted = dictionary->DeleteProperty(entry, mode);
703 if (deleted == GetHeap()->true_value()) {
704 FixedArray* new_properties = NULL;
705 MaybeObject* maybe_properties = dictionary->Shrink(name);
706 if (!maybe_properties->To(&new_properties)) {
707 return maybe_properties;
708 }
709 set_properties(new_properties);
710 }
711 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000712 }
713 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000714 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000715}
716
717
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000718bool JSObject::IsDirty() {
719 Object* cons_obj = map()->constructor();
720 if (!cons_obj->IsJSFunction())
721 return true;
722 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000723 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000724 return true;
725 // If the object is fully fast case and has the same map it was
726 // created with then no changes can have been made to it.
727 return map() != fun->initial_map()
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000728 || !HasFastObjectElements()
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000729 || !HasFastProperties();
730}
731
732
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000733Handle<Object> Object::GetProperty(Handle<Object> object,
734 Handle<Object> receiver,
735 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000736 Handle<Name> key,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000737 PropertyAttributes* attributes) {
738 Isolate* isolate = object->IsHeapObject()
739 ? Handle<HeapObject>::cast(object)->GetIsolate()
740 : Isolate::Current();
741 CALL_HEAP_FUNCTION(
742 isolate,
743 object->GetProperty(*receiver, result, *key, attributes),
744 Object);
745}
746
747
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000748MaybeObject* Object::GetPropertyOrFail(Handle<Object> object,
749 Handle<Object> receiver,
750 LookupResult* result,
751 Handle<Name> key,
752 PropertyAttributes* attributes) {
753 Isolate* isolate = object->IsHeapObject()
754 ? Handle<HeapObject>::cast(object)->GetIsolate()
755 : Isolate::Current();
756 CALL_HEAP_FUNCTION_PASS_EXCEPTION(
757 isolate,
758 object->GetProperty(*receiver, result, *key, attributes));
759}
760
761
lrn@chromium.org303ada72010-10-27 09:33:13 +0000762MaybeObject* Object::GetProperty(Object* receiver,
763 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +0000764 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000765 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 // Make sure that the top context does not change when doing
767 // callbacks or interceptor calls.
768 AssertNoContextChange ncc;
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000769 Isolate* isolate = name->GetIsolate();
770 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771
772 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000773 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774 // objects more than once in case of interceptors, because the
775 // holder will always be the interceptor holder and the search may
776 // only continue with a current object just after the interceptor
777 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000778 // Proxy handlers do not use the proxy's prototype, so we can skip this.
779 if (!result->IsHandler()) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000780 Object* last = result->IsProperty()
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000781 ? result->holder()
782 : Object::cast(heap->null_value());
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000783 ASSERT(this != this->GetPrototype(isolate));
784 for (Object* current = this;
785 true;
786 current = current->GetPrototype(isolate)) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000787 if (current->IsAccessCheckNeeded()) {
788 // Check if we're allowed to read from the current object. Note
789 // that even though we may not actually end up loading the named
790 // property from the current object, we still check that we have
791 // access to it.
792 JSObject* checked = JSObject::cast(current);
793 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
794 return checked->GetPropertyWithFailedAccessCheck(receiver,
795 result,
796 name,
797 attributes);
798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000800 // Stop traversing the chain once we reach the last object in the
801 // chain; either the holder of the result or null in case of an
802 // absent property.
803 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000804 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805 }
806
kasper.lund44510672008-07-25 07:37:58 +0000807 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000808 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000809 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000810 }
811 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 switch (result->type()) {
814 case NORMAL:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000815 value = result->holder()->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000816 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000817 return value->IsTheHole() ? heap->undefined_value() : value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000818 case FIELD: {
819 MaybeObject* maybe_result = result->holder()->FastPropertyAt(
820 result->representation(),
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +0000821 result->GetFieldIndex().field_index());
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000822 if (!maybe_result->To(&value)) return maybe_result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 return value->IsTheHole() ? heap->undefined_value() : value;
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000825 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 case CONSTANT_FUNCTION:
827 return result->GetConstantFunction();
828 case CALLBACKS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000829 return result->holder()->GetPropertyWithCallback(
830 receiver, result->GetCallbackObject(), name);
831 case HANDLER:
832 return result->proxy()->GetPropertyWithHandler(receiver, name);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000833 case INTERCEPTOR:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000834 return result->holder()->GetPropertyWithInterceptor(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +0000835 receiver, name, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +0000836 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +0000837 case NONEXISTENT:
838 UNREACHABLE();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000839 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000841 UNREACHABLE();
842 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843}
844
845
lrn@chromium.org303ada72010-10-27 09:33:13 +0000846MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000847 Isolate* isolate = IsSmi()
848 ? Isolate::Current()
849 : HeapObject::cast(this)->GetIsolate();
850 Heap* heap = isolate->heap();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000851 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000852
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000853 // Iterate up the prototype chain until an element is found or the null
854 // prototype is encountered.
855 for (holder = this;
856 holder != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000857 holder = holder->GetPrototype(isolate)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000858 if (!holder->IsJSObject()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000859 Context* native_context = isolate->context()->native_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000860 if (holder->IsNumber()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000861 holder = native_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000862 } else if (holder->IsString()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000863 holder = native_context->string_function()->instance_prototype();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000864 } else if (holder->IsSymbol()) {
865 holder = native_context->symbol_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000866 } else if (holder->IsBoolean()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000867 holder = native_context->boolean_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000868 } else if (holder->IsJSProxy()) {
869 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
870 } else {
871 // Undefined and null have no indexed properties.
872 ASSERT(holder->IsUndefined() || holder->IsNull());
873 return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000874 }
875 }
876
877 // Inline the case for JSObjects. Doing so significantly improves the
878 // performance of fetching elements where checking the prototype chain is
879 // necessary.
880 JSObject* js_object = JSObject::cast(holder);
881
882 // Check access rights if needed.
883 if (js_object->IsAccessCheckNeeded()) {
884 Isolate* isolate = heap->isolate();
885 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
886 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
887 return heap->undefined_value();
888 }
889 }
890
891 if (js_object->HasIndexedInterceptor()) {
892 return js_object->GetElementWithInterceptor(receiver, index);
893 }
894
895 if (js_object->elements() != heap->empty_fixed_array()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000896 MaybeObject* result = js_object->GetElementsAccessor()->Get(
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000897 receiver, js_object, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000898 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000899 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000900 }
901
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000902 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000903}
904
905
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000906Object* Object::GetPrototype(Isolate* isolate) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000907 if (IsSmi()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000908 Context* context = isolate->context()->native_context();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000909 return context->number_function()->instance_prototype();
910 }
911
912 HeapObject* heap_object = HeapObject::cast(this);
913
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000914 // The object is either a number, a string, a boolean,
915 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000916 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000917 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000918 }
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000919 Context* context = isolate->context()->native_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000921 if (heap_object->IsHeapNumber()) {
922 return context->number_function()->instance_prototype();
923 }
924 if (heap_object->IsString()) {
925 return context->string_function()->instance_prototype();
926 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000927 if (heap_object->IsSymbol()) {
928 return context->symbol_function()->instance_prototype();
929 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000930 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 return context->boolean_function()->instance_prototype();
932 } else {
hpayer@chromium.org8432c912013-02-28 15:55:26 +0000933 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 }
935}
936
937
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000938MaybeObject* Object::GetHash(CreationFlag flag) {
ulan@chromium.org750145a2013-03-07 15:14:13 +0000939 // The object is either a number, a name, an odd-ball,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000940 // a real JS object, or a Harmony proxy.
941 if (IsNumber()) {
942 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
943 return Smi::FromInt(hash & Smi::kMaxValue);
944 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000945 if (IsName()) {
946 uint32_t hash = Name::cast(this)->Hash();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000947 return Smi::FromInt(hash);
948 }
949 if (IsOddball()) {
950 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
951 return Smi::FromInt(hash);
952 }
953 if (IsJSReceiver()) {
954 return JSReceiver::cast(this)->GetIdentityHash(flag);
955 }
956
957 UNREACHABLE();
958 return Smi::FromInt(0);
959}
960
961
962bool Object::SameValue(Object* other) {
963 if (other == this) return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000964
ulan@chromium.org750145a2013-03-07 15:14:13 +0000965 // The object is either a number, a name, an odd-ball,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000966 // a real JS object, or a Harmony proxy.
967 if (IsNumber() && other->IsNumber()) {
968 double this_value = Number();
969 double other_value = other->Number();
970 return (this_value == other_value) ||
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000971 (std::isnan(this_value) && std::isnan(other_value));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000972 }
973 if (IsString() && other->IsString()) {
974 return String::cast(this)->Equals(String::cast(other));
975 }
976 return false;
977}
978
979
whesse@chromium.org023421e2010-12-21 12:19:12 +0000980void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000981 HeapStringAllocator allocator;
982 StringStream accumulator(&allocator);
983 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000984 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985}
986
987
988void Object::ShortPrint(StringStream* accumulator) {
989 if (IsSmi()) {
990 Smi::cast(this)->SmiPrint(accumulator);
991 } else if (IsFailure()) {
992 Failure::cast(this)->FailurePrint(accumulator);
993 } else {
994 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
995 }
996}
997
998
whesse@chromium.org023421e2010-12-21 12:19:12 +0000999void Smi::SmiPrint(FILE* out) {
1000 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001}
1002
1003
1004void Smi::SmiPrint(StringStream* accumulator) {
1005 accumulator->Add("%d", value());
1006}
1007
1008
1009void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001010 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011}
1012
1013
whesse@chromium.org023421e2010-12-21 12:19:12 +00001014void Failure::FailurePrint(FILE* out) {
1015 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001016}
1017
1018
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019// Should a word be prefixed by 'a' or 'an' in order to read naturally in
1020// English? Returns false for non-ASCII or words that don't start with
1021// a capital letter. The a/an rule follows pronunciation in English.
1022// We don't use the BBC's overcorrect "an historic occasion" though if
1023// you speak a dialect you may well say "an 'istoric occasion".
1024static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001025 if (str->length() == 0) return false; // A nothing.
1026 int c0 = str->Get(0);
1027 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028 if (c0 == 'U') {
1029 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001030 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001031 }
1032 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001033 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
1035 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
1036 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001037 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 }
1039 return false;
1040}
1041
1042
lrn@chromium.org303ada72010-10-27 09:33:13 +00001043MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001044#ifdef DEBUG
1045 // Do not attempt to flatten in debug mode when allocation is not
1046 // allowed. This is to avoid an assertion failure when allocating.
1047 // Flattening strings is the only case where we always allow
1048 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050#endif
1051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001053 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001054 case kConsStringTag: {
1055 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001056 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001057 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001058 }
1059 // There's little point in putting the flat string in new space if the
1060 // cons string is in old space. It can never get GCed until there is
1061 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001062 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001063 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001064 Object* object;
1065 String* result;
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001066 if (IsOneByteRepresentation()) {
1067 { MaybeObject* maybe_object =
1068 heap->AllocateRawOneByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001069 if (!maybe_object->ToObject(&object)) return maybe_object;
1070 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001071 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001073 int first_length = first->length();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001074 uint8_t* dest = SeqOneByteString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001075 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001076 String* second = cs->second();
1077 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001078 dest + first_length,
1079 0,
1080 len - first_length);
1081 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001082 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001084 if (!maybe_object->ToObject(&object)) return maybe_object;
1085 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001086 result = String::cast(object);
1087 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001088 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001089 int first_length = first->length();
1090 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001091 String* second = cs->second();
1092 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001093 dest + first_length,
1094 0,
1095 len - first_length);
1096 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 cs->set_first(result);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001098 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001099 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001100 }
1101 default:
1102 return this;
1103 }
1104}
1105
1106
ager@chromium.org6f10e412009-02-13 10:11:16 +00001107bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +00001108 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001109 // prohibited by the API.
1110 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001111#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +00001112 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001113 // Assert that the resource and the string are equivalent.
1114 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001115 ScopedVector<uc16> smart_chars(this->length());
1116 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1117 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001118 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001119 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001120 }
1121#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001123 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001124 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001125 return false;
1126 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001127 bool is_ascii = this->IsOneByteRepresentation();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001128 bool is_internalized = this->IsInternalizedString();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001129
1130 // Morph the object to an external string by adjusting the map and
1131 // reinitializing the fields.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001132 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001133 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001134 is_internalized
1135 ? (is_ascii
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001136 ? heap->external_internalized_string_with_one_byte_data_map()
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001137 : heap->external_internalized_string_map())
1138 : (is_ascii
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001139 ? heap->external_string_with_one_byte_data_map()
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001140 : heap->external_string_map()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001141 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001142 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001143 is_internalized
danno@chromium.orgca29dd82013-04-26 11:59:48 +00001144 ? (is_ascii
1145 ? heap->
1146 short_external_internalized_string_with_one_byte_data_map()
1147 : heap->short_external_internalized_string_map())
1148 : (is_ascii
1149 ? heap->short_external_string_with_one_byte_data_map()
1150 : heap->short_external_string_map()));
ager@chromium.org6f10e412009-02-13 10:11:16 +00001151 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001152 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
1153 self->set_resource(resource);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001154 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001155
1156 // Fill the remainder of the string with dead wood.
1157 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001158 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001159 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001160 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1161 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001162 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001163 return true;
1164}
1165
1166
1167bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
1168#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +00001169 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001170 // Assert that the resource and the string are equivalent.
1171 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001172 ScopedVector<char> smart_chars(this->length());
1173 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1174 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001175 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001176 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001177 }
1178#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001180 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001181 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001182 return false;
1183 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001184 bool is_internalized = this->IsInternalizedString();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001185
1186 // Morph the object to an external string by adjusting the map and
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001187 // reinitializing the fields. Use short version if space is limited.
1188 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001189 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001190 is_internalized ? heap->external_ascii_internalized_string_map()
1191 : heap->external_ascii_string_map());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001192 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001193 this->set_map_no_write_barrier(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001194 is_internalized ? heap->short_external_ascii_internalized_string_map()
1195 : heap->short_external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001196 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001197 ExternalAsciiString* self = ExternalAsciiString::cast(this);
1198 self->set_resource(resource);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001199 if (is_internalized) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001200
1201 // Fill the remainder of the string with dead wood.
1202 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001203 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001204 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001205 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1206 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001207 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001208 return true;
1209}
1210
1211
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001213 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001214 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 accumulator->Add("<Very long string[%u]>", len);
1216 return;
1217 }
1218
1219 if (!LooksValid()) {
1220 accumulator->Add("<Invalid String>");
1221 return;
1222 }
1223
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001224 ConsStringIteratorOp op;
1225 StringCharacterStream stream(this, &op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226
1227 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +00001228 if (len > kMaxShortPrintLength) {
1229 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 truncated = true;
1231 }
1232 bool ascii = true;
1233 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001234 uint16_t c = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235
1236 if (c < 32 || c >= 127) {
1237 ascii = false;
1238 }
1239 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001240 stream.Reset(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001242 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001243 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001244 accumulator->Put(static_cast<char>(stream.GetNext()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 }
1246 accumulator->Put('>');
1247 } else {
1248 // Backslash indicates that the string contains control
1249 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001250 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 for (int i = 0; i < len; i++) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001252 uint16_t c = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253 if (c == '\n') {
1254 accumulator->Add("\\n");
1255 } else if (c == '\r') {
1256 accumulator->Add("\\r");
1257 } else if (c == '\\') {
1258 accumulator->Add("\\\\");
1259 } else if (c < 32 || c > 126) {
1260 accumulator->Add("\\x%02x", c);
1261 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001262 accumulator->Put(static_cast<char>(c));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 }
1264 }
1265 if (truncated) {
1266 accumulator->Put('.');
1267 accumulator->Put('.');
1268 accumulator->Put('.');
1269 }
1270 accumulator->Put('>');
1271 }
1272 return;
1273}
1274
1275
1276void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1277 switch (map()->instance_type()) {
1278 case JS_ARRAY_TYPE: {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001279 double length = JSArray::cast(this)->length()->IsUndefined()
1280 ? 0
1281 : JSArray::cast(this)->length()->Number();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001282 accumulator->Add("<JS Array[%u]>", static_cast<uint32_t>(length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 break;
1284 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001285 case JS_WEAK_MAP_TYPE: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001286 accumulator->Add("<JS WeakMap>");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001287 break;
1288 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001289 case JS_REGEXP_TYPE: {
1290 accumulator->Add("<JS RegExp>");
1291 break;
1292 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 case JS_FUNCTION_TYPE: {
1294 Object* fun_name = JSFunction::cast(this)->shared()->name();
1295 bool printed = false;
1296 if (fun_name->IsString()) {
1297 String* str = String::cast(fun_name);
1298 if (str->length() > 0) {
1299 accumulator->Add("<JS Function ");
1300 accumulator->Put(str);
1301 accumulator->Put('>');
1302 printed = true;
1303 }
1304 }
1305 if (!printed) {
1306 accumulator->Add("<JS Function>");
1307 }
1308 break;
1309 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001310 case JS_GENERATOR_OBJECT_TYPE: {
1311 accumulator->Add("<JS Generator>");
1312 break;
1313 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001314 case JS_MODULE_TYPE: {
1315 accumulator->Add("<JS Module>");
1316 break;
1317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001319 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001321 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001323 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324 bool printed = false;
1325 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1328 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001329 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1333 } else {
1334 Object* constructor_name =
1335 JSFunction::cast(constructor)->shared()->name();
1336 if (constructor_name->IsString()) {
1337 String* str = String::cast(constructor_name);
1338 if (str->length() > 0) {
1339 bool vowel = AnWord(str);
1340 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001341 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001342 vowel ? "n" : "");
1343 accumulator->Put(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344 printed = true;
1345 }
1346 }
1347 }
1348 }
1349 if (!printed) {
1350 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1351 }
1352 }
1353 if (IsJSValue()) {
1354 accumulator->Add(" value = ");
1355 JSValue::cast(this)->value()->ShortPrint(accumulator);
1356 }
1357 accumulator->Put('>');
1358 break;
1359 }
1360 }
1361}
1362
1363
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001364void JSObject::PrintElementsTransition(
1365 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1366 ElementsKind to_kind, FixedArrayBase* to_elements) {
1367 if (from_kind != to_kind) {
1368 PrintF(file, "elements transition [");
1369 PrintElementsKind(file, from_kind);
1370 PrintF(file, " -> ");
1371 PrintElementsKind(file, to_kind);
1372 PrintF(file, "] in ");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001373 JavaScriptFrame::PrintTop(GetIsolate(), file, false, true);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001374 PrintF(file, " for ");
1375 ShortPrint(file);
1376 PrintF(file, " from ");
1377 from_elements->ShortPrint(file);
1378 PrintF(file, " to ");
1379 to_elements->ShortPrint(file);
1380 PrintF(file, "\n");
1381 }
1382}
1383
1384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001386 Heap* heap = GetHeap();
1387 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388 accumulator->Add("!!!INVALID POINTER!!!");
1389 return;
1390 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001391 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 accumulator->Add("!!!INVALID MAP!!!");
1393 return;
1394 }
1395
1396 accumulator->Add("%p ", this);
1397
1398 if (IsString()) {
1399 String::cast(this)->StringShortPrint(accumulator);
1400 return;
1401 }
1402 if (IsJSObject()) {
1403 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1404 return;
1405 }
1406 switch (map()->instance_type()) {
1407 case MAP_TYPE:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001408 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409 break;
1410 case FIXED_ARRAY_TYPE:
1411 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1412 break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001413 case FIXED_DOUBLE_ARRAY_TYPE:
1414 accumulator->Add("<FixedDoubleArray[%u]>",
1415 FixedDoubleArray::cast(this)->length());
1416 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 case BYTE_ARRAY_TYPE:
1418 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1419 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001420 case FREE_SPACE_TYPE:
1421 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1422 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001423 case EXTERNAL_PIXEL_ARRAY_TYPE:
1424 accumulator->Add("<ExternalPixelArray[%u]>",
1425 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001426 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001427 case EXTERNAL_BYTE_ARRAY_TYPE:
1428 accumulator->Add("<ExternalByteArray[%u]>",
1429 ExternalByteArray::cast(this)->length());
1430 break;
1431 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1432 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1433 ExternalUnsignedByteArray::cast(this)->length());
1434 break;
1435 case EXTERNAL_SHORT_ARRAY_TYPE:
1436 accumulator->Add("<ExternalShortArray[%u]>",
1437 ExternalShortArray::cast(this)->length());
1438 break;
1439 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1440 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1441 ExternalUnsignedShortArray::cast(this)->length());
1442 break;
1443 case EXTERNAL_INT_ARRAY_TYPE:
1444 accumulator->Add("<ExternalIntArray[%u]>",
1445 ExternalIntArray::cast(this)->length());
1446 break;
1447 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1448 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1449 ExternalUnsignedIntArray::cast(this)->length());
1450 break;
1451 case EXTERNAL_FLOAT_ARRAY_TYPE:
1452 accumulator->Add("<ExternalFloatArray[%u]>",
1453 ExternalFloatArray::cast(this)->length());
1454 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001455 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1456 accumulator->Add("<ExternalDoubleArray[%u]>",
1457 ExternalDoubleArray::cast(this)->length());
1458 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001459 case SHARED_FUNCTION_INFO_TYPE:
1460 accumulator->Add("<SharedFunctionInfo>");
1461 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001462 case JS_MESSAGE_OBJECT_TYPE:
1463 accumulator->Add("<JSMessageObject>");
1464 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465#define MAKE_STRUCT_CASE(NAME, Name, name) \
1466 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001467 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001469 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 break;
1471 STRUCT_LIST(MAKE_STRUCT_CASE)
1472#undef MAKE_STRUCT_CASE
1473 case CODE_TYPE:
1474 accumulator->Add("<Code>");
1475 break;
1476 case ODDBALL_TYPE: {
1477 if (IsUndefined())
1478 accumulator->Add("<undefined>");
1479 else if (IsTheHole())
1480 accumulator->Add("<the hole>");
1481 else if (IsNull())
1482 accumulator->Add("<null>");
1483 else if (IsTrue())
1484 accumulator->Add("<true>");
1485 else if (IsFalse())
1486 accumulator->Add("<false>");
1487 else
1488 accumulator->Add("<Odd Oddball>");
1489 break;
1490 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001491 case SYMBOL_TYPE: {
1492 Symbol* symbol = Symbol::cast(this);
1493 accumulator->Add("<Symbol: %d", symbol->Hash());
1494 if (!symbol->name()->IsUndefined()) {
1495 accumulator->Add(" ");
1496 String::cast(symbol->name())->StringShortPrint(accumulator);
1497 }
1498 accumulator->Add(">");
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001499 break;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001500 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001501 case HEAP_NUMBER_TYPE:
1502 accumulator->Add("<Number: ");
1503 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1504 accumulator->Put('>');
1505 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001506 case JS_PROXY_TYPE:
1507 accumulator->Add("<JSProxy>");
1508 break;
1509 case JS_FUNCTION_PROXY_TYPE:
1510 accumulator->Add("<JSFunctionProxy>");
1511 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001512 case FOREIGN_TYPE:
1513 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001515 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1516 accumulator->Add("Cell for ");
1517 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1518 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 default:
1520 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1521 break;
1522 }
1523}
1524
1525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001526void HeapObject::Iterate(ObjectVisitor* v) {
1527 // Handle header
1528 IteratePointer(v, kMapOffset);
1529 // Handle object body
1530 Map* m = map();
1531 IterateBody(m->instance_type(), SizeFromMap(m), v);
1532}
1533
1534
1535void HeapObject::IterateBody(InstanceType type, int object_size,
1536 ObjectVisitor* v) {
1537 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1538 // During GC, the map pointer field is encoded.
1539 if (type < FIRST_NONSTRING_TYPE) {
1540 switch (type & kStringRepresentationMask) {
1541 case kSeqStringTag:
1542 break;
1543 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001544 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 break;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001546 case kSlicedStringTag:
1547 SlicedString::BodyDescriptor::IterateBody(this, v);
1548 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001549 case kExternalStringTag:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001550 if ((type & kStringEncodingMask) == kOneByteStringTag) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001551 reinterpret_cast<ExternalAsciiString*>(this)->
1552 ExternalAsciiStringIterateBody(v);
1553 } else {
1554 reinterpret_cast<ExternalTwoByteString*>(this)->
1555 ExternalTwoByteStringIterateBody(v);
1556 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001557 break;
1558 }
1559 return;
1560 }
1561
1562 switch (type) {
1563 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001564 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001566 case FIXED_DOUBLE_ARRAY_TYPE:
1567 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001569 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001570 case JS_GENERATOR_OBJECT_TYPE:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00001571 case JS_MODULE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572 case JS_VALUE_TYPE:
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00001573 case JS_DATE_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 case JS_ARRAY_TYPE:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001575 case JS_ARRAY_BUFFER_TYPE:
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001576 case JS_TYPED_ARRAY_TYPE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001577 case JS_SET_TYPE:
1578 case JS_MAP_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001579 case JS_WEAK_MAP_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001580 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001581 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001584 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001585 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001587 case JS_FUNCTION_TYPE:
1588 reinterpret_cast<JSFunction*>(this)
1589 ->JSFunctionIterateBody(object_size, v);
1590 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001592 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001594 case JS_PROXY_TYPE:
1595 JSProxy::BodyDescriptor::IterateBody(this, v);
1596 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001597 case JS_FUNCTION_PROXY_TYPE:
1598 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1599 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001600 case FOREIGN_TYPE:
1601 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 break;
1603 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001604 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 break;
1606 case CODE_TYPE:
1607 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1608 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001609 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001610 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001611 break;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001612 case SYMBOL_TYPE:
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001613 Symbol::BodyDescriptor::IterateBody(this, v);
1614 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 case HEAP_NUMBER_TYPE:
1616 case FILLER_TYPE:
1617 case BYTE_ARRAY_TYPE:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001618 case FREE_SPACE_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001619 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001620 case EXTERNAL_BYTE_ARRAY_TYPE:
1621 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1622 case EXTERNAL_SHORT_ARRAY_TYPE:
1623 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1624 case EXTERNAL_INT_ARRAY_TYPE:
1625 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1626 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001627 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001629 case SHARED_FUNCTION_INFO_TYPE: {
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00001630 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 break;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001632 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001633
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634#define MAKE_STRUCT_CASE(NAME, Name, name) \
1635 case NAME##_TYPE:
1636 STRUCT_LIST(MAKE_STRUCT_CASE)
1637#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001638 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 break;
1640 default:
1641 PrintF("Unknown type: %d\n", type);
1642 UNREACHABLE();
1643 }
1644}
1645
1646
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001647bool HeapNumber::HeapNumberBooleanValue() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001649#if __BYTE_ORDER == __LITTLE_ENDIAN
1650 union IeeeDoubleLittleEndianArchType u;
1651#elif __BYTE_ORDER == __BIG_ENDIAN
1652 union IeeeDoubleBigEndianArchType u;
1653#endif
1654 u.d = value();
1655 if (u.bits.exp == 2047) {
1656 // Detect NaN for IEEE double precision floating point.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001657 if ((u.bits.man_low | u.bits.man_high) != 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001659 if (u.bits.exp == 0) {
1660 // Detect +0, and -0 for IEEE double precision floating point.
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001661 if ((u.bits.man_low | u.bits.man_high) == 0) return false;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001662 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00001663 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001664}
1665
1666
whesse@chromium.org023421e2010-12-21 12:19:12 +00001667void HeapNumber::HeapNumberPrint(FILE* out) {
1668 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669}
1670
1671
1672void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1673 // The Windows version of vsnprintf can allocate when printing a %g string
1674 // into a buffer that may not be big enough. We don't want random memory
1675 // allocation when producing post-crash stack traces, so we print into a
1676 // buffer that is plenty big enough for any floating point number, then
1677 // print that using vsnprintf (which may truncate but never allocate if
1678 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001679 EmbeddedVector<char, 100> buffer;
1680 OS::SNPrintF(buffer, "%.16g", Number());
1681 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682}
1683
1684
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001685String* JSReceiver::class_name() {
1686 if (IsJSFunction() && IsJSFunctionProxy()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001687 return GetHeap()->function_class_string();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001688 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689 if (map()->constructor()->IsJSFunction()) {
1690 JSFunction* constructor = JSFunction::cast(map()->constructor());
1691 return String::cast(constructor->shared()->instance_class_name());
1692 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001693 // If the constructor is not present, return "Object".
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001694 return GetHeap()->Object_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695}
1696
1697
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001698String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001699 if (map()->constructor()->IsJSFunction()) {
1700 JSFunction* constructor = JSFunction::cast(map()->constructor());
1701 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001702 if (name->length() > 0) return name;
1703 String* inferred_name = constructor->shared()->inferred_name();
1704 if (inferred_name->length() > 0) return inferred_name;
1705 Object* proto = GetPrototype();
1706 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001707 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001708 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001709 // If the constructor is not present, return "Object".
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001710 return GetHeap()->Object_string();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001711}
1712
1713
lrn@chromium.org303ada72010-10-27 09:33:13 +00001714MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001715 Name* name,
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001716 Object* value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001717 int field_index,
1718 Representation representation) {
1719 // This method is used to transition to a field. If we are transitioning to a
1720 // double field, allocate new storage.
1721 Object* storage;
1722 MaybeObject* maybe_storage =
1723 value->AllocateNewStorageFor(GetHeap(), representation);
1724 if (!maybe_storage->To(&storage)) return maybe_storage;
1725
ager@chromium.org7c537e22008-10-16 08:43:32 +00001726 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 int new_unused = new_map->unused_property_fields();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001728 FixedArray* values;
danno@chromium.orgf005df62013-04-30 16:36:45 +00001729 MaybeObject* maybe_values =
1730 properties()->CopySize(properties()->length() + new_unused + 1);
1731 if (!maybe_values->To(&values)) return maybe_values;
1732
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001733 set_properties(values);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001734 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001735
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001736 set_map(new_map);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001737
1738 FastPropertyAtPut(field_index, storage);
1739 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740}
1741
1742
ulan@chromium.org750145a2013-03-07 15:14:13 +00001743static bool IsIdentifier(UnicodeCache* cache, Name* name) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001744 // Checks whether the buffer contains an identifier (no escape).
ulan@chromium.org750145a2013-03-07 15:14:13 +00001745 if (!name->IsString()) return false;
1746 String* string = String::cast(name);
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001747 if (string->length() == 0) return false;
1748 ConsStringIteratorOp op;
1749 StringCharacterStream stream(string, &op);
1750 if (!cache->IsIdentifierStart(stream.GetNext())) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001751 return false;
1752 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00001753 while (stream.HasMore()) {
1754 if (!cache->IsIdentifierPart(stream.GetNext())) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001755 return false;
1756 }
1757 }
1758 return true;
1759}
1760
1761
ulan@chromium.org750145a2013-03-07 15:14:13 +00001762MaybeObject* JSObject::AddFastProperty(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001763 Object* value,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001764 PropertyAttributes attributes,
1765 StoreFromKeyed store_mode) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001766 ASSERT(!IsJSGlobalProxy());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00001767 ASSERT(DescriptorArray::kNotFound ==
1768 map()->instance_descriptors()->Search(
1769 name, map()->NumberOfOwnDescriptors()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001770
ulan@chromium.org750145a2013-03-07 15:14:13 +00001771 // Normalize the object if the name is an actual name (not the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001772 // hidden strings) and is not a real identifier.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001773 // Normalize the object if it will have too many fast properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 Isolate* isolate = GetHeap()->isolate();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001775 if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name)
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001776 && name != isolate->heap()->hidden_string()) ||
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001777 (map()->unused_property_fields() == 0 &&
1778 TooManyFastProperties(properties()->length(), store_mode))) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001779 Object* obj;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001780 MaybeObject* maybe_obj =
1781 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1782 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 return AddSlowProperty(name, value, attributes);
1785 }
1786
1787 // Compute the new index for new field.
1788 int index = map()->NextFreePropertyIndex();
1789
1790 // Allocate new instance descriptors with (name, index) added
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001791 Representation representation = value->OptimalRepresentation();
1792 FieldDescriptor new_field(name, index, attributes, representation);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001793
ager@chromium.org7c537e22008-10-16 08:43:32 +00001794 ASSERT(index < map()->inobject_properties() ||
1795 (index - map()->inobject_properties()) < properties()->length() ||
1796 map()->unused_property_fields() == 0);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001797
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001798 FixedArray* values = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001799
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001800 // TODO(verwaest): Merge with AddFastPropertyUsingMap.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001801 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001802 // Make room for the new value
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001803 MaybeObject* maybe_values =
1804 properties()->CopySize(properties()->length() + kFieldsAdded);
1805 if (!maybe_values->To(&values)) return maybe_values;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001806 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001807
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001808 TransitionFlag flag = INSERT_TRANSITION;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001809
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001810 Heap* heap = isolate->heap();
1811
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001812 Map* new_map;
1813 MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&new_field, flag);
1814 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
1815
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001816 Object* storage;
1817 MaybeObject* maybe_storage =
1818 value->AllocateNewStorageFor(heap, representation);
1819 if (!maybe_storage->To(&storage)) return maybe_storage;
1820
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001821 if (map()->unused_property_fields() == 0) {
1822 ASSERT(values != NULL);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001823 set_properties(values);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001824 new_map->set_unused_property_fields(kFieldsAdded - 1);
1825 } else {
1826 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 }
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00001828
ager@chromium.org7c537e22008-10-16 08:43:32 +00001829 set_map(new_map);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001830
1831 FastPropertyAtPut(index, storage);
1832 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833}
1834
1835
lrn@chromium.org303ada72010-10-27 09:33:13 +00001836MaybeObject* JSObject::AddConstantFunctionProperty(
ulan@chromium.org750145a2013-03-07 15:14:13 +00001837 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001838 JSFunction* function,
1839 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840 // Allocate new instance descriptors with (name, function) added
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001841 ConstantFunctionDescriptor d(name, function, attributes);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001842
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001843 TransitionFlag flag =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00001844 // Do not add transitions to global objects.
1845 (IsGlobalObject() ||
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001846 // Don't add transitions to special properties with non-trivial
1847 // attributes.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001848 attributes != NONE)
1849 ? OMIT_TRANSITION
1850 : INSERT_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001851
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001852 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00001853 MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001854 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001855
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001856 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857 return function;
1858}
1859
1860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001861// Add property in slow mode
ulan@chromium.org750145a2013-03-07 15:14:13 +00001862MaybeObject* JSObject::AddSlowProperty(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001863 Object* value,
1864 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001865 ASSERT(!HasFastProperties());
ulan@chromium.org750145a2013-03-07 15:14:13 +00001866 NameDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001867 Object* store_value = value;
1868 if (IsGlobalObject()) {
1869 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001870 int entry = dict->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00001871 if (entry != NameDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001872 store_value = dict->ValueAt(entry);
1873 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001874 // Assign an enumeration index to the property and update
1875 // SetNextEnumerationIndex.
1876 int index = dict->NextEnumerationIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001877 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001878 dict->SetNextEnumerationIndex(index + 1);
1879 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001880 return value;
1881 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001882 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001883 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001885 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1886 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001887 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001889 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001890 Object* result;
1891 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1892 if (!maybe_result->ToObject(&result)) return maybe_result;
1893 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00001894 if (dict != result) set_properties(NameDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895 return value;
1896}
1897
1898
ulan@chromium.org750145a2013-03-07 15:14:13 +00001899MaybeObject* JSObject::AddProperty(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001900 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001901 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001902 StrictModeFlag strict_mode,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001903 JSReceiver::StoreFromKeyed store_mode,
1904 ExtensibilityCheck extensibility_check) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001905 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001906 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001907 Heap* heap = GetHeap();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001908 Isolate* isolate = heap->isolate();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001909 MaybeObject* result;
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001910 if (extensibility_check == PERFORM_EXTENSIBILITY_CHECK &&
1911 !map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001912 if (strict_mode == kNonStrictMode) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001913 return value;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001914 } else {
ulan@chromium.org750145a2013-03-07 15:14:13 +00001915 Handle<Object> args[1] = {Handle<Name>(name)};
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001916 return isolate->Throw(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001917 *FACTORY->NewTypeError("object_not_extensible",
1918 HandleVector(args, 1)));
1919 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001920 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001921
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001922 if (HasFastProperties()) {
1923 // Ensure the descriptor array does not get too big.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00001924 if (map_of_this->NumberOfOwnDescriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925 DescriptorArray::kMaxNumberOfDescriptors) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001926 if (value->IsJSFunction()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001927 result = AddConstantFunctionProperty(name,
1928 JSFunction::cast(value),
1929 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001930 } else {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001931 result = AddFastProperty(name, value, attributes, store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 }
1933 } else {
1934 // Normalize the object to prevent very large instance descriptors.
1935 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001936 Object* obj;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001937 MaybeObject* maybe = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1938 if (!maybe->To(&obj)) return maybe;
1939 result = AddSlowProperty(name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001940 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001941 } else {
1942 result = AddSlowProperty(name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001943 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001944
1945 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001946 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001947
1948 if (FLAG_harmony_observation && map()->is_observed()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001949 EnqueueChangeRecord(handle(this, isolate),
1950 "new",
1951 handle(name, isolate),
1952 handle(heap->the_hole_value(), isolate));
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001953 }
1954
1955 return *hresult;
1956}
1957
1958
1959void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
1960 const char* type_str,
ulan@chromium.org750145a2013-03-07 15:14:13 +00001961 Handle<Name> name,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001962 Handle<Object> old_value) {
1963 Isolate* isolate = object->GetIsolate();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001964 HandleScope scope(isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001965 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00001966 if (object->IsJSGlobalObject()) {
1967 object = handle(JSGlobalObject::cast(*object)->global_receiver(), isolate);
1968 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001969 Handle<Object> args[] = { type, object, name, old_value };
1970 bool threw;
1971 Execution::Call(Handle<JSFunction>(isolate->observers_notify_change()),
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001972 isolate->factory()->undefined_value(),
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001973 old_value->IsTheHole() ? 3 : 4, args,
1974 &threw);
1975 ASSERT(!threw);
1976}
1977
1978
1979void JSObject::DeliverChangeRecords(Isolate* isolate) {
1980 ASSERT(isolate->observer_delivery_pending());
1981 bool threw = false;
1982 Execution::Call(
1983 isolate->observers_deliver_changes(),
1984 isolate->factory()->undefined_value(),
1985 0,
1986 NULL,
1987 &threw);
1988 ASSERT(!threw);
1989 isolate->set_observer_delivery_pending(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990}
1991
1992
lrn@chromium.org303ada72010-10-27 09:33:13 +00001993MaybeObject* JSObject::SetPropertyPostInterceptor(
ulan@chromium.org750145a2013-03-07 15:14:13 +00001994 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00001995 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001996 PropertyAttributes attributes,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00001997 StrictModeFlag strict_mode,
1998 ExtensibilityCheck extensibility_check) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002000 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002001 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002002 if (!result.IsFound()) map()->LookupTransition(this, name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002003 if (result.IsFound()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002004 // An existing property or a map transition was found. Use set property to
2005 // handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002006 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00002007 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002008 bool done = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002009 MaybeObject* result_object;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002010 result_object =
2011 SetPropertyViaPrototypes(name, value, attributes, strict_mode, &done);
2012 if (done) return result_object;
ager@chromium.org5c838252010-02-19 08:53:10 +00002013 // Add a new real property.
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00002014 return AddProperty(name, value, attributes, strict_mode,
2015 MAY_BE_STORE_FROM_KEYED, extensibility_check);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016}
2017
2018
ulan@chromium.org750145a2013-03-07 15:14:13 +00002019MaybeObject* JSObject::ReplaceSlowProperty(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002020 Object* value,
2021 PropertyAttributes attributes) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002022 NameDictionary* dictionary = property_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002023 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002024 int new_enumeration_index = 0; // 0 means "Use the next available index."
2025 if (old_index != -1) {
2026 // All calls to ReplaceSlowProperty have had all transitions removed.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002027 new_enumeration_index = dictionary->DetailsAt(old_index).dictionary_index();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002028 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002029
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002030 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002031 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002032}
2033
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002034
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002035MaybeObject* JSObject::ConvertTransitionToMapTransition(
2036 int transition_index,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002037 Name* name,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002038 Object* new_value,
2039 PropertyAttributes attributes) {
2040 Map* old_map = map();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002041 Map* old_target = old_map->GetTransition(transition_index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002042 Object* result;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002043
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002044 MaybeObject* maybe_result =
2045 ConvertDescriptorToField(name, new_value, attributes);
2046 if (!maybe_result->To(&result)) return maybe_result;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002047
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002048 if (!HasFastProperties()) return result;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002049
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00002050 // This method should only be used to convert existing transitions.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002051 Map* new_map = map();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002052
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002053 // TODO(verwaest): From here on we lose existing map transitions, causing
2054 // invalid back pointers. This will change once we can store multiple
2055 // transitions with the same key.
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002056 bool owned_descriptors = old_map->owns_descriptors();
2057 if (owned_descriptors ||
2058 old_target->instance_descriptors() == old_map->instance_descriptors()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002059 // Since the conversion above generated a new fast map with an additional
2060 // property which can be shared as well, install this descriptor pointer
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002061 // along the entire chain of smaller maps.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002062 Map* map;
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002063 DescriptorArray* new_descriptors = new_map->instance_descriptors();
2064 DescriptorArray* old_descriptors = old_map->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002065 for (Object* current = old_map;
2066 !current->IsUndefined();
2067 current = map->GetBackPointer()) {
2068 map = Map::cast(current);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002069 if (map->instance_descriptors() != old_descriptors) break;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00002070 map->SetEnumLength(Map::kInvalidEnumCache);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002071 map->set_instance_descriptors(new_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002072 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00002073 old_map->set_owns_descriptors(false);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002074 }
2075
danno@chromium.orgf005df62013-04-30 16:36:45 +00002076 old_target->DeprecateTransitionTree();
2077
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002078 old_map->SetTransition(transition_index, new_map);
2079 new_map->SetBackPointer(old_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002080 return result;
2081}
2082
2083
ulan@chromium.org750145a2013-03-07 15:14:13 +00002084MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002085 Object* new_value,
2086 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002087 if (map()->unused_property_fields() == 0 &&
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002088 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002089 Object* obj;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002090 MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2091 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002092 return ReplaceSlowProperty(name, new_value, attributes);
2093 }
2094
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002095 Representation representation = new_value->OptimalRepresentation();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002096 int index = map()->NextFreePropertyIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002097 FieldDescriptor new_field(name, index, attributes, representation);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002098
ager@chromium.org7c537e22008-10-16 08:43:32 +00002099 // Make a new map for the object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00002100 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002101 MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field,
2102 OMIT_TRANSITION);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002103 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002104
2105 // Make new properties array if necessary.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002106 FixedArray* new_properties = NULL;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002107 int new_unused_property_fields = map()->unused_property_fields() - 1;
2108 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002109 new_unused_property_fields = kFieldsAdded - 1;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002110 MaybeObject* maybe_new_properties =
2111 properties()->CopySize(properties()->length() + kFieldsAdded);
2112 if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002113 }
2114
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002115 Heap* heap = GetHeap();
2116 Object* storage;
2117 MaybeObject* maybe_storage =
2118 new_value->AllocateNewStorageFor(heap, representation);
2119 if (!maybe_storage->To(&storage)) return maybe_storage;
2120
ager@chromium.org7c537e22008-10-16 08:43:32 +00002121 // Update pointers to commit changes.
2122 // Object points to the new map.
2123 new_map->set_unused_property_fields(new_unused_property_fields);
2124 set_map(new_map);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00002125 if (new_properties != NULL) {
2126 set_properties(new_properties);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002127 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002128 FastPropertyAtPut(index, new_value);
2129 return new_value;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002130}
2131
2132
danno@chromium.orgf005df62013-04-30 16:36:45 +00002133const char* Representation::Mnemonic() const {
2134 switch (kind_) {
2135 case kNone: return "v";
2136 case kTagged: return "t";
2137 case kSmi: return "s";
2138 case kDouble: return "d";
2139 case kInteger32: return "i";
2140 case kExternal: return "x";
2141 default:
2142 UNREACHABLE();
2143 return NULL;
2144 }
2145}
2146
2147
2148enum RightTrimMode { FROM_GC, FROM_MUTATOR };
2149
2150
2151static void ZapEndOfFixedArray(Address new_end, int to_trim) {
2152 // If we are doing a big trim in old space then we zap the space.
2153 Object** zap = reinterpret_cast<Object**>(new_end);
2154 zap++; // Header of filler must be at least one word so skip that.
2155 for (int i = 1; i < to_trim; i++) {
2156 *zap++ = Smi::FromInt(0);
2157 }
2158}
2159
2160
2161template<RightTrimMode trim_mode>
2162static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) {
2163 ASSERT(elms->map() != HEAP->fixed_cow_array_map());
2164 // For now this trick is only applied to fixed arrays in new and paged space.
2165 ASSERT(!HEAP->lo_space()->Contains(elms));
2166
2167 const int len = elms->length();
2168
2169 ASSERT(to_trim < len);
2170
2171 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim);
2172
2173 if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) {
2174 ZapEndOfFixedArray(new_end, to_trim);
2175 }
2176
2177 int size_delta = to_trim * kPointerSize;
2178
2179 // Technically in new space this write might be omitted (except for
2180 // debug mode which iterates through the heap), but to play safer
2181 // we still do it.
2182 heap->CreateFillerObjectAt(new_end, size_delta);
2183
2184 elms->set_length(len - to_trim);
2185
2186 // Maintain marking consistency for IncrementalMarking.
2187 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) {
2188 if (trim_mode == FROM_GC) {
2189 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta);
2190 } else {
2191 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
2192 }
2193 }
2194}
2195
2196
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002197bool Map::InstancesNeedRewriting(Map* target,
2198 int target_number_of_fields,
danno@chromium.orgf005df62013-04-30 16:36:45 +00002199 int target_inobject,
2200 int target_unused) {
2201 // If fields were added (or removed), rewrite the instance.
2202 int number_of_fields = NumberOfFields();
2203 ASSERT(target_number_of_fields >= number_of_fields);
2204 if (target_number_of_fields != number_of_fields) return true;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002205
2206 if (FLAG_track_double_fields) {
2207 // If smi descriptors were replaced by double descriptors, rewrite.
2208 DescriptorArray* old_desc = instance_descriptors();
2209 DescriptorArray* new_desc = target->instance_descriptors();
2210 int limit = NumberOfOwnDescriptors();
2211 for (int i = 0; i < limit; i++) {
2212 if (new_desc->GetDetails(i).representation().IsDouble() &&
2213 old_desc->GetDetails(i).representation().IsSmi()) {
2214 return true;
2215 }
2216 }
2217 }
2218
danno@chromium.orgf005df62013-04-30 16:36:45 +00002219 // If no fields were added, and no inobject properties were removed, setting
2220 // the map is sufficient.
2221 if (target_inobject == inobject_properties()) return false;
2222 // In-object slack tracking may have reduced the object size of the new map.
2223 // In that case, succeed if all existing fields were inobject, and they still
2224 // fit within the new inobject size.
2225 ASSERT(target_inobject < inobject_properties());
2226 if (target_number_of_fields <= target_inobject) {
2227 ASSERT(target_number_of_fields + target_unused == target_inobject);
2228 return false;
2229 }
2230 // Otherwise, properties will need to be moved to the backing store.
2231 return true;
2232}
2233
2234
2235// To migrate an instance to a map:
2236// - First check whether the instance needs to be rewritten. If not, simply
2237// change the map.
2238// - Otherwise, allocate a fixed array large enough to hold all fields, in
2239// addition to unused space.
2240// - Copy all existing properties in, in the following order: backing store
2241// properties, unused fields, inobject properties.
2242// - If all allocation succeeded, commit the state atomically:
2243// * Copy inobject properties from the backing store back into the object.
2244// * Trim the difference in instance size of the object. This also cleanly
2245// frees inobject properties that moved to the backing store.
2246// * If there are properties left in the backing store, trim of the space used
2247// to temporarily store the inobject properties.
2248// * If there are properties left in the backing store, install the backing
2249// store.
2250MaybeObject* JSObject::MigrateToMap(Map* new_map) {
2251 Heap* heap = GetHeap();
2252 Map* old_map = map();
2253 int number_of_fields = new_map->NumberOfFields();
2254 int inobject = new_map->inobject_properties();
2255 int unused = new_map->unused_property_fields();
2256
2257 // Nothing to do if no functions were converted to fields.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002258 if (!old_map->InstancesNeedRewriting(
2259 new_map, number_of_fields, inobject, unused)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00002260 set_map(new_map);
2261 return this;
2262 }
2263
2264 int total_size = number_of_fields + unused;
2265 int external = total_size - inobject;
2266 FixedArray* array;
2267 MaybeObject* maybe_array = heap->AllocateFixedArray(total_size);
2268 if (!maybe_array->To(&array)) return maybe_array;
2269
2270 DescriptorArray* old_descriptors = old_map->instance_descriptors();
2271 DescriptorArray* new_descriptors = new_map->instance_descriptors();
2272 int descriptors = new_map->NumberOfOwnDescriptors();
2273
2274 for (int i = 0; i < descriptors; i++) {
2275 PropertyDetails details = new_descriptors->GetDetails(i);
2276 if (details.type() != FIELD) continue;
2277 PropertyDetails old_details = old_descriptors->GetDetails(i);
2278 ASSERT(old_details.type() == CONSTANT_FUNCTION ||
2279 old_details.type() == FIELD);
2280 Object* value = old_details.type() == CONSTANT_FUNCTION
2281 ? old_descriptors->GetValue(i)
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002282 : RawFastPropertyAt(old_descriptors->GetFieldIndex(i));
2283 if (FLAG_track_double_fields &&
2284 old_details.representation().IsSmi() &&
2285 details.representation().IsDouble()) {
2286 // Objects must be allocated in the old object space, since the
2287 // overall number of HeapNumbers needed for the conversion might
2288 // exceed the capacity of new space, and we would fail repeatedly
2289 // trying to migrate the instance.
2290 MaybeObject* maybe_storage =
2291 value->AllocateNewStorageFor(heap, details.representation(), TENURED);
2292 if (!maybe_storage->To(&value)) return maybe_storage;
2293 }
2294 ASSERT(!(FLAG_track_double_fields &&
2295 details.representation().IsDouble() &&
2296 value->IsSmi()));
danno@chromium.orgf005df62013-04-30 16:36:45 +00002297 int target_index = new_descriptors->GetFieldIndex(i) - inobject;
2298 if (target_index < 0) target_index += total_size;
2299 array->set(target_index, value);
2300 }
2301
2302 // From here on we cannot fail anymore.
2303
2304 // Copy (real) inobject properties. If necessary, stop at number_of_fields to
2305 // avoid overwriting |one_pointer_filler_map|.
2306 int limit = Min(inobject, number_of_fields);
2307 for (int i = 0; i < limit; i++) {
2308 FastPropertyAtPut(i, array->get(external + i));
2309 }
2310
2311 // Create filler object past the new instance size.
2312 int new_instance_size = new_map->instance_size();
2313 int instance_size_delta = old_map->instance_size() - new_instance_size;
2314 ASSERT(instance_size_delta >= 0);
2315 Address address = this->address() + new_instance_size;
2316 heap->CreateFillerObjectAt(address, instance_size_delta);
2317
2318 // If there are properties in the new backing store, trim it to the correct
2319 // size and install the backing store into the object.
2320 if (external > 0) {
2321 RightTrimFixedArray<FROM_MUTATOR>(heap, array, inobject);
2322 set_properties(array);
2323 }
2324
2325 set_map(new_map);
2326
2327 return this;
2328}
2329
2330
2331MaybeObject* JSObject::GeneralizeFieldRepresentation(
2332 int modify_index,
2333 Representation new_representation) {
2334 Map* new_map;
2335 MaybeObject* maybe_new_map =
2336 map()->GeneralizeRepresentation(modify_index, new_representation);
2337 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
2338 ASSERT(map() != new_map || new_map->FindRootMap()->is_deprecated());
2339
2340 return MigrateToMap(new_map);
2341}
2342
2343
2344int Map::NumberOfFields() {
2345 DescriptorArray* descriptors = instance_descriptors();
2346 int result = 0;
2347 for (int i = 0; i < NumberOfOwnDescriptors(); i++) {
2348 if (descriptors->GetDetails(i).type() == FIELD) result++;
2349 }
2350 return result;
2351}
2352
2353
2354MaybeObject* Map::CopyGeneralizeAllRepresentations() {
2355 Map* new_map;
2356 MaybeObject* maybe_map = this->Copy();
2357 if (!maybe_map->To(&new_map)) return maybe_map;
2358
2359 new_map->instance_descriptors()->InitializeRepresentations(
2360 Representation::Tagged());
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002361 if (FLAG_trace_generalization) {
2362 PrintF("failed generalization %p -> %p\n",
2363 static_cast<void*>(this), static_cast<void*>(new_map));
2364 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00002365 return new_map;
2366}
2367
2368
2369void Map::DeprecateTransitionTree() {
2370 if (!FLAG_track_fields) return;
2371 if (is_deprecated()) return;
2372 if (HasTransitionArray()) {
2373 TransitionArray* transitions = this->transitions();
2374 for (int i = 0; i < transitions->number_of_transitions(); i++) {
2375 transitions->GetTarget(i)->DeprecateTransitionTree();
2376 }
2377 }
2378 deprecate();
2379 dependent_code()->DeoptimizeDependentCodeGroup(
2380 GetIsolate(), DependentCode::kTransitionGroup);
2381 dependent_code()->DeoptimizeDependentCodeGroup(
2382 GetIsolate(), DependentCode::kPrototypeCheckGroup);
2383}
2384
2385
2386// Invalidates a transition target at |key|, and installs |new_descriptors| over
2387// the current instance_descriptors to ensure proper sharing of descriptor
2388// arrays.
2389void Map::DeprecateTarget(Name* key, DescriptorArray* new_descriptors) {
2390 if (HasTransitionArray()) {
2391 TransitionArray* transitions = this->transitions();
2392 int transition = transitions->Search(key);
2393 if (transition != TransitionArray::kNotFound) {
2394 transitions->GetTarget(transition)->DeprecateTransitionTree();
2395 }
2396 }
2397
2398 // Don't overwrite the empty descriptor array.
2399 if (NumberOfOwnDescriptors() == 0) return;
2400
2401 DescriptorArray* to_replace = instance_descriptors();
2402 Map* current = this;
2403 while (current->instance_descriptors() == to_replace) {
2404 current->SetEnumLength(Map::kInvalidEnumCache);
2405 current->set_instance_descriptors(new_descriptors);
2406 Object* next = current->GetBackPointer();
2407 if (next->IsUndefined()) break;
2408 current = Map::cast(next);
2409 }
2410
2411 set_owns_descriptors(false);
2412}
2413
2414
2415Map* Map::FindRootMap() {
2416 Map* result = this;
2417 while (true) {
2418 Object* back = result->GetBackPointer();
2419 if (back->IsUndefined()) return result;
2420 result = Map::cast(back);
2421 }
2422}
2423
2424
2425Map* Map::FindUpdatedMap(int verbatim,
2426 int length,
2427 DescriptorArray* descriptors) {
2428 // This can only be called on roots of transition trees.
2429 ASSERT(GetBackPointer()->IsUndefined());
2430
2431 Map* current = this;
2432
2433 for (int i = verbatim; i < length; i++) {
2434 if (!current->HasTransitionArray()) break;
2435 Name* name = descriptors->GetKey(i);
2436 TransitionArray* transitions = current->transitions();
2437 int transition = transitions->Search(name);
2438 if (transition == TransitionArray::kNotFound) break;
2439 current = transitions->GetTarget(transition);
2440 }
2441
2442 return current;
2443}
2444
2445
2446Map* Map::FindLastMatchMap(int verbatim,
2447 int length,
2448 DescriptorArray* descriptors) {
2449 // This can only be called on roots of transition trees.
2450 ASSERT(GetBackPointer()->IsUndefined());
2451
2452 Map* current = this;
2453
2454 for (int i = verbatim; i < length; i++) {
2455 if (!current->HasTransitionArray()) break;
2456 Name* name = descriptors->GetKey(i);
2457 TransitionArray* transitions = current->transitions();
2458 int transition = transitions->Search(name);
2459 if (transition == TransitionArray::kNotFound) break;
2460
2461 Map* next = transitions->GetTarget(transition);
2462 DescriptorArray* next_descriptors = next->instance_descriptors();
2463
2464 if (next_descriptors->GetValue(i) != descriptors->GetValue(i)) break;
2465
2466 PropertyDetails details = descriptors->GetDetails(i);
2467 PropertyDetails next_details = next_descriptors->GetDetails(i);
2468 if (details.type() != next_details.type()) break;
2469 if (details.attributes() != next_details.attributes()) break;
2470 if (!details.representation().Equals(next_details.representation())) break;
2471 ASSERT(!details.IsDeleted());
2472 ASSERT(!next_details.IsDeleted());
2473
2474 current = next;
2475 }
2476 return current;
2477}
2478
2479
2480// Generalize the representation of the descriptor at |modify_index|.
2481// This method rewrites the transition tree to reflect the new change. To avoid
2482// high degrees over polymorphism, and to stabilize quickly, on every rewrite
2483// the new type is deduced by merging the current type with any potential new
2484// (partial) version of the type in the transition tree.
2485// To do this, on each rewrite:
2486// - Search the root of the transition tree using FindRootMap.
2487// - Find |updated|, the newest matching version of this map using
2488// FindUpdatedMap. This uses the keys in the own map's descriptor array to
2489// walk the transition tree.
2490// - Merge/generalize the descriptor array of the current map and |updated|.
2491// - Generalize the |modify_index| descriptor using |new_representation|.
2492// - Walk the tree again starting from the root towards |updated|. Stop at
2493// |split_map|, the first map who's descriptor array does not match the merged
2494// descriptor array.
2495// - If |updated| == |split_map|, |updated| is in the expected state. Return it.
2496// - Otherwise, invalidate the outdated transition target from |updated|, and
2497// replace its transition tree with a new branch for the updated descriptors.
2498MaybeObject* Map::GeneralizeRepresentation(int modify_index,
2499 Representation new_representation) {
2500 Map* old_map = this;
2501 DescriptorArray* old_descriptors = old_map->instance_descriptors();
2502 Representation old_reprepresentation =
2503 old_descriptors->GetDetails(modify_index).representation();
2504
2505 if (old_reprepresentation.IsNone()) {
2506 UNREACHABLE();
2507 old_descriptors->SetRepresentation(modify_index, new_representation);
2508 return this;
2509 }
2510
2511 int descriptors = old_map->NumberOfOwnDescriptors();
2512 Map* root_map = old_map->FindRootMap();
2513
2514 if (!old_map->EquivalentToForTransition(root_map)) {
2515 return CopyGeneralizeAllRepresentations();
2516 }
2517
2518 int verbatim = root_map->NumberOfOwnDescriptors();
2519
2520 Map* updated = root_map->FindUpdatedMap(
2521 verbatim, descriptors, old_descriptors);
2522 // Check the state of the root map.
2523 DescriptorArray* updated_descriptors = updated->instance_descriptors();
2524
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002525 int valid = updated->NumberOfOwnDescriptors();
2526 if (updated_descriptors->IsMoreGeneralThan(
2527 verbatim, valid, descriptors, old_descriptors)) {
2528 Representation updated_representation =
2529 updated_descriptors->GetDetails(modify_index).representation();
2530 if (new_representation.fits_into(updated_representation)) {
2531 if (FLAG_trace_generalization) {
2532 PrintF("migrating to existing map %p -> %p\n",
2533 static_cast<void*>(this), static_cast<void*>(updated));
2534 }
2535 return updated;
2536 }
2537 }
2538
danno@chromium.orgf005df62013-04-30 16:36:45 +00002539 DescriptorArray* new_descriptors;
2540 MaybeObject* maybe_descriptors = updated_descriptors->Merge(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002541 verbatim, valid, descriptors, old_descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002542 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
2543
2544 old_reprepresentation =
2545 new_descriptors->GetDetails(modify_index).representation();
2546 new_representation = new_representation.generalize(old_reprepresentation);
2547 new_descriptors->SetRepresentation(modify_index, new_representation);
2548
2549 Map* split_map = root_map->FindLastMatchMap(
2550 verbatim, descriptors, new_descriptors);
2551
2552 int split_descriptors = split_map->NumberOfOwnDescriptors();
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002553 // This is shadowed by |updated_descriptors| being more general than
2554 // |old_descriptors|.
2555 ASSERT(descriptors != split_descriptors);
danno@chromium.orgf005df62013-04-30 16:36:45 +00002556
2557 int descriptor = split_descriptors;
2558 split_map->DeprecateTarget(
2559 old_descriptors->GetKey(descriptor), new_descriptors);
2560
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002561 if (FLAG_trace_generalization) {
2562 PrintF("migrating to new map %p -> %p (%i steps)\n",
2563 static_cast<void*>(this),
2564 static_cast<void*>(new_descriptors),
2565 descriptors - descriptor);
2566 }
2567
danno@chromium.orgf005df62013-04-30 16:36:45 +00002568 Map* new_map = split_map;
2569 // Add missing transitions.
2570 for (; descriptor < descriptors; descriptor++) {
2571 MaybeObject* maybe_map = new_map->CopyInstallDescriptors(
2572 descriptor, new_descriptors);
2573 if (!maybe_map->To(&new_map)) {
2574 // Create a handle for the last created map to ensure it stays alive
2575 // during GC. Its descriptor array is too large, but it will be
2576 // overwritten during retry anyway.
2577 Handle<Map>(new_map);
2578 }
2579 }
2580
2581 new_map->set_owns_descriptors(true);
2582 return new_map;
2583}
2584
ager@chromium.org7c537e22008-10-16 08:43:32 +00002585
lrn@chromium.org303ada72010-10-27 09:33:13 +00002586MaybeObject* JSObject::SetPropertyWithInterceptor(
ulan@chromium.org750145a2013-03-07 15:14:13 +00002587 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002588 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002589 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002590 StrictModeFlag strict_mode) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00002591 // TODO(rossberg): Support symbols in the API.
2592 if (name->IsSymbol()) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002593 Isolate* isolate = GetIsolate();
2594 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002595 Handle<JSObject> this_handle(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00002596 Handle<String> name_handle(String::cast(name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002597 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002598 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2599 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002600 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
2601 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002602 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002603 v8::NamedPropertySetter setter =
2604 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
2605 v8::Handle<v8::Value> result;
2606 {
2607 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002608 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002609 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610 isolate->heap()->undefined_value() :
2611 value,
2612 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002613 result = setter(v8::Utils::ToLocal(name_handle),
2614 v8::Utils::ToLocal(value_unhole),
2615 info);
2616 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002617 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002618 if (!result.IsEmpty()) return *value_handle;
2619 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002620 MaybeObject* raw_result =
2621 this_handle->SetPropertyPostInterceptor(*name_handle,
2622 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002623 attributes,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00002624 strict_mode,
2625 PERFORM_EXTENSIBILITY_CHECK);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002626 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002627 return raw_result;
2628}
2629
2630
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002631Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002632 Handle<Name> key,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002633 Handle<Object> value,
2634 PropertyAttributes attributes,
2635 StrictModeFlag strict_mode) {
2636 CALL_HEAP_FUNCTION(object->GetIsolate(),
2637 object->SetProperty(*key, *value, attributes, strict_mode),
2638 Object);
2639}
2640
2641
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002642MaybeObject* JSReceiver::SetPropertyOrFail(
2643 Handle<JSReceiver> object,
2644 Handle<Name> key,
2645 Handle<Object> value,
2646 PropertyAttributes attributes,
2647 StrictModeFlag strict_mode,
2648 JSReceiver::StoreFromKeyed store_mode) {
2649 CALL_HEAP_FUNCTION_PASS_EXCEPTION(
2650 object->GetIsolate(),
2651 object->SetProperty(*key, *value, attributes, strict_mode, store_mode));
2652}
2653
2654
ulan@chromium.org750145a2013-03-07 15:14:13 +00002655MaybeObject* JSReceiver::SetProperty(Name* name,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002656 Object* value,
2657 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002658 StrictModeFlag strict_mode,
2659 JSReceiver::StoreFromKeyed store_mode) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002660 LookupResult result(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00002661 LocalLookup(name, &result, true);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00002662 if (!result.IsFound()) {
2663 map()->LookupTransition(JSObject::cast(this), name, &result);
2664 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002665 return SetProperty(&result, name, value, attributes, strict_mode, store_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002666}
2667
2668
lrn@chromium.org303ada72010-10-27 09:33:13 +00002669MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
ulan@chromium.org750145a2013-03-07 15:14:13 +00002670 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002671 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002672 JSObject* holder,
2673 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002674 Isolate* isolate = GetIsolate();
2675 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676
2677 // We should never get here to initialize a const with the hole
2678 // value since a const declaration would conflict with the setter.
2679 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002680 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681
2682 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002683 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002684 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002685 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002686 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002687 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002688 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002689 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002690 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002691 if (obj->IsFailure()) return obj;
2692 return *value_handle;
2693 }
2694
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002695 if (structure->IsExecutableAccessorInfo()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002696 // api style callbacks
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002697 ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(structure);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002698 if (!data->IsCompatibleReceiver(this)) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002699 Handle<Object> name_handle(name, isolate);
2700 Handle<Object> receiver_handle(this, isolate);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002701 Handle<Object> args[2] = { name_handle, receiver_handle };
2702 Handle<Object> error =
2703 isolate->factory()->NewTypeError("incompatible_method_receiver",
2704 HandleVector(args,
2705 ARRAY_SIZE(args)));
2706 return isolate->Throw(*error);
2707 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00002708 // TODO(rossberg): Support symbols in the API.
2709 if (name->IsSymbol()) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002710 Object* call_obj = data->setter();
2711 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
2712 if (call_fun == NULL) return value;
ulan@chromium.org750145a2013-03-07 15:14:13 +00002713 Handle<String> key(String::cast(name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002714 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
2715 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002716 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002717 {
2718 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002719 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002720 call_fun(v8::Utils::ToLocal(key),
2721 v8::Utils::ToLocal(value_handle),
2722 info);
2723 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002725 return *value_handle;
2726 }
2727
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002728 if (structure->IsAccessorPair()) {
2729 Object* setter = AccessorPair::cast(structure)->setter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002730 if (setter->IsSpecFunction()) {
2731 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2732 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002733 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002734 if (strict_mode == kNonStrictMode) {
2735 return value;
2736 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00002737 Handle<Name> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002738 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002739 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002740 return isolate->Throw(
2741 *isolate->factory()->NewTypeError("no_setter_in_callback",
2742 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002744 }
2745
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002746 // TODO(dcarney): Handle correctly.
2747 if (structure->IsDeclaredAccessorInfo()) {
2748 return value;
2749 }
2750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002751 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002752 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002753}
2754
2755
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002756MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2757 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002758 Isolate* isolate = GetIsolate();
2759 Handle<Object> value_handle(value, isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002760 Handle<JSReceiver> fun(setter, isolate);
2761 Handle<JSReceiver> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002762#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002763 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002764 // Handle stepping into a setter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002765 // TODO(rossberg): should this apply to getters that are function proxies?
2766 if (debug->StepInActive() && fun->IsJSFunction()) {
2767 debug->HandleStepIn(
2768 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002769 }
2770#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002771 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002772 Handle<Object> argv[] = { value_handle };
2773 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002774 // Check for pending exception and return the result.
2775 if (has_pending_exception) return Failure::Exception();
2776 return *value_handle;
2777}
2778
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002779
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002780MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2781 uint32_t index,
2782 Object* value,
2783 bool* found,
2784 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002785 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002786 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002787 pt != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002788 pt = pt->GetPrototype(GetIsolate())) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002789 if (pt->IsJSProxy()) {
2790 String* name;
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002791 MaybeObject* maybe = heap->Uint32ToString(index);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002792 if (!maybe->To<String>(&name)) {
2793 *found = true; // Force abort
2794 return maybe;
2795 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002796 return JSProxy::cast(pt)->SetPropertyViaPrototypesWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00002797 this, name, value, NONE, strict_mode, found);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002798 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002799 if (!JSObject::cast(pt)->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002800 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002801 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002802 SeededNumberDictionary* dictionary =
2803 JSObject::cast(pt)->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002804 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002805 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002806 PropertyDetails details = dictionary->DetailsAt(entry);
2807 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002808 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002809 return SetElementWithCallback(dictionary->ValueAt(entry),
2810 index,
2811 value,
2812 JSObject::cast(pt),
2813 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002814 }
2815 }
2816 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002817 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002818 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002819}
2820
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002821MaybeObject* JSObject::SetPropertyViaPrototypes(
ulan@chromium.org750145a2013-03-07 15:14:13 +00002822 Name* name,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002823 Object* value,
2824 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002825 StrictModeFlag strict_mode,
2826 bool* done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002827 Heap* heap = GetHeap();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002828 Isolate* isolate = heap->isolate();
2829
2830 *done = false;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002831 // We could not find a local property so let's check whether there is an
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002832 // accessor that wants to handle the property, or whether the property is
2833 // read-only on the prototype chain.
2834 LookupResult result(isolate);
2835 LookupRealNamedPropertyInPrototypes(name, &result);
2836 if (result.IsFound()) {
2837 switch (result.type()) {
2838 case NORMAL:
2839 case FIELD:
2840 case CONSTANT_FUNCTION:
2841 *done = result.IsReadOnly();
2842 break;
2843 case INTERCEPTOR: {
2844 PropertyAttributes attr =
2845 result.holder()->GetPropertyAttributeWithInterceptor(
2846 this, name, true);
2847 *done = !!(attr & READ_ONLY);
2848 break;
2849 }
2850 case CALLBACKS: {
2851 if (!FLAG_es5_readonly && result.IsReadOnly()) break;
2852 *done = true;
2853 return SetPropertyWithCallback(result.GetCallbackObject(),
2854 name, value, result.holder(), strict_mode);
2855 }
2856 case HANDLER: {
2857 return result.proxy()->SetPropertyViaPrototypesWithHandler(
2858 this, name, value, attributes, strict_mode, done);
2859 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002860 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00002861 case NONEXISTENT:
2862 UNREACHABLE();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002863 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002864 }
2865 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002866
2867 // If we get here with *done true, we have encountered a read-only property.
2868 if (!FLAG_es5_readonly) *done = false;
2869 if (*done) {
2870 if (strict_mode == kNonStrictMode) return value;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002871 Handle<Object> args[] = { Handle<Object>(name, isolate),
2872 Handle<Object>(this, isolate)};
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002873 return isolate->Throw(*isolate->factory()->NewTypeError(
2874 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
2875 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002876 return heap->the_hole_value();
2877}
2878
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002879
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002880void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
2881 Handle<DescriptorArray> descriptors(map->instance_descriptors());
2882 if (slack <= descriptors->NumberOfSlackDescriptors()) return;
2883 int number_of_descriptors = descriptors->number_of_descriptors();
2884 Isolate* isolate = map->GetIsolate();
2885 Handle<DescriptorArray> new_descriptors =
2886 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack);
2887 DescriptorArray::WhitenessWitness witness(*new_descriptors);
2888
2889 for (int i = 0; i < number_of_descriptors; ++i) {
2890 new_descriptors->CopyFrom(i, *descriptors, i, witness);
2891 }
2892
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002893 map->set_instance_descriptors(*new_descriptors);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002894}
2895
2896
2897void Map::AppendCallbackDescriptors(Handle<Map> map,
2898 Handle<Object> descriptors) {
danno@chromium.org129d3982012-07-25 15:01:47 +00002899 Isolate* isolate = map->GetIsolate();
2900 Handle<DescriptorArray> array(map->instance_descriptors());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002901 NeanderArray callbacks(descriptors);
danno@chromium.org129d3982012-07-25 15:01:47 +00002902 int nof_callbacks = callbacks.length();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002903
2904 ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks);
danno@chromium.org129d3982012-07-25 15:01:47 +00002905
ulan@chromium.org750145a2013-03-07 15:14:13 +00002906 // Ensure the keys are unique names before writing them into the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002907 // instance descriptor. Since it may cause a GC, it has to be done before we
danno@chromium.org129d3982012-07-25 15:01:47 +00002908 // temporarily put the heap in an invalid state while appending descriptors.
2909 for (int i = 0; i < nof_callbacks; ++i) {
2910 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i)));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002911 if (!entry->name()->IsUniqueName()) {
2912 Handle<String> key =
2913 isolate->factory()->InternalizedStringFromString(
2914 Handle<String>(String::cast(entry->name())));
2915 entry->set_name(*key);
2916 }
danno@chromium.org129d3982012-07-25 15:01:47 +00002917 }
2918
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002919 int nof = map->NumberOfOwnDescriptors();
danno@chromium.org129d3982012-07-25 15:01:47 +00002920
2921 // Fill in new callback descriptors. Process the callbacks from
2922 // back to front so that the last callback with a given name takes
2923 // precedence over previously added callbacks with that name.
2924 for (int i = nof_callbacks - 1; i >= 0; i--) {
2925 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i));
ulan@chromium.org750145a2013-03-07 15:14:13 +00002926 Name* key = Name::cast(entry->name());
danno@chromium.org129d3982012-07-25 15:01:47 +00002927 // Check if a descriptor with this name already exists before writing.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002928 if (array->Search(key, nof) == DescriptorArray::kNotFound) {
danno@chromium.org129d3982012-07-25 15:01:47 +00002929 CallbacksDescriptor desc(key, entry, entry->property_attributes());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002930 array->Append(&desc);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00002931 nof += 1;
danno@chromium.org129d3982012-07-25 15:01:47 +00002932 }
2933 }
2934
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002935 map->SetNumberOfOwnDescriptors(nof);
danno@chromium.org129d3982012-07-25 15:01:47 +00002936}
2937
2938
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002939static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2940 ASSERT(!map.is_null());
2941 for (int i = 0; i < maps->length(); ++i) {
2942 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2943 }
2944 return false;
2945}
2946
2947
2948template <class T>
2949static Handle<T> MaybeNull(T* p) {
2950 if (p == NULL) return Handle<T>::null();
2951 return Handle<T>(p);
2952}
2953
2954
2955Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002956 ElementsKind kind = elements_kind();
2957 Handle<Map> transitioned_map = Handle<Map>::null();
2958 Handle<Map> current_map(this);
2959 bool packed = IsFastPackedElementsKind(kind);
2960 if (IsTransitionableFastElementsKind(kind)) {
2961 while (CanTransitionToMoreGeneralFastElementsKind(kind, false)) {
2962 kind = GetNextMoreGeneralFastElementsKind(kind, false);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002963 Handle<Map> maybe_transitioned_map =
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002964 MaybeNull(current_map->LookupElementsTransitionMap(kind));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002965 if (maybe_transitioned_map.is_null()) break;
2966 if (ContainsMap(candidates, maybe_transitioned_map) &&
2967 (packed || !IsFastPackedElementsKind(kind))) {
2968 transitioned_map = maybe_transitioned_map;
2969 if (!IsFastPackedElementsKind(kind)) packed = false;
2970 }
2971 current_map = maybe_transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002972 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002973 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002974 return transitioned_map;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002975}
2976
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00002977
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002978static Map* FindClosestElementsTransition(Map* map, ElementsKind to_kind) {
2979 Map* current_map = map;
2980 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
verwaest@chromium.org50915592012-06-18 12:15:44 +00002981 int to_index = IsFastElementsKind(to_kind)
2982 ? GetSequenceIndexFromFastElementsKind(to_kind)
2983 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
2984
2985 ASSERT(index <= to_index);
2986
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002987 for (; index < to_index; ++index) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002988 if (!current_map->HasElementsTransition()) return current_map;
2989 current_map = current_map->elements_transition_map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002990 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002991 if (!IsFastElementsKind(to_kind) && current_map->HasElementsTransition()) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00002992 Map* next_map = current_map->elements_transition_map();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002993 if (next_map->elements_kind() == to_kind) return next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00002994 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002995 ASSERT(IsFastElementsKind(to_kind)
2996 ? current_map->elements_kind() == to_kind
2997 : current_map->elements_kind() == TERMINAL_FAST_ELEMENTS_KIND);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002998 return current_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002999}
3000
3001
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003002Map* Map::LookupElementsTransitionMap(ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003003 Map* to_map = FindClosestElementsTransition(this, to_kind);
3004 if (to_map->elements_kind() == to_kind) return to_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003005 return NULL;
3006}
3007
3008
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003009static MaybeObject* AddMissingElementsTransitions(Map* map,
3010 ElementsKind to_kind) {
verwaest@chromium.org50915592012-06-18 12:15:44 +00003011 ASSERT(IsFastElementsKind(map->elements_kind()));
3012 int index = GetSequenceIndexFromFastElementsKind(map->elements_kind());
3013 int to_index = IsFastElementsKind(to_kind)
3014 ? GetSequenceIndexFromFastElementsKind(to_kind)
3015 : GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
3016
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003017 ASSERT(index <= to_index);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003018
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003019 Map* current_map = map;
3020
verwaest@chromium.org50915592012-06-18 12:15:44 +00003021 for (; index < to_index; ++index) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003022 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(index + 1);
3023 MaybeObject* maybe_next_map =
3024 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
3025 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003026 }
3027
verwaest@chromium.org50915592012-06-18 12:15:44 +00003028 // In case we are exiting the fast elements kind system, just add the map in
3029 // the end.
3030 if (!IsFastElementsKind(to_kind)) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003031 MaybeObject* maybe_next_map =
3032 current_map->CopyAsElementsKind(to_kind, INSERT_TRANSITION);
3033 if (!maybe_next_map->To(&current_map)) return maybe_next_map;
verwaest@chromium.org50915592012-06-18 12:15:44 +00003034 }
3035
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003036 ASSERT(current_map->elements_kind() == to_kind);
3037 return current_map;
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003038}
3039
3040
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003041Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
3042 ElementsKind to_kind) {
3043 Isolate* isolate = object->GetIsolate();
3044 CALL_HEAP_FUNCTION(isolate,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003045 object->GetElementsTransitionMap(isolate, to_kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003046 Map);
3047}
3048
3049
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003050MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003051 Map* start_map = map();
3052 ElementsKind from_kind = start_map->elements_kind();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00003053
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003054 if (from_kind == to_kind) {
3055 return start_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003056 }
3057
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003058 bool allow_store_transition =
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003059 // Only remember the map transition if there is not an already existing
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003060 // non-matching element transition.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003061 !start_map->IsUndefined() && !start_map->is_shared() &&
verwaest@chromium.org50915592012-06-18 12:15:44 +00003062 IsFastElementsKind(from_kind);
3063
3064 // Only store fast element maps in ascending generality.
3065 if (IsFastElementsKind(to_kind)) {
3066 allow_store_transition &=
3067 IsTransitionableFastElementsKind(from_kind) &&
3068 IsMoreGeneralElementsKindTransition(from_kind, to_kind);
3069 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003070
3071 if (!allow_store_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003072 return start_map->CopyAsElementsKind(to_kind, OMIT_TRANSITION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003073 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003074
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003075 return start_map->AsElementsKind(to_kind);
3076}
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003077
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003078
3079MaybeObject* Map::AsElementsKind(ElementsKind kind) {
3080 Map* closest_map = FindClosestElementsTransition(this, kind);
3081
3082 if (closest_map->elements_kind() == kind) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003083 return closest_map;
3084 }
3085
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003086 return AddMissingElementsTransitions(closest_map, kind);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003087}
3088
3089
ulan@chromium.org750145a2013-03-07 15:14:13 +00003090void JSObject::LocalLookupRealNamedProperty(Name* name, LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003091 if (IsJSGlobalProxy()) {
3092 Object* proto = GetPrototype();
3093 if (proto->IsNull()) return result->NotFound();
3094 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003095 // A GlobalProxy's prototype should always be a proper JSObject.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003096 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
3097 }
3098
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099 if (HasFastProperties()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003100 map()->LookupDescriptor(this, name, result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003101 // A property or a map transition was found. We return all of these result
3102 // types because LocalLookupRealNamedProperty is used when setting
3103 // properties where map transitions are handled.
3104 ASSERT(!result->IsFound() ||
3105 (result->holder() == this && result->IsFastPropertyType()));
3106 // Disallow caching for uninitialized constants. These can only
3107 // occur as fields.
3108 if (result->IsField() &&
3109 result->IsReadOnly() &&
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003110 RawFastPropertyAt(result->GetFieldIndex().field_index())->IsTheHole()) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003111 result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003112 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003113 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003115
3116 int entry = property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003117 if (entry != NameDictionary::kNotFound) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003118 Object* value = property_dictionary()->ValueAt(entry);
3119 if (IsGlobalObject()) {
3120 PropertyDetails d = property_dictionary()->DetailsAt(entry);
3121 if (d.IsDeleted()) {
3122 result->NotFound();
3123 return;
3124 }
3125 value = JSGlobalPropertyCell::cast(value)->value();
3126 }
3127 // Make sure to disallow caching for uninitialized constants
3128 // found in the dictionary-mode objects.
3129 if (value->IsTheHole()) result->DisallowCaching();
3130 result->DictionaryResult(this, entry);
3131 return;
3132 }
3133
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003134 result->NotFound();
3135}
3136
3137
ulan@chromium.org750145a2013-03-07 15:14:13 +00003138void JSObject::LookupRealNamedProperty(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003139 LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003140 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003141
3142 LookupRealNamedPropertyInPrototypes(name, result);
3143}
3144
3145
ulan@chromium.org750145a2013-03-07 15:14:13 +00003146void JSObject::LookupRealNamedPropertyInPrototypes(Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 LookupResult* result) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003148 Isolate* isolate = GetIsolate();
3149 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003150 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 pt != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00003152 pt = pt->GetPrototype(isolate)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003153 if (pt->IsJSProxy()) {
3154 return result->HandlerResult(JSProxy::cast(pt));
3155 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003156 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003157 ASSERT(!(result->IsFound() && result->type() == INTERCEPTOR));
3158 if (result->IsFound()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003159 }
3160 result->NotFound();
3161}
3162
3163
3164// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003165MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
3166 LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003167 Name* name,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003168 Object* value,
3169 bool check_prototype,
3170 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003171 if (check_prototype && !result->IsProperty()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003172 LookupRealNamedPropertyInPrototypes(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003173 }
3174
3175 if (result->IsProperty()) {
3176 if (!result->IsReadOnly()) {
3177 switch (result->type()) {
3178 case CALLBACKS: {
3179 Object* obj = result->GetCallbackObject();
3180 if (obj->IsAccessorInfo()) {
3181 AccessorInfo* info = AccessorInfo::cast(obj);
3182 if (info->all_can_write()) {
3183 return SetPropertyWithCallback(result->GetCallbackObject(),
3184 name,
3185 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003186 result->holder(),
3187 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003188 }
3189 }
3190 break;
3191 }
3192 case INTERCEPTOR: {
3193 // Try lookup real named properties. Note that only property can be
3194 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003195 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003196 LookupRealNamedProperty(name, &r);
3197 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003198 return SetPropertyWithFailedAccessCheck(&r,
3199 name,
3200 value,
3201 check_prototype,
3202 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003203 }
3204 break;
3205 }
3206 default: {
3207 break;
3208 }
3209 }
3210 }
3211 }
3212
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003213 Isolate* isolate = GetIsolate();
3214 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003215 Handle<Object> value_handle(value, isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003216 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003217 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003218}
3219
3220
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003221MaybeObject* JSReceiver::SetProperty(LookupResult* result,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003222 Name* key,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003223 Object* value,
3224 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003225 StrictModeFlag strict_mode,
3226 JSReceiver::StoreFromKeyed store_mode) {
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00003227 if (result->IsHandler()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003228 return result->proxy()->SetPropertyWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00003229 this, key, value, attributes, strict_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003230 } else {
3231 return JSObject::cast(this)->SetPropertyForResult(
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003232 result, key, value, attributes, strict_mode, store_mode);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003233 }
3234}
3235
3236
ulan@chromium.org750145a2013-03-07 15:14:13 +00003237bool JSProxy::HasPropertyWithHandler(Name* name_raw) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003238 Isolate* isolate = GetIsolate();
3239 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003240 Handle<Object> receiver(this, isolate);
3241 Handle<Object> name(name_raw, isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003242
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003243 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3244 if (name->IsSymbol()) return false;
3245
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003246 Handle<Object> args[] = { name };
3247 Handle<Object> result = CallTrap(
3248 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003249 if (isolate->has_pending_exception()) return false;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003250
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003251 return result->BooleanValue();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003252}
3253
3254
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003255MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00003256 JSReceiver* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003257 Name* name_raw,
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003258 Object* value_raw,
3259 PropertyAttributes attributes,
3260 StrictModeFlag strict_mode) {
3261 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003262 HandleScope scope(isolate);
verwaest@chromium.org37141392012-05-31 13:27:02 +00003263 Handle<JSReceiver> receiver(receiver_raw);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003264 Handle<Object> name(name_raw, isolate);
3265 Handle<Object> value(value_raw, isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003266
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003267 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3268 if (name->IsSymbol()) return *value;
3269
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003270 Handle<Object> args[] = { receiver, name, value };
3271 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003272 if (isolate->has_pending_exception()) return Failure::Exception();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003273
3274 return *value;
3275}
3276
3277
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003278MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyViaPrototypesWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +00003279 JSReceiver* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003280 Name* name_raw,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003281 Object* value_raw,
3282 PropertyAttributes attributes,
3283 StrictModeFlag strict_mode,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003284 bool* done) {
3285 Isolate* isolate = GetIsolate();
rossberg@chromium.org052b24a2012-06-11 12:32:17 +00003286 Handle<JSProxy> proxy(this);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003287 Handle<JSReceiver> receiver(receiver_raw);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003288 Handle<Name> name(name_raw);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003289 Handle<Object> value(value_raw, isolate);
3290 Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003291
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003292 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3293 if (name->IsSymbol()) {
3294 *done = false;
3295 return isolate->heap()->the_hole_value();
3296 }
3297
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003298 *done = true; // except where redefined...
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003299 Handle<Object> args[] = { name };
3300 Handle<Object> result = proxy->CallTrap(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003301 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003302 if (isolate->has_pending_exception()) return Failure::Exception();
3303
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003304 if (result->IsUndefined()) {
3305 *done = false;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003306 return isolate->heap()->the_hole_value();
rossberg@chromium.org400388e2012-06-06 09:29:22 +00003307 }
3308
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003309 // Emulate [[GetProperty]] semantics for proxies.
3310 bool has_pending_exception;
3311 Handle<Object> argv[] = { result };
3312 Handle<Object> desc =
3313 Execution::Call(isolate->to_complete_property_descriptor(), result,
3314 ARRAY_SIZE(argv), argv, &has_pending_exception);
3315 if (has_pending_exception) return Failure::Exception();
3316
3317 // [[GetProperty]] requires to check that all properties are configurable.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003318 Handle<String> configurable_name =
3319 isolate->factory()->InternalizeOneByteString(
3320 STATIC_ASCII_VECTOR("configurable_"));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003321 Handle<Object> configurable(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003322 v8::internal::GetProperty(isolate, desc, configurable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003323 ASSERT(!isolate->has_pending_exception());
3324 ASSERT(configurable->IsTrue() || configurable->IsFalse());
3325 if (configurable->IsFalse()) {
3326 Handle<String> trap =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003327 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003328 STATIC_ASCII_VECTOR("getPropertyDescriptor"));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003329 Handle<Object> args[] = { handler, trap, name };
3330 Handle<Object> error = isolate->factory()->NewTypeError(
3331 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
3332 return isolate->Throw(*error);
3333 }
3334 ASSERT(configurable->IsTrue());
3335
3336 // Check for DataDescriptor.
3337 Handle<String> hasWritable_name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003338 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003339 STATIC_ASCII_VECTOR("hasWritable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003340 Handle<Object> hasWritable(
3341 v8::internal::GetProperty(isolate, desc, hasWritable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003342 ASSERT(!isolate->has_pending_exception());
3343 ASSERT(hasWritable->IsTrue() || hasWritable->IsFalse());
3344 if (hasWritable->IsTrue()) {
3345 Handle<String> writable_name =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003346 isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003347 STATIC_ASCII_VECTOR("writable_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003348 Handle<Object> writable(
3349 v8::internal::GetProperty(isolate, desc, writable_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003350 ASSERT(!isolate->has_pending_exception());
3351 ASSERT(writable->IsTrue() || writable->IsFalse());
3352 *done = writable->IsFalse();
3353 if (!*done) return GetHeap()->the_hole_value();
3354 if (strict_mode == kNonStrictMode) return *value;
3355 Handle<Object> args[] = { name, receiver };
3356 Handle<Object> error = isolate->factory()->NewTypeError(
3357 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
3358 return isolate->Throw(*error);
3359 }
3360
3361 // We have an AccessorDescriptor.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003362 Handle<String> set_name = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003363 STATIC_ASCII_VECTOR("set_"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003364 Handle<Object> setter(v8::internal::GetProperty(isolate, desc, set_name));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003365 ASSERT(!isolate->has_pending_exception());
3366 if (!setter->IsUndefined()) {
3367 // TODO(rossberg): nicer would be to cast to some JSCallable here...
3368 return receiver->SetPropertyWithDefinedSetter(
3369 JSReceiver::cast(*setter), *value);
3370 }
3371
3372 if (strict_mode == kNonStrictMode) return *value;
3373 Handle<Object> args2[] = { name, proxy };
3374 Handle<Object> error = isolate->factory()->NewTypeError(
3375 "no_setter_in_callback", HandleVector(args2, ARRAY_SIZE(args2)));
3376 return isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003377}
3378
3379
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003380MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
ulan@chromium.org750145a2013-03-07 15:14:13 +00003381 Name* name_raw, DeleteMode mode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003382 Isolate* isolate = GetIsolate();
3383 HandleScope scope(isolate);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003384 Handle<JSProxy> receiver(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003385 Handle<Object> name(name_raw, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003386
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003387 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3388 if (name->IsSymbol()) return isolate->heap()->false_value();
3389
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003390 Handle<Object> args[] = { name };
3391 Handle<Object> result = CallTrap(
3392 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003393 if (isolate->has_pending_exception()) return Failure::Exception();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003394
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003395 bool result_bool = result->BooleanValue();
3396 if (mode == STRICT_DELETION && !result_bool) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003397 Handle<Object> handler(receiver->handler(), isolate);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003398 Handle<String> trap_name = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003399 STATIC_ASCII_VECTOR("delete"));
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00003400 Handle<Object> args[] = { handler, trap_name };
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003401 Handle<Object> error = isolate->factory()->NewTypeError(
3402 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
3403 isolate->Throw(*error);
3404 return Failure::Exception();
3405 }
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003406 return isolate->heap()->ToBoolean(result_bool);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003407}
3408
3409
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003410MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
3411 uint32_t index,
3412 DeleteMode mode) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003413 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003414 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003415 Handle<String> name = isolate->factory()->Uint32ToString(index);
3416 return JSProxy::DeletePropertyWithHandler(*name, mode);
3417}
3418
3419
3420MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
3421 JSReceiver* receiver_raw,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003422 Name* name_raw) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003423 Isolate* isolate = GetIsolate();
3424 HandleScope scope(isolate);
3425 Handle<JSProxy> proxy(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003426 Handle<Object> handler(this->handler(), isolate); // Trap might morph proxy.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003427 Handle<JSReceiver> receiver(receiver_raw);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003428 Handle<Object> name(name_raw, isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003429
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003430 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
3431 if (name->IsSymbol()) return ABSENT;
3432
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003433 Handle<Object> args[] = { name };
3434 Handle<Object> result = CallTrap(
3435 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003436 if (isolate->has_pending_exception()) return NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003437
3438 if (result->IsUndefined()) return ABSENT;
3439
3440 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003441 Handle<Object> argv[] = { result };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003442 Handle<Object> desc =
3443 Execution::Call(isolate->to_complete_property_descriptor(), result,
3444 ARRAY_SIZE(argv), argv, &has_pending_exception);
3445 if (has_pending_exception) return NONE;
3446
3447 // Convert result to PropertyAttributes.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003448 Handle<String> enum_n = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003449 STATIC_ASCII_VECTOR("enumerable"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003450 Handle<Object> enumerable(v8::internal::GetProperty(isolate, desc, enum_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003451 if (isolate->has_pending_exception()) return NONE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003452 Handle<String> conf_n = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003453 STATIC_ASCII_VECTOR("configurable"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003454 Handle<Object> configurable(v8::internal::GetProperty(isolate, desc, conf_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003455 if (isolate->has_pending_exception()) return NONE;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003456 Handle<String> writ_n = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003457 STATIC_ASCII_VECTOR("writable"));
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003458 Handle<Object> writable(v8::internal::GetProperty(isolate, desc, writ_n));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003459 if (isolate->has_pending_exception()) return NONE;
3460
3461 if (configurable->IsFalse()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003462 Handle<String> trap = isolate->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003463 STATIC_ASCII_VECTOR("getPropertyDescriptor"));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003464 Handle<Object> args[] = { handler, trap, name };
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003465 Handle<Object> error = isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003466 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003467 isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003468 return NONE;
3469 }
3470
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003471 int attributes = NONE;
svenpanne@chromium.org9faefa42013-03-08 13:13:16 +00003472 if (!enumerable->BooleanValue()) attributes |= DONT_ENUM;
3473 if (!configurable->BooleanValue()) attributes |= DONT_DELETE;
3474 if (!writable->BooleanValue()) attributes |= READ_ONLY;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003475 return static_cast<PropertyAttributes>(attributes);
3476}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003477
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003478
3479MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003480 JSReceiver* receiver_raw,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003481 uint32_t index) {
3482 Isolate* isolate = GetIsolate();
3483 HandleScope scope(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003484 Handle<JSProxy> proxy(this);
3485 Handle<JSReceiver> receiver(receiver_raw);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003486 Handle<String> name = isolate->factory()->Uint32ToString(index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003487 return proxy->GetPropertyAttributeWithHandler(*receiver, *name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003488}
3489
3490
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003491void JSProxy::Fix() {
3492 Isolate* isolate = GetIsolate();
3493 HandleScope scope(isolate);
3494 Handle<JSProxy> self(this);
3495
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003496 // Save identity hash.
3497 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
3498
lrn@chromium.org34e60782011-09-15 07:25:40 +00003499 if (IsJSFunctionProxy()) {
3500 isolate->factory()->BecomeJSFunction(self);
3501 // Code will be set on the JavaScript side.
3502 } else {
3503 isolate->factory()->BecomeJSObject(self);
3504 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003505 ASSERT(self->IsJSObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003506
3507 // Inherit identity, if it was present.
3508 Object* hash;
3509 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
3510 Handle<JSObject> new_self(JSObject::cast(*self));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003511 isolate->factory()->SetIdentityHash(new_self, Smi::cast(hash));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003512 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003513}
3514
3515
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003516MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
3517 Handle<Object> derived,
3518 int argc,
3519 Handle<Object> argv[]) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003520 Isolate* isolate = GetIsolate();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003521 Handle<Object> handler(this->handler(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003522
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003523 Handle<String> trap_name = isolate->factory()->InternalizeUtf8String(name);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003524 Handle<Object> trap(v8::internal::GetProperty(isolate, handler, trap_name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003525 if (isolate->has_pending_exception()) return trap;
3526
3527 if (trap->IsUndefined()) {
3528 if (derived.is_null()) {
3529 Handle<Object> args[] = { handler, trap_name };
3530 Handle<Object> error = isolate->factory()->NewTypeError(
3531 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
3532 isolate->Throw(*error);
3533 return Handle<Object>();
3534 }
3535 trap = Handle<Object>(derived);
3536 }
3537
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003538 bool threw;
3539 return Execution::Call(trap, handler, argc, argv, &threw);
3540}
3541
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003542
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003543void JSObject::AllocateStorageForMap(Handle<JSObject> object, Handle<Map> map) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003544 CALL_HEAP_FUNCTION_VOID(
3545 object->GetIsolate(),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003546 object->AllocateStorageForMap(*map));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003547}
3548
3549
danno@chromium.orgf005df62013-04-30 16:36:45 +00003550void JSObject::MigrateInstance(Handle<JSObject> object) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003551 if (FLAG_trace_migration) {
3552 PrintF("migrating instance %p (%p)\n",
3553 static_cast<void*>(*object),
3554 static_cast<void*>(object->map()));
3555 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003556 CALL_HEAP_FUNCTION_VOID(
3557 object->GetIsolate(),
3558 object->MigrateInstance());
3559}
3560
3561
3562Handle<Map> Map::GeneralizeRepresentation(Handle<Map> map,
3563 int modify_index,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003564 Representation representation) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003565 CALL_HEAP_FUNCTION(
3566 map->GetIsolate(),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003567 map->GeneralizeRepresentation(modify_index, representation),
danno@chromium.orgf005df62013-04-30 16:36:45 +00003568 Map);
3569}
3570
3571
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003572MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003573 Name* name_raw,
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003574 Object* value_raw,
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003575 PropertyAttributes attributes,
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003576 StrictModeFlag strict_mode,
3577 StoreFromKeyed store_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003578 Heap* heap = GetHeap();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003579 Isolate* isolate = heap->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003580 // Make sure that the top context does not change when doing callbacks or
3581 // interceptor calls.
3582 AssertNoContextChange ncc;
3583
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003584 // Optimization for 2-byte strings often used as keys in a decompression
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003585 // dictionary. We internalize these short keys to avoid constantly
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003586 // reallocating them.
ulan@chromium.org750145a2013-03-07 15:14:13 +00003587 if (name_raw->IsString() && !name_raw->IsInternalizedString() &&
3588 String::cast(name_raw)->length() <= 2) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003589 Object* internalized_version;
ulan@chromium.org750145a2013-03-07 15:14:13 +00003590 { MaybeObject* maybe_string_version =
3591 heap->InternalizeString(String::cast(name_raw));
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003592 if (maybe_string_version->ToObject(&internalized_version)) {
3593 name_raw = String::cast(internalized_version);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003594 }
3595 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003596 }
3597
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 // Check access rights if needed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003599 if (IsAccessCheckNeeded()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003600 if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003601 return SetPropertyWithFailedAccessCheck(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003602 lookup, name_raw, value_raw, true, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003605
3606 if (IsJSGlobalProxy()) {
3607 Object* proto = GetPrototype();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003608 if (proto->IsNull()) return value_raw;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003609 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003610 return JSObject::cast(proto)->SetPropertyForResult(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003611 lookup, name_raw, value_raw, attributes, strict_mode, store_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003612 }
3613
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003614 ASSERT(!lookup->IsFound() || lookup->holder() == this ||
3615 lookup->holder()->map()->is_hidden_prototype());
3616
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003617 // From this point on everything needs to be handlified, because
3618 // SetPropertyViaPrototypes might call back into JavaScript.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003619 HandleScope scope(isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003620 Handle<JSObject> self(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003621 Handle<Name> name(name_raw);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003622 Handle<Object> value(value_raw, isolate);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003623
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003624 if (!lookup->IsProperty() && !self->IsJSContextExtensionObject()) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003625 bool done = false;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003626 MaybeObject* result_object = self->SetPropertyViaPrototypes(
3627 *name, *value, attributes, strict_mode, &done);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00003628 if (done) return result_object;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003629 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003630
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003631 if (!lookup->IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003632 // Neither properties nor transitions found.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003633 return self->AddProperty(
3634 *name, *value, attributes, strict_mode, store_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003635 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003636
3637 if (lookup->IsProperty() && lookup->IsReadOnly()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003638 if (strict_mode == kStrictMode) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003639 Handle<Object> args[] = { name, self };
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003640 return isolate->Throw(*isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003641 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003642 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003643 return *value;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003644 }
3645 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003646
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003647 Handle<Object> old_value(heap->the_hole_value(), isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003648 if (FLAG_harmony_observation &&
3649 map()->is_observed() && lookup->IsDataProperty()) {
3650 old_value = Object::GetProperty(self, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003651 }
3652
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003653 // This is a real property that is not read-only, or it is a
3654 // transition or null descriptor and there are no setters in the prototypes.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003655 MaybeObject* result = *value;
3656 switch (lookup->type()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003657 case NORMAL:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003658 result = lookup->holder()->SetNormalizedProperty(lookup, *value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003659 break;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003660 case FIELD: {
3661 Representation representation = lookup->representation();
3662 if (!value->FitsRepresentation(representation)) {
3663 MaybeObject* maybe_failure =
3664 lookup->holder()->GeneralizeFieldRepresentation(
3665 lookup->GetDescriptorIndex(), value->OptimalRepresentation());
3666 if (maybe_failure->IsFailure()) return maybe_failure;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003667 DescriptorArray* desc = lookup->holder()->map()->instance_descriptors();
3668 int descriptor = lookup->GetDescriptorIndex();
3669 representation = desc->GetDetails(descriptor).representation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003670 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003671 if (FLAG_track_double_fields && representation.IsDouble()) {
3672 HeapNumber* storage =
3673 HeapNumber::cast(lookup->holder()->RawFastPropertyAt(
3674 lookup->GetFieldIndex().field_index()));
3675 storage->set_value(value->Number());
3676 result = *value;
3677 break;
3678 }
3679 lookup->holder()->FastPropertyAtPut(
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00003680 lookup->GetFieldIndex().field_index(), *value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003681 result = *value;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003682 break;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003683 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003685 // Only replace the function if necessary.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003686 if (*value == lookup->GetConstantFunction()) return *value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003687 // Preserve the attributes of this existing property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003688 attributes = lookup->GetAttributes();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003689 result =
3690 lookup->holder()->ConvertDescriptorToField(*name, *value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003691 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003692 case CALLBACKS: {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003693 Object* callback_object = lookup->GetCallbackObject();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003694 return self->SetPropertyWithCallback(
3695 callback_object, *name, *value, lookup->holder(), strict_mode);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00003696 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003697 case INTERCEPTOR:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003698 result = lookup->holder()->SetPropertyWithInterceptor(
3699 *name, *value, attributes, strict_mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003700 break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003701 case TRANSITION: {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003702 Map* transition_map = lookup->GetTransitionTarget();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003703 int descriptor = transition_map->LastAdded();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003704
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003705 DescriptorArray* descriptors = transition_map->instance_descriptors();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003706 PropertyDetails details = descriptors->GetDetails(descriptor);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003707
3708 if (details.type() == FIELD) {
3709 if (attributes == details.attributes()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003710 Representation representation = details.representation();
3711 if (!value->FitsRepresentation(representation)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003712 MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
3713 descriptor, value->OptimalRepresentation());
3714 if (!maybe_map->To(&transition_map)) return maybe_map;
3715 Object* back = transition_map->GetBackPointer();
3716 if (back->IsMap()) {
3717 MaybeObject* maybe_failure =
3718 lookup->holder()->MigrateToMap(Map::cast(back));
3719 if (maybe_failure->IsFailure()) return maybe_failure;
3720 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003721 DescriptorArray* desc = transition_map->instance_descriptors();
3722 int descriptor = transition_map->LastAdded();
3723 representation = desc->GetDetails(descriptor).representation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003724 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003725 int field_index = descriptors->GetFieldIndex(descriptor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003726 result = lookup->holder()->AddFastPropertyUsingMap(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003727 transition_map, *name, *value, field_index, representation);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003728 } else {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003729 result = lookup->holder()->ConvertDescriptorToField(
3730 *name, *value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003731 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003732 } else if (details.type() == CALLBACKS) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003733 result = lookup->holder()->ConvertDescriptorToField(
3734 *name, *value, attributes);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003735 } else {
3736 ASSERT(details.type() == CONSTANT_FUNCTION);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003737
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003738 Object* constant_function = descriptors->GetValue(descriptor);
3739 if (constant_function == *value) {
3740 // If the same constant function is being added we can simply
3741 // transition to the target map.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003742 lookup->holder()->set_map(transition_map);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003743 result = constant_function;
3744 } else {
3745 // Otherwise, replace with a map transition to a new map with a FIELD,
3746 // even if the value is a constant function.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003747 result = lookup->holder()->ConvertTransitionToMapTransition(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003748 lookup->GetTransitionIndex(), *name, *value, attributes);
3749 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003750 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003751 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003752 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003753 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003754 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003755 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003757
3758 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003759 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003760
3761 if (FLAG_harmony_observation && map()->is_observed()) {
3762 if (lookup->IsTransition()) {
3763 EnqueueChangeRecord(self, "new", name, old_value);
3764 } else {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003765 LookupResult new_lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003766 self->LocalLookup(*name, &new_lookup, true);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003767 if (new_lookup.IsDataProperty()) {
3768 Handle<Object> new_value = Object::GetProperty(self, name);
3769 if (!new_value->SameValue(*old_value)) {
3770 EnqueueChangeRecord(self, "updated", name, old_value);
3771 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003772 }
3773 }
3774 }
3775
3776 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777}
3778
3779
3780// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003781// present, add it with attributes NONE. This code is an exact clone of
3782// SetProperty, with the check for IsReadOnly and the check for a
3783// callback setter removed. The two lines looking up the LookupResult
3784// result are also added. If one of the functions is changed, the other
3785// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00003786// Note that this method cannot be used to set the prototype of a function
3787// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3788// doesn't handle function prototypes correctly.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003789Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3790 Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003791 Handle<Name> key,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003792 Handle<Object> value,
3793 PropertyAttributes attributes) {
3794 CALL_HEAP_FUNCTION(
3795 object->GetIsolate(),
3796 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3797 Object);
3798}
3799
3800
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003801MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
ulan@chromium.org750145a2013-03-07 15:14:13 +00003802 Name* name_raw,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003803 Object* value_raw,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003804 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805 // Make sure that the top context does not change when doing callbacks or
3806 // interceptor calls.
3807 AssertNoContextChange ncc;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003808 Isolate* isolate = GetIsolate();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003809 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003810 LocalLookup(name_raw, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003811 if (!lookup.IsFound()) map()->LookupTransition(this, name_raw, &lookup);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003813 if (IsAccessCheckNeeded()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003814 if (!isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) {
3815 return SetPropertyWithFailedAccessCheck(&lookup,
3816 name_raw,
3817 value_raw,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003818 false,
3819 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003820 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003821 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003822
3823 if (IsJSGlobalProxy()) {
3824 Object* proto = GetPrototype();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003825 if (proto->IsNull()) return value_raw;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003826 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003827 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003828 name_raw,
3829 value_raw,
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003830 attributes);
3831 }
3832
ager@chromium.org7c537e22008-10-16 08:43:32 +00003833 // Check for accessor in prototype chain removed here in clone.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003834 if (!lookup.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003835 // Neither properties nor transitions found.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003836 return AddProperty(name_raw, value_raw, attributes, kNonStrictMode);
3837 }
3838
3839 // From this point on everything needs to be handlified.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003840 HandleScope scope(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003841 Handle<JSObject> self(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00003842 Handle<Name> name(name_raw);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003843 Handle<Object> value(value_raw, isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003844
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003845 Handle<Object> old_value(isolate->heap()->the_hole_value(), isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003846 PropertyAttributes old_attributes = ABSENT;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00003847 bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
3848 if (is_observed) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00003849 if (lookup.IsDataProperty()) old_value = Object::GetProperty(self, name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003850 old_attributes = lookup.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003852
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003853 // Check of IsReadOnly removed from here in clone.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003854 MaybeObject* result = *value;
3855 switch (lookup.type()) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003856 case NORMAL: {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003857 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003858 result = self->SetNormalizedProperty(*name, *value, details);
3859 break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003860 }
danno@chromium.orgf005df62013-04-30 16:36:45 +00003861 case FIELD: {
3862 Representation representation = lookup.representation();
3863 if (!value->FitsRepresentation(representation)) {
3864 MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation(
3865 lookup.GetDescriptorIndex(), value->OptimalRepresentation());
3866 if (maybe_failure->IsFailure()) return maybe_failure;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003867 DescriptorArray* desc = self->map()->instance_descriptors();
3868 int descriptor = lookup.GetDescriptorIndex();
3869 representation = desc->GetDetails(descriptor).representation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003870 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003871 if (FLAG_track_double_fields && representation.IsDouble()) {
3872 HeapNumber* storage =
3873 HeapNumber::cast(self->RawFastPropertyAt(
3874 lookup.GetFieldIndex().field_index()));
3875 storage->set_value(value->Number());
3876 result = *value;
3877 break;
3878 }
3879 self->FastPropertyAtPut(lookup.GetFieldIndex().field_index(), *value);
3880 result = *value;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003881 break;
danno@chromium.orgf005df62013-04-30 16:36:45 +00003882 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003883 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003884 // Only replace the function if necessary.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003885 if (*value != lookup.GetConstantFunction()) {
3886 // Preserve the attributes of this existing property.
3887 attributes = lookup.GetAttributes();
3888 result = self->ConvertDescriptorToField(*name, *value, attributes);
3889 }
3890 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003891 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003892 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003893 // Override callback in clone
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003894 result = self->ConvertDescriptorToField(*name, *value, attributes);
3895 break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003896 case TRANSITION: {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003897 Map* transition_map = lookup.GetTransitionTarget();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00003898 int descriptor = transition_map->LastAdded();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003899
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003900 DescriptorArray* descriptors = transition_map->instance_descriptors();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003901 PropertyDetails details = descriptors->GetDetails(descriptor);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003902
3903 if (details.type() == FIELD) {
3904 if (attributes == details.attributes()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003905 Representation representation = details.representation();
3906 if (!value->FitsRepresentation(representation)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00003907 MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
3908 descriptor, value->OptimalRepresentation());
3909 if (!maybe_map->To(&transition_map)) return maybe_map;
3910 Object* back = transition_map->GetBackPointer();
3911 if (back->IsMap()) {
3912 MaybeObject* maybe_failure = self->MigrateToMap(Map::cast(back));
3913 if (maybe_failure->IsFailure()) return maybe_failure;
3914 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003915 DescriptorArray* desc = transition_map->instance_descriptors();
3916 int descriptor = transition_map->LastAdded();
3917 representation = desc->GetDetails(descriptor).representation();
danno@chromium.orgf005df62013-04-30 16:36:45 +00003918 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003919 int field_index = descriptors->GetFieldIndex(descriptor);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003920 result = self->AddFastPropertyUsingMap(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00003921 transition_map, *name, *value, field_index, representation);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003922 } else {
3923 result = self->ConvertDescriptorToField(*name, *value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003924 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003925 } else if (details.type() == CALLBACKS) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003926 result = self->ConvertDescriptorToField(*name, *value, attributes);
3927 } else {
3928 ASSERT(details.type() == CONSTANT_FUNCTION);
3929
3930 // Replace transition to CONSTANT FUNCTION with a map transition to a
3931 // new map with a FIELD, even if the value is a function.
3932 result = self->ConvertTransitionToMapTransition(
3933 lookup.GetTransitionIndex(), *name, *value, attributes);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003934 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003935 break;
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00003936 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003937 case HANDLER:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00003938 case NONEXISTENT:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003939 UNREACHABLE();
3940 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003941
3942 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00003943 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003944
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00003945 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003946 if (lookup.IsTransition()) {
3947 EnqueueChangeRecord(self, "new", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003948 } else if (old_value->IsTheHole()) {
3949 EnqueueChangeRecord(self, "reconfigured", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003950 } else {
3951 LookupResult new_lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00003952 self->LocalLookup(*name, &new_lookup, true);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00003953 bool value_changed = false;
3954 if (new_lookup.IsDataProperty()) {
3955 Handle<Object> new_value = Object::GetProperty(self, name);
3956 value_changed = !old_value->SameValue(*new_value);
3957 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003958 if (new_lookup.GetAttributes() != old_attributes) {
3959 if (!value_changed) old_value = isolate->factory()->the_hole_value();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003960 EnqueueChangeRecord(self, "reconfigured", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00003961 } else if (value_changed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00003962 EnqueueChangeRecord(self, "updated", name, old_value);
3963 }
3964 }
3965 }
3966
3967 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968}
3969
3970
3971PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3972 JSObject* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003973 Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 bool continue_search) {
3975 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003976 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00003978 if (result.IsFound()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979
3980 if (continue_search) {
3981 // Continue searching via the prototype chain.
3982 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003983 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 return JSObject::cast(pt)->
3985 GetPropertyAttributeWithReceiver(receiver, name);
3986 }
3987 }
3988 return ABSENT;
3989}
3990
3991
3992PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3993 JSObject* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00003994 Name* name,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 bool continue_search) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00003996 // TODO(rossberg): Support symbols in the API.
3997 if (name->IsSymbol()) return ABSENT;
3998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 Isolate* isolate = GetIsolate();
4000
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 // Make sure that the top context does not change when doing
4002 // callbacks or interceptor calls.
4003 AssertNoContextChange ncc;
4004
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004005 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
4007 Handle<JSObject> receiver_handle(receiver);
4008 Handle<JSObject> holder_handle(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004009 Handle<String> name_handle(String::cast(name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004010 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004011 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004013 v8::NamedPropertyQuery query =
4014 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004015 LOG(isolate,
4016 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004017 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 {
4019 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004020 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 result = query(v8::Utils::ToLocal(name_handle), info);
4022 }
4023 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004024 ASSERT(result->IsInt32());
4025 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 }
4027 } else if (!interceptor->getter()->IsUndefined()) {
4028 v8::NamedPropertyGetter getter =
4029 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004030 LOG(isolate,
4031 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 v8::Handle<v8::Value> result;
4033 {
4034 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004035 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004036 result = getter(v8::Utils::ToLocal(name_handle), info);
4037 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004038 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 }
4040 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
4041 *name_handle,
4042 continue_search);
4043}
4044
4045
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004046PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
4047 JSReceiver* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004048 Name* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004049 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004050 if (IsJSObject() && key->AsArrayIndex(&index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004051 return JSObject::cast(this)->GetElementAttributeWithReceiver(
4052 receiver, index, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 }
4054 // Named property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004055 LookupResult lookup(GetIsolate());
4056 Lookup(key, &lookup);
4057 return GetPropertyAttributeForResult(receiver, &lookup, key, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004058}
4059
4060
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004061PropertyAttributes JSReceiver::GetPropertyAttributeForResult(
4062 JSReceiver* receiver,
4063 LookupResult* lookup,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004064 Name* name,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004065 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004067 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004068 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004069 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004070 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
4071 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004072 receiver, lookup, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004073 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004075 if (lookup->IsFound()) {
4076 switch (lookup->type()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 case NORMAL: // fall through
4078 case FIELD:
4079 case CONSTANT_FUNCTION:
4080 case CALLBACKS:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004081 return lookup->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004082 case HANDLER: {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004083 return JSProxy::cast(lookup->proxy())->GetPropertyAttributeWithHandler(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004084 receiver, name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004085 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 case INTERCEPTOR:
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004087 return lookup->holder()->GetPropertyAttributeWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004088 JSObject::cast(receiver), name, continue_search);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004089 case TRANSITION:
4090 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004091 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 }
4093 }
4094 return ABSENT;
4095}
4096
4097
ulan@chromium.org750145a2013-03-07 15:14:13 +00004098PropertyAttributes JSReceiver::GetLocalPropertyAttribute(Name* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004100 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004101 if (IsJSObject() && name->AsArrayIndex(&index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004102 return GetLocalElementAttribute(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004103 }
4104 // Named property.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004105 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00004106 LocalLookup(name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004107 return GetPropertyAttributeForResult(this, &lookup, name, false);
4108}
4109
4110
4111PropertyAttributes JSObject::GetElementAttributeWithReceiver(
4112 JSReceiver* receiver, uint32_t index, bool continue_search) {
4113 Isolate* isolate = GetIsolate();
4114
4115 // Check access rights if needed.
4116 if (IsAccessCheckNeeded()) {
4117 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
4118 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4119 return ABSENT;
4120 }
4121 }
4122
4123 if (IsJSGlobalProxy()) {
4124 Object* proto = GetPrototype();
4125 if (proto->IsNull()) return ABSENT;
4126 ASSERT(proto->IsJSGlobalObject());
4127 return JSObject::cast(proto)->GetElementAttributeWithReceiver(
4128 receiver, index, continue_search);
4129 }
4130
4131 // Check for lookup interceptor except when bootstrapping.
4132 if (HasIndexedInterceptor() && !isolate->bootstrapper()->IsActive()) {
4133 return GetElementAttributeWithInterceptor(receiver, index, continue_search);
4134 }
4135
4136 return GetElementAttributeWithoutInterceptor(
4137 receiver, index, continue_search);
4138}
4139
4140
4141PropertyAttributes JSObject::GetElementAttributeWithInterceptor(
4142 JSReceiver* receiver, uint32_t index, bool continue_search) {
4143 Isolate* isolate = GetIsolate();
4144 // Make sure that the top context does not change when doing
4145 // callbacks or interceptor calls.
4146 AssertNoContextChange ncc;
4147 HandleScope scope(isolate);
4148 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
4149 Handle<JSReceiver> hreceiver(receiver);
4150 Handle<JSObject> holder(this);
4151 CustomArguments args(isolate, interceptor->data(), receiver, this);
4152 v8::AccessorInfo info(args.end());
4153 if (!interceptor->query()->IsUndefined()) {
4154 v8::IndexedPropertyQuery query =
4155 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
4156 LOG(isolate,
4157 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
4158 v8::Handle<v8::Integer> result;
4159 {
4160 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004161 VMState<EXTERNAL> state(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004162 result = query(index, info);
4163 }
4164 if (!result.IsEmpty())
4165 return static_cast<PropertyAttributes>(result->Int32Value());
4166 } else if (!interceptor->getter()->IsUndefined()) {
4167 v8::IndexedPropertyGetter getter =
4168 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
4169 LOG(isolate,
4170 ApiIndexedPropertyAccess("interceptor-indexed-get-has", this, index));
4171 v8::Handle<v8::Value> result;
4172 {
4173 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004174 VMState<EXTERNAL> state(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004175 result = getter(index, info);
4176 }
danno@chromium.org1f34ad32012-11-26 14:53:56 +00004177 if (!result.IsEmpty()) return NONE;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004178 }
4179
4180 return holder->GetElementAttributeWithoutInterceptor(
4181 *hreceiver, index, continue_search);
4182}
4183
4184
4185PropertyAttributes JSObject::GetElementAttributeWithoutInterceptor(
4186 JSReceiver* receiver, uint32_t index, bool continue_search) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004187 PropertyAttributes attr = GetElementsAccessor()->GetAttributes(
4188 receiver, this, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004189 if (attr != ABSENT) return attr;
4190
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004191 // Handle [] on String objects.
4192 if (IsStringObjectWithCharacterAt(index)) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004193 return static_cast<PropertyAttributes>(READ_ONLY | DONT_DELETE);
4194 }
4195
4196 if (!continue_search) return ABSENT;
4197
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004198 Object* pt = GetPrototype();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004199 if (pt->IsJSProxy()) {
4200 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004201 return JSProxy::cast(pt)->GetElementAttributeWithHandler(receiver, index);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004202 }
4203 if (pt->IsNull()) return ABSENT;
4204 return JSObject::cast(pt)->GetElementAttributeWithReceiver(
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00004205 receiver, index, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004206}
4207
4208
lrn@chromium.org303ada72010-10-27 09:33:13 +00004209MaybeObject* NormalizedMapCache::Get(JSObject* obj,
4210 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004211 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004212 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004213 int index = fast->Hash() % kEntries;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004214 Object* result = get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004215 if (result->IsMap() &&
4216 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004217#ifdef VERIFY_HEAP
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004218 if (FLAG_verify_heap) {
4219 Map::cast(result)->SharedMapVerify();
4220 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00004221#endif
4222#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004223 if (FLAG_enable_slow_asserts) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004224 // The cached map should match newly created normalized map bit-by-bit,
4225 // except for the code cache, which can contain some ics which can be
4226 // applied to the shared map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004227 Object* fresh;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004228 MaybeObject* maybe_fresh =
4229 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
4230 if (maybe_fresh->ToObject(&fresh)) {
4231 ASSERT(memcmp(Map::cast(fresh)->address(),
4232 Map::cast(result)->address(),
4233 Map::kCodeCacheOffset) == 0);
ulan@chromium.org750145a2013-03-07 15:14:13 +00004234 STATIC_ASSERT(Map::kDependentCodeOffset ==
4235 Map::kCodeCacheOffset + kPointerSize);
4236 int offset = Map::kDependentCodeOffset + kPointerSize;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00004237 ASSERT(memcmp(Map::cast(fresh)->address() + offset,
4238 Map::cast(result)->address() + offset,
4239 Map::kSize - offset) == 0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004240 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004241 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004242#endif
4243 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004244 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004245
lrn@chromium.org303ada72010-10-27 09:33:13 +00004246 { MaybeObject* maybe_result =
4247 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
4248 if (!maybe_result->ToObject(&result)) return maybe_result;
4249 }
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004250 ASSERT(Map::cast(result)->is_dictionary_map());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004251 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004252 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004253
4254 return result;
4255}
4256
4257
ricow@chromium.org65fae842010-08-25 15:26:24 +00004258void NormalizedMapCache::Clear() {
4259 int entries = length();
4260 for (int i = 0; i != entries; i++) {
4261 set_undefined(i);
4262 }
4263}
4264
4265
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004266void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004267 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004268 Handle<Code> code) {
4269 Isolate* isolate = object->GetIsolate();
4270 CALL_HEAP_FUNCTION_VOID(isolate,
4271 object->UpdateMapCodeCache(*name, *code));
4272}
4273
4274
ulan@chromium.org750145a2013-03-07 15:14:13 +00004275MaybeObject* JSObject::UpdateMapCodeCache(Name* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004276 if (map()->is_shared()) {
4277 // Fast case maps are never marked as shared.
4278 ASSERT(!HasFastProperties());
4279 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004280 Object* obj;
4281 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
4282 UNIQUE_NORMALIZED_MAP);
4283 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4284 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004285 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004286
4287 set_map(Map::cast(obj));
4288 }
4289 return map()->UpdateCodeCache(name, code);
4290}
4291
4292
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004293void JSObject::NormalizeProperties(Handle<JSObject> object,
4294 PropertyNormalizationMode mode,
4295 int expected_additional_properties) {
4296 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
4297 object->NormalizeProperties(
4298 mode, expected_additional_properties));
4299}
4300
4301
lrn@chromium.org303ada72010-10-27 09:33:13 +00004302MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
4303 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004304 if (!HasFastProperties()) return this;
4305
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004306 // The global object is always normalized.
4307 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004308 // JSGlobalProxy must never be normalized
4309 ASSERT(!IsJSGlobalProxy());
4310
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004311 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004313 // Allocate new content.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004314 int real_size = map_of_this->NumberOfOwnDescriptors();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00004315 int property_count = real_size;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004316 if (expected_additional_properties > 0) {
4317 property_count += expected_additional_properties;
4318 } else {
4319 property_count += 2; // Make space for two more properties.
4320 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00004321 NameDictionary* dictionary;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004322 MaybeObject* maybe_dictionary =
4323 NameDictionary::Allocate(GetHeap(), property_count);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004324 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004326 DescriptorArray* descs = map_of_this->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004327 for (int i = 0; i < real_size; i++) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004328 PropertyDetails details = descs->GetDetails(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 switch (details.type()) {
4330 case CONSTANT_FUNCTION: {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004331 PropertyDetails d = PropertyDetails(
4332 details.attributes(), NORMAL, i + 1);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004333 Object* value = descs->GetConstantFunction(i);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004334 MaybeObject* maybe_dictionary =
4335 dictionary->Add(descs->GetKey(i), value, d);
4336 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004337 break;
4338 }
4339 case FIELD: {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004340 PropertyDetails d =
4341 PropertyDetails(details.attributes(), NORMAL, i + 1);
4342 Object* value = RawFastPropertyAt(descs->GetFieldIndex(i));
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004343 MaybeObject* maybe_dictionary =
4344 dictionary->Add(descs->GetKey(i), value, d);
4345 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346 break;
4347 }
4348 case CALLBACKS: {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004349 Object* value = descs->GetCallbacksObject(i);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004350 PropertyDetails d = PropertyDetails(
4351 details.attributes(), CALLBACKS, i + 1);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004352 MaybeObject* maybe_dictionary =
danno@chromium.orgf005df62013-04-30 16:36:45 +00004353 dictionary->Add(descs->GetKey(i), value, d);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004354 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355 break;
4356 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004357 case INTERCEPTOR:
4358 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00004359 case HANDLER:
4360 case NORMAL:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00004361 case TRANSITION:
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00004362 case NONEXISTENT:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004363 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00004364 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365 }
4366 }
4367
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004368 Heap* current_heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004370 // Copy the next enumeration index from instance descriptor.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004371 dictionary->SetNextEnumerationIndex(real_size + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004372
ulan@chromium.org65a89c22012-02-14 11:46:07 +00004373 Map* new_map;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004374 MaybeObject* maybe_map =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004375 current_heap->isolate()->context()->native_context()->
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00004376 normalized_map_cache()->Get(this, mode);
4377 if (!maybe_map->To(&new_map)) return maybe_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00004378 ASSERT(new_map->is_dictionary_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004379
ager@chromium.org32912102009-01-16 10:38:43 +00004380 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004381 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00004382
4383 // Resize the object in the heap if necessary.
4384 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004385 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004386 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004387 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
4388 instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004389 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004390 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
4391 -instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004392 }
4393
ager@chromium.org32912102009-01-16 10:38:43 +00004394 set_map(new_map);
ulan@chromium.org2e04b582013-02-21 14:06:02 +00004395 map_of_this->NotifyLeafMapLayoutChange();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004397 set_properties(dictionary);
4398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004399 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400
4401#ifdef DEBUG
4402 if (FLAG_trace_normalization) {
4403 PrintF("Object properties have been normalized:\n");
4404 Print();
4405 }
4406#endif
4407 return this;
4408}
4409
4410
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004411void JSObject::TransformToFastProperties(Handle<JSObject> object,
4412 int unused_property_fields) {
4413 CALL_HEAP_FUNCTION_VOID(
4414 object->GetIsolate(),
4415 object->TransformToFastProperties(unused_property_fields));
4416}
4417
4418
lrn@chromium.org303ada72010-10-27 09:33:13 +00004419MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004420 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004421 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004423 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004424}
4425
4426
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004427Handle<SeededNumberDictionary> JSObject::NormalizeElements(
4428 Handle<JSObject> object) {
4429 CALL_HEAP_FUNCTION(object->GetIsolate(),
4430 object->NormalizeElements(),
4431 SeededNumberDictionary);
4432}
4433
4434
lrn@chromium.org303ada72010-10-27 09:33:13 +00004435MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004436 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00004437
whesse@chromium.org7b260152011-06-20 15:33:18 +00004438 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004439 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004440 Map* old_map = array->map();
4441 bool is_arguments =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004442 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004443 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004444 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004445 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004446 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004448 ASSERT(HasFastSmiOrObjectElements() ||
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004449 HasFastDoubleElements() ||
4450 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00004451 // Compute the effective length and allocate a new backing store.
4452 int length = IsJSArray()
4453 ? Smi::cast(JSArray::cast(this)->length())->value()
4454 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00004455 int old_capacity = 0;
4456 int used_elements = 0;
4457 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004458 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004459 { Object* object;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004460 MaybeObject* maybe =
4461 SeededNumberDictionary::Allocate(GetHeap(), used_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004462 if (!maybe->ToObject(&object)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004463 dictionary = SeededNumberDictionary::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004464 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004465
4466 // Copy the elements to the new backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004467 bool has_double_elements = array->IsFixedDoubleArray();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 for (int i = 0; i < length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004469 Object* value = NULL;
4470 if (has_double_elements) {
4471 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
4472 if (double_array->is_the_hole(i)) {
4473 value = GetIsolate()->heap()->the_hole_value();
4474 } else {
4475 // Objects must be allocated in the old object space, since the
4476 // overall number of HeapNumbers needed for the conversion might
4477 // exceed the capacity of new space, and we would fail repeatedly
4478 // trying to convert the FixedDoubleArray.
4479 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004480 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004481 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004482 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004483 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00004484 ASSERT(old_map->has_fast_smi_or_object_elements());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004485 value = FixedArray::cast(array)->get(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004486 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004487 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004488 if (!value->IsTheHole()) {
4489 Object* result;
4490 MaybeObject* maybe_result =
4491 dictionary->AddNumberEntry(i, value, details);
4492 if (!maybe_result->ToObject(&result)) return maybe_result;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004493 dictionary = SeededNumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004494 }
4495 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004496
whesse@chromium.org7b260152011-06-20 15:33:18 +00004497 // Switch to using the dictionary as the backing storage for elements.
4498 if (is_arguments) {
4499 FixedArray::cast(elements())->set(1, dictionary);
4500 } else {
4501 // Set the new map first to satify the elements type assert in
4502 // set_elements().
4503 Object* new_map;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00004504 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
4505 DICTIONARY_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004506 if (!maybe->ToObject(&new_map)) return maybe;
4507 set_map(Map::cast(new_map));
4508 set_elements(dictionary);
4509 }
4510
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004511 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
4512 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004513
4514#ifdef DEBUG
4515 if (FLAG_trace_normalization) {
4516 PrintF("Object elements have been normalized:\n");
4517 Print();
4518 }
4519#endif
4520
whesse@chromium.org7b260152011-06-20 15:33:18 +00004521 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
4522 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523}
4524
4525
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004526Smi* JSReceiver::GenerateIdentityHash() {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004527 Isolate* isolate = GetIsolate();
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004528
4529 int hash_value;
4530 int attempts = 0;
4531 do {
4532 // Generate a random 32-bit hash value but limit range to fit
4533 // within a smi.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004534 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004535 attempts++;
4536 } while (hash_value == 0 && attempts < 30);
4537 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
4538
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004539 return Smi::FromInt(hash_value);
4540}
4541
4542
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004543MaybeObject* JSObject::SetIdentityHash(Smi* hash, CreationFlag flag) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004544 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_string(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004545 hash);
4546 if (maybe->IsFailure()) return maybe;
4547 return this;
4548}
4549
4550
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004551int JSObject::GetIdentityHash(Handle<JSObject> obj) {
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00004552 CALL_AND_RETRY_OR_DIE(obj->GetIsolate(),
4553 obj->GetIdentityHash(ALLOW_CREATION),
4554 return Smi::cast(__object__)->value(),
4555 return 0);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004556}
4557
4558
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004559MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004560 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_string());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004561 if (stored_value->IsSmi()) return stored_value;
4562
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004563 // Do not generate permanent identity hash code if not requested.
4564 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
4565
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004566 Smi* hash = GenerateIdentityHash();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004567 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_string(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004568 hash);
4569 if (result->IsFailure()) return result;
4570 if (result->ToObjectUnchecked()->IsUndefined()) {
4571 // Trying to get hash of detached proxy.
4572 return Smi::FromInt(0);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004573 }
4574 return hash;
4575}
4576
4577
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004578MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
4579 Object* hash = this->hash();
4580 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
4581 hash = GenerateIdentityHash();
4582 set_hash(hash);
4583 }
4584 return hash;
4585}
4586
4587
ulan@chromium.org750145a2013-03-07 15:14:13 +00004588Object* JSObject::GetHiddenProperty(Name* key) {
4589 ASSERT(key->IsUniqueName());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004590 if (IsJSGlobalProxy()) {
4591 // For a proxy, use the prototype as target object.
4592 Object* proxy_parent = GetPrototype();
4593 // If the proxy is detached, return undefined.
4594 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
4595 ASSERT(proxy_parent->IsJSGlobalObject());
4596 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
4597 }
4598 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004599 MaybeObject* hidden_lookup =
4600 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004601 Object* inline_value = hidden_lookup->ToObjectUnchecked();
4602
4603 if (inline_value->IsSmi()) {
4604 // Handle inline-stored identity hash.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004605 if (key == GetHeap()->identity_hash_string()) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004606 return inline_value;
4607 } else {
4608 return GetHeap()->undefined_value();
4609 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004610 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004611
4612 if (inline_value->IsUndefined()) return GetHeap()->undefined_value();
4613
4614 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
4615 Object* entry = hashtable->Lookup(key);
4616 if (entry->IsTheHole()) return GetHeap()->undefined_value();
4617 return entry;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004618}
4619
4620
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004621Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004622 Handle<Name> key,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004623 Handle<Object> value) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004624 CALL_HEAP_FUNCTION(obj->GetIsolate(),
4625 obj->SetHiddenProperty(*key, *value),
4626 Object);
4627}
4628
4629
ulan@chromium.org750145a2013-03-07 15:14:13 +00004630MaybeObject* JSObject::SetHiddenProperty(Name* key, Object* value) {
4631 ASSERT(key->IsUniqueName());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004632 if (IsJSGlobalProxy()) {
4633 // For a proxy, use the prototype as target object.
4634 Object* proxy_parent = GetPrototype();
4635 // If the proxy is detached, return undefined.
4636 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
4637 ASSERT(proxy_parent->IsJSGlobalObject());
4638 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
4639 }
4640 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004641 MaybeObject* hidden_lookup =
4642 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004643 Object* inline_value = hidden_lookup->ToObjectUnchecked();
4644
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004645 // If there is no backing store yet, store the identity hash inline.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004646 if (value->IsSmi() &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004647 key == GetHeap()->identity_hash_string() &&
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004648 (inline_value->IsUndefined() || inline_value->IsSmi())) {
4649 return SetHiddenPropertiesHashTable(value);
4650 }
4651
4652 hidden_lookup = GetHiddenPropertiesHashTable(CREATE_NEW_IF_ABSENT);
4653 ObjectHashTable* hashtable;
4654 if (!hidden_lookup->To(&hashtable)) return hidden_lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004655
4656 // If it was found, check if the key is already in the dictionary.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004657 MaybeObject* insert_result = hashtable->Put(key, value);
4658 ObjectHashTable* new_table;
4659 if (!insert_result->To(&new_table)) return insert_result;
4660 if (new_table != hashtable) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004661 // If adding the key expanded the dictionary (i.e., Add returned a new
4662 // dictionary), store it back to the object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004663 MaybeObject* store_result = SetHiddenPropertiesHashTable(new_table);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004664 if (store_result->IsFailure()) return store_result;
4665 }
4666 // Return this to mark success.
4667 return this;
4668}
4669
4670
ulan@chromium.org750145a2013-03-07 15:14:13 +00004671void JSObject::DeleteHiddenProperty(Name* key) {
4672 ASSERT(key->IsUniqueName());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004673 if (IsJSGlobalProxy()) {
4674 // For a proxy, use the prototype as target object.
4675 Object* proxy_parent = GetPrototype();
4676 // If the proxy is detached, return immediately.
4677 if (proxy_parent->IsNull()) return;
4678 ASSERT(proxy_parent->IsJSGlobalObject());
4679 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
4680 return;
4681 }
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004682 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004683 MaybeObject* hidden_lookup =
4684 GetHiddenPropertiesHashTable(ONLY_RETURN_INLINE_VALUE);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004685 Object* inline_value = hidden_lookup->ToObjectUnchecked();
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004686
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004687 // We never delete (inline-stored) identity hashes.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004688 ASSERT(key != GetHeap()->identity_hash_string());
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004689 if (inline_value->IsUndefined() || inline_value->IsSmi()) return;
4690
4691 ObjectHashTable* hashtable = ObjectHashTable::cast(inline_value);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004692 MaybeObject* delete_result = hashtable->Put(key, GetHeap()->the_hole_value());
4693 USE(delete_result);
4694 ASSERT(!delete_result->IsFailure()); // Delete does not cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004695}
4696
4697
4698bool JSObject::HasHiddenProperties() {
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00004699 return GetPropertyAttributePostInterceptor(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004700 GetHeap()->hidden_string(),
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00004701 false) != ABSENT;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004702}
4703
4704
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004705MaybeObject* JSObject::GetHiddenPropertiesHashTable(
4706 InitializeHiddenProperties init_option) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004707 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004708 Object* inline_value;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004709 if (HasFastProperties()) {
4710 // If the object has fast properties, check whether the first slot
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004711 // in the descriptor array matches the hidden string. Since the
ulan@chromium.org750145a2013-03-07 15:14:13 +00004712 // hidden strings hash code is zero (and no other name has hash
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004713 // code zero) it will always occupy the first entry if present.
4714 DescriptorArray* descriptors = this->map()->instance_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004715 if (descriptors->number_of_descriptors() > 0) {
4716 int sorted_index = descriptors->GetSortedKeyIndex(0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004717 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004718 sorted_index < map()->NumberOfOwnDescriptors()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004719 ASSERT(descriptors->GetType(sorted_index) == FIELD);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004720 MaybeObject* maybe_value = this->FastPropertyAt(
4721 descriptors->GetDetails(sorted_index).representation(),
4722 descriptors->GetFieldIndex(sorted_index));
4723 if (!maybe_value->To(&inline_value)) return maybe_value;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004724 } else {
4725 inline_value = GetHeap()->undefined_value();
4726 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004727 } else {
4728 inline_value = GetHeap()->undefined_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004729 }
4730 } else {
4731 PropertyAttributes attributes;
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004732 // You can't install a getter on a property indexed by the hidden string,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004733 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
4734 // object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004735 inline_value =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004736 GetLocalPropertyPostInterceptor(this,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004737 GetHeap()->hidden_string(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004738 &attributes)->ToObjectUnchecked();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004739 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004740
4741 if (init_option == ONLY_RETURN_INLINE_VALUE ||
4742 inline_value->IsHashTable()) {
4743 return inline_value;
4744 }
4745
4746 ObjectHashTable* hashtable;
4747 static const int kInitialCapacity = 4;
4748 MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00004749 ObjectHashTable::Allocate(GetHeap(),
4750 kInitialCapacity,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004751 ObjectHashTable::USE_CUSTOM_MINIMUM_CAPACITY);
4752 if (!maybe_obj->To<ObjectHashTable>(&hashtable)) return maybe_obj;
4753
4754 if (inline_value->IsSmi()) {
4755 // We were storing the identity hash inline and now allocated an actual
4756 // dictionary. Put the identity hash into the new dictionary.
4757 MaybeObject* insert_result =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004758 hashtable->Put(GetHeap()->identity_hash_string(), inline_value);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004759 ObjectHashTable* new_table;
4760 if (!insert_result->To(&new_table)) return insert_result;
4761 // We expect no resizing for the first insert.
4762 ASSERT_EQ(hashtable, new_table);
4763 }
4764
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00004765 MaybeObject* store_result =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004766 SetPropertyPostInterceptor(GetHeap()->hidden_string(),
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004767 hashtable,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00004768 DONT_ENUM,
4769 kNonStrictMode,
4770 OMIT_EXTENSIBILITY_CHECK);
4771 if (store_result->IsFailure()) return store_result;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004772 return hashtable;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004773}
4774
4775
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004776MaybeObject* JSObject::SetHiddenPropertiesHashTable(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004777 ASSERT(!IsJSGlobalProxy());
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004778 // We can store the identity hash inline iff there is no backing store
4779 // for hidden properties yet.
4780 ASSERT(HasHiddenProperties() != value->IsSmi());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004781 if (HasFastProperties()) {
4782 // If the object has fast properties, check whether the first slot
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004783 // in the descriptor array matches the hidden string. Since the
ulan@chromium.org750145a2013-03-07 15:14:13 +00004784 // hidden strings hash code is zero (and no other name has hash
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004785 // code zero) it will always occupy the first entry if present.
4786 DescriptorArray* descriptors = this->map()->instance_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004787 if (descriptors->number_of_descriptors() > 0) {
4788 int sorted_index = descriptors->GetSortedKeyIndex(0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004789 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_string() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00004790 sorted_index < map()->NumberOfOwnDescriptors()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004791 ASSERT(descriptors->GetType(sorted_index) == FIELD);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00004792 FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), value);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004793 return this;
4794 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004795 }
4796 }
4797 MaybeObject* store_result =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004798 SetPropertyPostInterceptor(GetHeap()->hidden_string(),
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00004799 value,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004800 DONT_ENUM,
mstarzinger@chromium.orgccab3672012-06-14 15:01:16 +00004801 kNonStrictMode,
4802 OMIT_EXTENSIBILITY_CHECK);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004803 if (store_result->IsFailure()) return store_result;
4804 return this;
4805}
4806
4807
ulan@chromium.org750145a2013-03-07 15:14:13 +00004808MaybeObject* JSObject::DeletePropertyPostInterceptor(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004809 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004810 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004811 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004813 if (!result.IsFound()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814
4815 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004816 Object* obj;
4817 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4818 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004821 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822}
4823
4824
ulan@chromium.org750145a2013-03-07 15:14:13 +00004825MaybeObject* JSObject::DeletePropertyWithInterceptor(Name* name) {
4826 // TODO(rossberg): Support symbols in the API.
4827 if (name->IsSymbol()) return GetHeap()->false_value();
4828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004829 Isolate* isolate = GetIsolate();
4830 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004831 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
ulan@chromium.org750145a2013-03-07 15:14:13 +00004832 Handle<String> name_handle(String::cast(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 Handle<JSObject> this_handle(this);
4834 if (!interceptor->deleter()->IsUndefined()) {
4835 v8::NamedPropertyDeleter deleter =
4836 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004837 LOG(isolate,
4838 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
4839 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004840 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 v8::Handle<v8::Boolean> result;
4842 {
4843 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004844 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845 result = deleter(v8::Utils::ToLocal(name_handle), info);
4846 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004847 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 if (!result.IsEmpty()) {
4849 ASSERT(result->IsBoolean());
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004850 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4851 result_internal->VerifyApiCallResultType();
4852 return *result_internal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853 }
4854 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004855 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00004856 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004857 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 return raw_result;
4859}
4860
4861
lrn@chromium.org303ada72010-10-27 09:33:13 +00004862MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004863 Isolate* isolate = GetIsolate();
4864 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865 // Make sure that the top context does not change when doing
4866 // callbacks or interceptor calls.
4867 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004868 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004870 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004871 v8::IndexedPropertyDeleter deleter =
4872 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
4873 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004874 LOG(isolate,
4875 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
4876 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004877 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 v8::Handle<v8::Boolean> result;
4879 {
4880 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004881 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004882 result = deleter(index, info);
4883 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004884 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885 if (!result.IsEmpty()) {
4886 ASSERT(result->IsBoolean());
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00004887 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
4888 result_internal->VerifyApiCallResultType();
4889 return *result_internal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00004891 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
4892 *this_handle,
4893 index,
4894 NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004895 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004896 return raw_result;
4897}
4898
4899
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004900Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
4901 uint32_t index) {
4902 CALL_HEAP_FUNCTION(obj->GetIsolate(),
4903 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
4904 Object);
4905}
4906
4907
lrn@chromium.org303ada72010-10-27 09:33:13 +00004908MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004909 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004910 // Check access rights if needed.
4911 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004912 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
4913 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
4914 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004915 }
4916
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004917 if (IsStringObjectWithCharacterAt(index)) {
4918 if (mode == STRICT_DELETION) {
4919 // Deleting a non-configurable property in strict mode.
4920 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00004921 Handle<Object> holder(this, isolate);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00004922 Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
4923 Handle<Object> args[2] = { name, holder };
4924 Handle<Object> error =
4925 isolate->factory()->NewTypeError("strict_delete_property",
4926 HandleVector(args, 2));
4927 return isolate->Throw(*error);
4928 }
4929 return isolate->heap()->false_value();
4930 }
4931
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004932 if (IsJSGlobalProxy()) {
4933 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004934 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004935 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00004936 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004937 }
4938
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004939 // From this point on everything needs to be handlified.
4940 HandleScope scope(isolate);
4941 Handle<JSObject> self(this);
4942
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004943 Handle<Object> old_value;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004944 bool should_enqueue_change_record = false;
4945 if (FLAG_harmony_observation && self->map()->is_observed()) {
4946 should_enqueue_change_record = self->HasLocalElement(index);
4947 if (should_enqueue_change_record) {
4948 old_value = self->GetLocalElementAccessorPair(index) != NULL
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004949 ? Handle<Object>::cast(isolate->factory()->the_hole_value())
4950 : Object::GetElement(self, index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004951 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004952 }
4953
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004954 MaybeObject* result;
4955 // Skip interceptor if forcing deletion.
4956 if (self->HasIndexedInterceptor() && mode != FORCE_DELETION) {
4957 result = self->DeleteElementWithInterceptor(index);
4958 } else {
4959 result = self->GetElementsAccessor()->Delete(*self, index, mode);
4960 }
4961
4962 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004963 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004964
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00004965 if (should_enqueue_change_record && !self->HasLocalElement(index)) {
4966 Handle<String> name = isolate->factory()->Uint32ToString(index);
4967 EnqueueChangeRecord(self, "deleted", name, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00004968 }
4969
4970 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004971}
4972
4973
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004974Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
ulan@chromium.org750145a2013-03-07 15:14:13 +00004975 Handle<Name> prop) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004976 CALL_HEAP_FUNCTION(obj->GetIsolate(),
4977 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
4978 Object);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004979}
4980
4981
ulan@chromium.org750145a2013-03-07 15:14:13 +00004982MaybeObject* JSObject::DeleteProperty(Name* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004983 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004984 // ECMA-262, 3rd, 8.6.2.5
ulan@chromium.org750145a2013-03-07 15:14:13 +00004985 ASSERT(name->IsName());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004987 // Check access rights if needed.
4988 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
4990 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
4991 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004992 }
4993
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004994 if (IsJSGlobalProxy()) {
4995 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004997 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00004998 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005000
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005001 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005002 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00005003 return DeleteElement(index, mode);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005004 }
5005
5006 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005007 LocalLookup(name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005008 if (!lookup.IsFound()) return isolate->heap()->true_value();
5009 // Ignore attributes if forcing a deletion.
5010 if (lookup.IsDontDelete() && mode != FORCE_DELETION) {
5011 if (mode == STRICT_DELETION) {
5012 // Deleting a non-configurable property in strict mode.
5013 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005014 Handle<Object> args[2] = { Handle<Object>(name, isolate),
5015 Handle<Object>(this, isolate) };
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005016 return isolate->Throw(*isolate->factory()->NewTypeError(
5017 "strict_delete_property", HandleVector(args, 2)));
5018 }
5019 return isolate->heap()->false_value();
5020 }
5021
5022 // From this point on everything needs to be handlified.
5023 HandleScope scope(isolate);
5024 Handle<JSObject> self(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005025 Handle<Name> hname(name);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005026
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005027 Handle<Object> old_value = isolate->factory()->the_hole_value();
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005028 bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005029 if (is_observed && lookup.IsDataProperty()) {
5030 old_value = Object::GetProperty(self, hname);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005031 }
5032 MaybeObject* result;
5033
5034 // Check for interceptor.
5035 if (lookup.IsInterceptor()) {
5036 // Skip interceptor if forcing a deletion.
5037 if (mode == FORCE_DELETION) {
5038 result = self->DeletePropertyPostInterceptor(*hname, mode);
5039 } else {
5040 result = self->DeletePropertyWithInterceptor(*hname);
5041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005042 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005043 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005044 Object* obj;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005045 result = self->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
5046 if (!result->To(&obj)) return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005047 // Make sure the properties are normalized before removing the entry.
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005048 result = self->DeleteNormalizedProperty(*hname, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005049 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005050
5051 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005052 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005053
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005054 if (is_observed && !self->HasLocalProperty(*hname)) {
5055 EnqueueChangeRecord(self, "deleted", hname, old_value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005056 }
5057
5058 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005059}
5060
5061
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005062MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
5063 if (IsJSProxy()) {
5064 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
5065 }
5066 return JSObject::cast(this)->DeleteElement(index, mode);
5067}
5068
5069
ulan@chromium.org750145a2013-03-07 15:14:13 +00005070MaybeObject* JSReceiver::DeleteProperty(Name* name, DeleteMode mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005071 if (IsJSProxy()) {
5072 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
5073 }
5074 return JSObject::cast(this)->DeleteProperty(name, mode);
5075}
5076
5077
whesse@chromium.org7b260152011-06-20 15:33:18 +00005078bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
5079 ElementsKind kind,
5080 Object* object) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005081 ASSERT(IsFastObjectElementsKind(kind) ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005082 kind == DICTIONARY_ELEMENTS);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005083 if (IsFastObjectElementsKind(kind)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005084 int length = IsJSArray()
5085 ? Smi::cast(JSArray::cast(this)->length())->value()
5086 : elements->length();
5087 for (int i = 0; i < length; ++i) {
5088 Object* element = elements->get(i);
5089 if (!element->IsTheHole() && element == object) return true;
5090 }
5091 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005092 Object* key =
5093 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00005094 if (!key->IsUndefined()) return true;
5095 }
5096 return false;
5097}
5098
5099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005100// Check whether this object references another object.
5101bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005102 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005103 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005104 AssertNoAllocation no_alloc;
5105
5106 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005107 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 return true;
5109 }
5110
5111 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005112 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 return true;
5114 }
5115
5116 // Check if the object is among the named properties.
5117 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 return true;
5120 }
5121
5122 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00005123 ElementsKind kind = GetElementsKind();
5124 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005125 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00005126 case EXTERNAL_BYTE_ELEMENTS:
5127 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5128 case EXTERNAL_SHORT_ELEMENTS:
5129 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5130 case EXTERNAL_INT_ELEMENTS:
5131 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5132 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00005133 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00005134 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005135 case FAST_HOLEY_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00005136 // Raw pixels and external arrays do not reference other
5137 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005138 break;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005139 case FAST_SMI_ELEMENTS:
5140 case FAST_HOLEY_SMI_ELEMENTS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005141 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005142 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005143 case FAST_HOLEY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005144 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005145 FixedArray* elements = FixedArray::cast(this->elements());
5146 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005147 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00005149 case NON_STRICT_ARGUMENTS_ELEMENTS: {
5150 FixedArray* parameter_map = FixedArray::cast(elements());
5151 // Check the mapped parameters.
5152 int length = parameter_map->length();
5153 for (int i = 2; i < length; ++i) {
5154 Object* value = parameter_map->get(i);
5155 if (!value->IsTheHole() && value == obj) return true;
5156 }
5157 // Check the arguments.
5158 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005159 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS :
5160 FAST_HOLEY_ELEMENTS;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005161 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005162 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005163 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005164 }
5165
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00005166 // For functions check the context.
5167 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005168 // Get the constructor function for arguments array.
5169 JSObject* arguments_boilerplate =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005170 heap->isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005171 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005172 JSFunction* arguments_function =
5173 JSFunction::cast(arguments_boilerplate->map()->constructor());
5174
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005175 // Get the context and don't check if it is the native context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005176 JSFunction* f = JSFunction::cast(this);
5177 Context* context = f->context();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00005178 if (context->IsNativeContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179 return false;
5180 }
5181
5182 // Check the non-special context slots.
5183 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
5184 // Only check JS objects.
5185 if (context->get(i)->IsJSObject()) {
5186 JSObject* ctxobj = JSObject::cast(context->get(i));
5187 // If it is an arguments array check the content.
5188 if (ctxobj->map()->constructor() == arguments_function) {
5189 if (ctxobj->ReferencesObject(obj)) {
5190 return true;
5191 }
5192 } else if (ctxobj == obj) {
5193 return true;
5194 }
5195 }
5196 }
5197
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005198 // Check the context extension (if any) if it can have references.
5199 if (context->has_extension() && !context->IsCatchContext()) {
5200 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 }
5202 }
5203
5204 // No references to object.
5205 return false;
5206}
5207
5208
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005209Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
5210 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
5211}
5212
5213
lrn@chromium.org303ada72010-10-27 09:33:13 +00005214MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005216 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005217 !isolate->MayNamedAccess(this,
5218 isolate->heap()->undefined_value(),
5219 v8::ACCESS_KEYS)) {
5220 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
5221 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00005222 }
5223
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00005224 if (IsJSGlobalProxy()) {
5225 Object* proto = GetPrototype();
5226 if (proto->IsNull()) return this;
5227 ASSERT(proto->IsJSGlobalObject());
5228 return JSObject::cast(proto)->PreventExtensions();
5229 }
5230
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005231 // It's not possible to seal objects with external array elements
5232 if (HasExternalArrayElements()) {
5233 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005234 Handle<Object> object(this, isolate);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00005235 Handle<Object> error =
5236 isolate->factory()->NewTypeError(
5237 "cant_prevent_ext_external_array_elements",
5238 HandleVector(&object, 1));
5239 return isolate->Throw(*error);
5240 }
5241
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005242 // If there are fast elements we normalize.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005243 SeededNumberDictionary* dictionary = NULL;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005244 { MaybeObject* maybe = NormalizeElements();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005245 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005246 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005247 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005248 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005249 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005250
5251 // Do a map transition, other objects with this map may still
5252 // be extensible.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005253 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00005254 MaybeObject* maybe = map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005255 if (!maybe->To(&new_map)) return maybe;
5256
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00005257 new_map->set_is_extensible(false);
5258 set_map(new_map);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00005259 ASSERT(!map()->is_extensible());
5260 return new_map;
5261}
5262
5263
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005264MUST_USE_RESULT MaybeObject* JSObject::DeepCopy(Isolate* isolate) {
5265 StackLimitCheck check(isolate);
5266 if (check.HasOverflowed()) return isolate->StackOverflow();
5267
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005268 if (map()->is_deprecated()) {
5269 MaybeObject* maybe_failure = MigrateInstance();
5270 if (maybe_failure->IsFailure()) return maybe_failure;
5271 }
5272
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005273 Heap* heap = isolate->heap();
5274 Object* result;
5275 { MaybeObject* maybe_result = heap->CopyJSObject(this);
5276 if (!maybe_result->ToObject(&result)) return maybe_result;
5277 }
5278 JSObject* copy = JSObject::cast(result);
5279
5280 // Deep copy local properties.
5281 if (copy->HasFastProperties()) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005282 DescriptorArray* descriptors = copy->map()->instance_descriptors();
5283 int limit = copy->map()->NumberOfOwnDescriptors();
5284 for (int i = 0; i < limit; i++) {
5285 PropertyDetails details = descriptors->GetDetails(i);
5286 if (details.type() != FIELD) continue;
5287 int index = descriptors->GetFieldIndex(i);
5288 Object* value = RawFastPropertyAt(index);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005289 if (value->IsJSObject()) {
5290 JSObject* js_object = JSObject::cast(value);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005291 MaybeObject* maybe_copy = js_object->DeepCopy(isolate);
5292 if (!maybe_copy->To(&value)) return maybe_copy;
5293 } else {
5294 Representation representation = details.representation();
5295 MaybeObject* maybe_storage =
5296 value->AllocateNewStorageFor(heap, representation);
5297 if (!maybe_storage->To(&value)) return maybe_storage;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005298 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005299 copy->FastPropertyAtPut(index, value);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00005300 }
5301 } else {
5302 { MaybeObject* maybe_result =
5303 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
5304 if (!maybe_result->ToObject(&result)) return maybe_result;
5305 }
5306 FixedArray* names = FixedArray::cast(result);
5307 copy->GetLocalPropertyNames(names, 0);
5308 for (int i = 0; i < names->length(); i++) {
5309 ASSERT(names->get(i)->IsString());
5310 String* key_string = String::cast(names->get(i));
5311 PropertyAttributes attributes =
5312 copy->GetLocalPropertyAttribute(key_string);
5313 // Only deep copy fields from the object literal expression.
5314 // In particular, don't try to copy the length attribute of
5315 // an array.
5316 if (attributes != NONE) continue;
5317 Object* value =
5318 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
5319 if (value->IsJSObject()) {
5320 JSObject* js_object = JSObject::cast(value);
5321 { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
5322 if (!maybe_result->ToObject(&result)) return maybe_result;
5323 }
5324 { MaybeObject* maybe_result =
5325 // Creating object copy for literals. No strict mode needed.
5326 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
5327 if (!maybe_result->ToObject(&result)) return maybe_result;
5328 }
5329 }
5330 }
5331 }
5332
5333 // Deep copy local elements.
5334 // Pixel elements cannot be created using an object literal.
5335 ASSERT(!copy->HasExternalArrayElements());
5336 switch (copy->GetElementsKind()) {
5337 case FAST_SMI_ELEMENTS:
5338 case FAST_ELEMENTS:
5339 case FAST_HOLEY_SMI_ELEMENTS:
5340 case FAST_HOLEY_ELEMENTS: {
5341 FixedArray* elements = FixedArray::cast(copy->elements());
5342 if (elements->map() == heap->fixed_cow_array_map()) {
5343 isolate->counters()->cow_arrays_created_runtime()->Increment();
5344#ifdef DEBUG
5345 for (int i = 0; i < elements->length(); i++) {
5346 ASSERT(!elements->get(i)->IsJSObject());
5347 }
5348#endif
5349 } else {
5350 for (int i = 0; i < elements->length(); i++) {
5351 Object* value = elements->get(i);
5352 ASSERT(value->IsSmi() ||
5353 value->IsTheHole() ||
5354 (IsFastObjectElementsKind(copy->GetElementsKind())));
5355 if (value->IsJSObject()) {
5356 JSObject* js_object = JSObject::cast(value);
5357 { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
5358 if (!maybe_result->ToObject(&result)) return maybe_result;
5359 }
5360 elements->set(i, result);
5361 }
5362 }
5363 }
5364 break;
5365 }
5366 case DICTIONARY_ELEMENTS: {
5367 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
5368 int capacity = element_dictionary->Capacity();
5369 for (int i = 0; i < capacity; i++) {
5370 Object* k = element_dictionary->KeyAt(i);
5371 if (element_dictionary->IsKey(k)) {
5372 Object* value = element_dictionary->ValueAt(i);
5373 if (value->IsJSObject()) {
5374 JSObject* js_object = JSObject::cast(value);
5375 { MaybeObject* maybe_result = js_object->DeepCopy(isolate);
5376 if (!maybe_result->ToObject(&result)) return maybe_result;
5377 }
5378 element_dictionary->ValueAtPut(i, result);
5379 }
5380 }
5381 }
5382 break;
5383 }
5384 case NON_STRICT_ARGUMENTS_ELEMENTS:
5385 UNIMPLEMENTED();
5386 break;
5387 case EXTERNAL_PIXEL_ELEMENTS:
5388 case EXTERNAL_BYTE_ELEMENTS:
5389 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5390 case EXTERNAL_SHORT_ELEMENTS:
5391 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5392 case EXTERNAL_INT_ELEMENTS:
5393 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5394 case EXTERNAL_FLOAT_ELEMENTS:
5395 case EXTERNAL_DOUBLE_ELEMENTS:
5396 case FAST_DOUBLE_ELEMENTS:
5397 case FAST_HOLEY_DOUBLE_ELEMENTS:
5398 // No contained objects, nothing to do.
5399 break;
5400 }
5401 return copy;
5402}
5403
5404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405// Tests for the fast common case for property enumeration:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005406// - This object and all prototypes has an enum cache (which means that
5407// it is no proxy, has no interceptors and needs no access checks).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005408// - This object has no elements.
5409// - No prototype has enumerable properties/elements.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005410bool JSReceiver::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005411 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005413 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005414 o = JSObject::cast(o)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005415 if (!o->IsJSObject()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005416 JSObject* curr = JSObject::cast(o);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005417 int enum_length = curr->map()->EnumLength();
5418 if (enum_length == Map::kInvalidEnumCache) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005419 ASSERT(!curr->HasNamedInterceptor());
5420 ASSERT(!curr->HasIndexedInterceptor());
5421 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005422 if (curr->NumberOfEnumElements() > 0) return false;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00005423 if (curr != this && enum_length != 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 }
5425 return true;
5426}
5427
5428
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005429int Map::NumberOfDescribedProperties(DescriptorFlag which,
5430 PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005432 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005433 int limit = which == ALL_DESCRIPTORS
5434 ? descs->number_of_descriptors()
5435 : NumberOfOwnDescriptors();
5436 for (int i = 0; i < limit; i++) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00005437 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
5438 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
5439 result++;
5440 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005441 }
5442 return result;
5443}
5444
5445
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005446int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005447 int max_index = -1;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005448 int number_of_own_descriptors = NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005449 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005450 for (int i = 0; i < number_of_own_descriptors; i++) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005451 if (descs->GetType(i) == FIELD) {
5452 int current_index = descs->GetFieldIndex(i);
5453 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454 }
5455 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005456 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005457}
5458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459
ulan@chromium.org750145a2013-03-07 15:14:13 +00005460AccessorDescriptor* Map::FindAccessor(Name* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005461 DescriptorArray* descs = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005462 int number_of_own_descriptors = NumberOfOwnDescriptors();
5463 for (int i = 0; i < number_of_own_descriptors; i++) {
5464 if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005465 return descs->GetCallbacks(i);
5466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467 }
5468 return NULL;
5469}
5470
5471
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005472void JSReceiver::LocalLookup(
ulan@chromium.org750145a2013-03-07 15:14:13 +00005473 Name* name, LookupResult* result, bool search_hidden_prototypes) {
5474 ASSERT(name->IsName());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005475
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005476 Heap* heap = GetHeap();
5477
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005478 if (IsJSGlobalProxy()) {
5479 Object* proto = GetPrototype();
5480 if (proto->IsNull()) return result->NotFound();
5481 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005482 return JSReceiver::cast(proto)->LocalLookup(
5483 name, result, search_hidden_prototypes);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005484 }
5485
5486 if (IsJSProxy()) {
5487 result->HandlerResult(JSProxy::cast(this));
5488 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005489 }
5490
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 // Do not use inline caching if the object is a non-global object
5492 // that requires access checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005493 if (IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494 result->DisallowCaching();
5495 }
5496
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005497 JSObject* js_object = JSObject::cast(this);
5498
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005499 // Check for lookup interceptor except when bootstrapping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005500 if (js_object->HasNamedInterceptor() &&
5501 !heap->isolate()->bootstrapper()->IsActive()) {
5502 result->InterceptorResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503 return;
5504 }
5505
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005506 js_object->LocalLookupRealNamedProperty(name, result);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005507 if (result->IsFound() || !search_hidden_prototypes) return;
5508
5509 Object* proto = js_object->GetPrototype();
5510 if (!proto->IsJSReceiver()) return;
5511 JSReceiver* receiver = JSReceiver::cast(proto);
5512 if (receiver->map()->is_hidden_prototype()) {
5513 receiver->LocalLookup(name, result, search_hidden_prototypes);
5514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005515}
5516
5517
ulan@chromium.org750145a2013-03-07 15:14:13 +00005518void JSReceiver::Lookup(Name* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005519 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005520 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005522 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005523 current = JSObject::cast(current)->GetPrototype()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005524 JSReceiver::cast(current)->LocalLookup(name, result, false);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005525 if (result->IsFound()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005526 }
5527 result->NotFound();
5528}
5529
5530
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005531// Search object and its prototype chain for callback properties.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005532void JSObject::LookupCallbackProperty(Name* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005533 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005534 for (Object* current = this;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00005535 current != heap->null_value() && current->IsJSObject();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005536 current = JSObject::cast(current)->GetPrototype()) {
5537 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005538 if (result->IsPropertyCallbacks()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005539 }
5540 result->NotFound();
5541}
5542
5543
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005544// Try to update an accessor in an elements dictionary. Return true if the
5545// update succeeded, and false otherwise.
5546static bool UpdateGetterSetterInDictionary(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005547 SeededNumberDictionary* dictionary,
5548 uint32_t index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00005549 Object* getter,
5550 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005551 PropertyAttributes attributes) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005552 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005553 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005554 Object* result = dictionary->ValueAt(entry);
5555 PropertyDetails details = dictionary->DetailsAt(entry);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005556 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00005557 ASSERT(!details.IsDontDelete());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005558 if (details.attributes() != attributes) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00005559 dictionary->DetailsAtPut(
5560 entry,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005561 PropertyDetails(attributes, CALLBACKS, index));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005562 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00005563 AccessorPair::cast(result)->SetComponents(getter, setter);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005564 return true;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005565 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00005566 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005567 return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005568}
5569
5570
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005571MaybeObject* JSObject::DefineElementAccessor(uint32_t index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00005572 Object* getter,
5573 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005574 PropertyAttributes attributes) {
5575 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005576 case FAST_SMI_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005577 case FAST_ELEMENTS:
5578 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005579 case FAST_HOLEY_SMI_ELEMENTS:
5580 case FAST_HOLEY_ELEMENTS:
5581 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005582 break;
5583 case EXTERNAL_PIXEL_ELEMENTS:
5584 case EXTERNAL_BYTE_ELEMENTS:
5585 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
5586 case EXTERNAL_SHORT_ELEMENTS:
5587 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
5588 case EXTERNAL_INT_ELEMENTS:
5589 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
5590 case EXTERNAL_FLOAT_ELEMENTS:
5591 case EXTERNAL_DOUBLE_ELEMENTS:
5592 // Ignore getters and setters on pixel and external array elements.
5593 return GetHeap()->undefined_value();
5594 case DICTIONARY_ELEMENTS:
5595 if (UpdateGetterSetterInDictionary(element_dictionary(),
5596 index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00005597 getter,
5598 setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005599 attributes)) {
5600 return GetHeap()->undefined_value();
whesse@chromium.org7b260152011-06-20 15:33:18 +00005601 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005602 break;
5603 case NON_STRICT_ARGUMENTS_ELEMENTS: {
5604 // Ascertain whether we have read-only properties or an existing
5605 // getter/setter pair in an arguments elements dictionary backing
5606 // store.
5607 FixedArray* parameter_map = FixedArray::cast(elements());
5608 uint32_t length = parameter_map->length();
5609 Object* probe =
5610 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
5611 if (probe == NULL || probe->IsTheHole()) {
5612 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
5613 if (arguments->IsDictionary()) {
5614 SeededNumberDictionary* dictionary =
5615 SeededNumberDictionary::cast(arguments);
5616 if (UpdateGetterSetterInDictionary(dictionary,
5617 index,
danno@chromium.org88aa0582012-03-23 15:11:57 +00005618 getter,
5619 setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005620 attributes)) {
5621 return GetHeap()->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00005622 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005623 }
5624 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005625 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005626 }
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005627 }
5628
5629 AccessorPair* accessors;
5630 { MaybeObject* maybe_accessors = GetHeap()->AllocateAccessorPair();
5631 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
5632 }
danno@chromium.org88aa0582012-03-23 15:11:57 +00005633 accessors->SetComponents(getter, setter);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005634
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005635 return SetElementCallback(index, accessors, attributes);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005636}
5637
5638
ulan@chromium.org750145a2013-03-07 15:14:13 +00005639MaybeObject* JSObject::CreateAccessorPairFor(Name* name) {
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00005640 LookupResult result(GetHeap()->isolate());
5641 LocalLookupRealNamedProperty(name, &result);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005642 if (result.IsPropertyCallbacks()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005643 // Note that the result can actually have IsDontDelete() == true when we
5644 // e.g. have to fall back to the slow case while adding a setter after
5645 // successfully reusing a map transition for a getter. Nevertheless, this is
5646 // OK, because the assertion only holds for the whole addition of both
5647 // accessors, not for the addition of each part. See first comment in
5648 // DefinePropertyAccessor below.
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00005649 Object* obj = result.GetCallbackObject();
5650 if (obj->IsAccessorPair()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005651 return AccessorPair::cast(obj)->Copy();
jkummerow@chromium.org28faa982012-04-13 09:58:30 +00005652 }
5653 }
5654 return GetHeap()->AllocateAccessorPair();
5655}
5656
5657
ulan@chromium.org750145a2013-03-07 15:14:13 +00005658MaybeObject* JSObject::DefinePropertyAccessor(Name* name,
danno@chromium.org88aa0582012-03-23 15:11:57 +00005659 Object* getter,
5660 Object* setter,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005661 PropertyAttributes attributes) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005662 // We could assert that the property is configurable here, but we would need
5663 // to do a lookup, which seems to be a bit of overkill.
5664 Heap* heap = GetHeap();
5665 bool only_attribute_changes = getter->IsNull() && setter->IsNull();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005666 if (HasFastProperties() && !only_attribute_changes &&
5667 (map()->NumberOfOwnDescriptors() <
5668 DescriptorArray::kMaxNumberOfDescriptors)) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005669 MaybeObject* getterOk = heap->undefined_value();
5670 if (!getter->IsNull()) {
5671 getterOk = DefineFastAccessor(name, ACCESSOR_GETTER, getter, attributes);
5672 if (getterOk->IsFailure()) return getterOk;
5673 }
5674
5675 MaybeObject* setterOk = heap->undefined_value();
5676 if (getterOk != heap->null_value() && !setter->IsNull()) {
5677 setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes);
5678 if (setterOk->IsFailure()) return setterOk;
5679 }
5680
5681 if (getterOk != heap->null_value() && setterOk != heap->null_value()) {
5682 return heap->undefined_value();
5683 }
5684 }
5685
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005686 AccessorPair* accessors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005687 MaybeObject* maybe_accessors = CreateAccessorPairFor(name);
5688 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
5689
danno@chromium.org88aa0582012-03-23 15:11:57 +00005690 accessors->SetComponents(getter, setter);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +00005691 return SetPropertyCallback(name, accessors, attributes);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005692}
5693
5694
ulan@chromium.org750145a2013-03-07 15:14:13 +00005695bool JSObject::CanSetCallback(Name* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005696 ASSERT(!IsAccessCheckNeeded() ||
5697 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005698
5699 // Check if there is an API defined callback object which prohibits
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005700 // callback overwriting in this object or its prototype chain.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005701 // This mechanism is needed for instance in a browser setting, where
5702 // certain accessors such as window.location should not be allowed
5703 // to be overwritten because allowing overwriting could potentially
5704 // cause security problems.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005705 LookupResult callback_result(GetIsolate());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005706 LookupCallbackProperty(name, &callback_result);
5707 if (callback_result.IsFound()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005708 Object* obj = callback_result.GetCallbackObject();
5709 if (obj->IsAccessorInfo() &&
5710 AccessorInfo::cast(obj)->prohibits_overwriting()) {
5711 return false;
5712 }
5713 }
5714
5715 return true;
5716}
5717
5718
lrn@chromium.org303ada72010-10-27 09:33:13 +00005719MaybeObject* JSObject::SetElementCallback(uint32_t index,
5720 Object* structure,
5721 PropertyAttributes attributes) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005722 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005723
5724 // Normalize elements to make this operation simple.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005725 SeededNumberDictionary* dictionary;
5726 { MaybeObject* maybe_dictionary = NormalizeElements();
5727 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005728 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00005729 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005730
5731 // Update the dictionary with the new CALLBACKS property.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005732 { MaybeObject* maybe_dictionary = dictionary->Set(index, structure, details);
5733 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005734 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005735
whesse@chromium.org7b260152011-06-20 15:33:18 +00005736 dictionary->set_requires_slow_elements();
5737 // Update the dictionary backing store on the object.
5738 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
5739 // Also delete any parameter alias.
5740 //
5741 // TODO(kmillikin): when deleting the last parameter alias we could
5742 // switch to a direct backing store without the parameter map. This
5743 // would allow GC of the context.
5744 FixedArray* parameter_map = FixedArray::cast(elements());
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005745 if (index < static_cast<uint32_t>(parameter_map->length()) - 2) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00005746 parameter_map->set(index + 2, GetHeap()->the_hole_value());
5747 }
5748 parameter_map->set(1, dictionary);
5749 } else {
5750 set_elements(dictionary);
5751 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005752
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005753 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005754}
5755
5756
ulan@chromium.org750145a2013-03-07 15:14:13 +00005757MaybeObject* JSObject::SetPropertyCallback(Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005758 Object* structure,
5759 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005760 // Normalize object to make this operation simple.
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005761 MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
5762 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005763
5764 // For the global object allocate a new map to invalidate the global inline
5765 // caches which have a global property cell reference directly in the code.
5766 if (IsGlobalObject()) {
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005767 Map* new_map;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005768 MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
5769 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +00005770 ASSERT(new_map->is_dictionary_map());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005771
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005772 set_map(new_map);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005773 // When running crankshaft, changing the map is not enough. We
5774 // need to deoptimize all functions that rely on this global
5775 // object.
5776 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005777 }
5778
5779 // Update the dictionary with the new CALLBACKS property.
ulan@chromium.org57ff8812013-05-10 08:16:55 +00005780 PropertyDetails details = PropertyDetails(attributes, CALLBACKS, 0);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005781 maybe_ok = SetNormalizedProperty(name, structure, details);
5782 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005783
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005784 return GetHeap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005785}
5786
danno@chromium.org88aa0582012-03-23 15:11:57 +00005787
5788void JSObject::DefineAccessor(Handle<JSObject> object,
ulan@chromium.org750145a2013-03-07 15:14:13 +00005789 Handle<Name> name,
danno@chromium.org88aa0582012-03-23 15:11:57 +00005790 Handle<Object> getter,
5791 Handle<Object> setter,
5792 PropertyAttributes attributes) {
5793 CALL_HEAP_FUNCTION_VOID(
5794 object->GetIsolate(),
5795 object->DefineAccessor(*name, *getter, *setter, attributes));
5796}
5797
ulan@chromium.org750145a2013-03-07 15:14:13 +00005798MaybeObject* JSObject::DefineAccessor(Name* name_raw,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005799 Object* getter_raw,
5800 Object* setter_raw,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005801 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005802 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005803 // Check access rights if needed.
5804 if (IsAccessCheckNeeded() &&
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005805 !isolate->MayNamedAccess(this, name_raw, v8::ACCESS_SET)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005806 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
5807 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005808 }
5809
5810 if (IsJSGlobalProxy()) {
5811 Object* proto = GetPrototype();
5812 if (proto->IsNull()) return this;
5813 ASSERT(proto->IsJSGlobalObject());
danno@chromium.org88aa0582012-03-23 15:11:57 +00005814 return JSObject::cast(proto)->DefineAccessor(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005815 name_raw, getter_raw, setter_raw, attributes);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005816 }
5817
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005818 // Make sure that the top context does not change when doing callbacks or
5819 // interceptor calls.
5820 AssertNoContextChange ncc;
5821
5822 // Try to flatten before operating on the string.
ulan@chromium.org750145a2013-03-07 15:14:13 +00005823 if (name_raw->IsString()) String::cast(name_raw)->TryFlatten();
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005824
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005825 if (!CanSetCallback(name_raw)) return isolate->heap()->undefined_value();
5826
5827 // From this point on everything needs to be handlified.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005828 HandleScope scope(isolate);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005829 Handle<JSObject> self(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +00005830 Handle<Name> name(name_raw);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00005831 Handle<Object> getter(getter_raw, isolate);
5832 Handle<Object> setter(setter_raw, isolate);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00005833
5834 uint32_t index = 0;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005835 bool is_element = name->AsArrayIndex(&index);
5836
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005837 Handle<Object> old_value = isolate->factory()->the_hole_value();
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005838 bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005839 bool preexists = false;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005840 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005841 if (is_element) {
5842 preexists = HasLocalElement(index);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005843 if (preexists && self->GetLocalElementAccessorPair(index) == NULL) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005844 old_value = Object::GetElement(self, index);
5845 }
5846 } else {
5847 LookupResult lookup(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00005848 LocalLookup(*name, &lookup, true);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005849 preexists = lookup.IsProperty();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00005850 if (preexists && lookup.IsDataProperty()) {
5851 old_value = Object::GetProperty(self, name);
5852 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005853 }
5854 }
5855
5856 MaybeObject* result = is_element ?
5857 self->DefineElementAccessor(index, *getter, *setter, attributes) :
5858 self->DefinePropertyAccessor(*name, *getter, *setter, attributes);
5859
5860 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00005861 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005862
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00005863 if (is_observed) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005864 const char* type = preexists ? "reconfigured" : "new";
5865 EnqueueChangeRecord(self, type, name, old_value);
5866 }
5867
5868 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005869}
5870
5871
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005872static MaybeObject* TryAccessorTransition(JSObject* self,
5873 Map* transitioned_map,
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005874 int target_descriptor,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005875 AccessorComponent component,
5876 Object* accessor,
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005877 PropertyAttributes attributes) {
5878 DescriptorArray* descs = transitioned_map->instance_descriptors();
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005879 PropertyDetails details = descs->GetDetails(target_descriptor);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005880
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005881 // If the transition target was not callbacks, fall back to the slow case.
5882 if (details.type() != CALLBACKS) return self->GetHeap()->null_value();
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005883 Object* descriptor = descs->GetCallbacksObject(target_descriptor);
5884 if (!descriptor->IsAccessorPair()) return self->GetHeap()->null_value();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005885
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005886 Object* target_accessor = AccessorPair::cast(descriptor)->get(component);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005887 PropertyAttributes target_attributes = details.attributes();
5888
5889 // Reuse transition if adding same accessor with same attributes.
5890 if (target_accessor == accessor && target_attributes == attributes) {
5891 self->set_map(transitioned_map);
5892 return self;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005893 }
5894
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005895 // If either not the same accessor, or not the same attributes, fall back to
5896 // the slow case.
5897 return self->GetHeap()->null_value();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005898}
5899
5900
ulan@chromium.org750145a2013-03-07 15:14:13 +00005901MaybeObject* JSObject::DefineFastAccessor(Name* name,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005902 AccessorComponent component,
5903 Object* accessor,
5904 PropertyAttributes attributes) {
5905 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined());
5906 LookupResult result(GetIsolate());
5907 LocalLookup(name, &result);
5908
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00005909 if (result.IsFound() && !result.IsPropertyCallbacks()) {
5910 return GetHeap()->null_value();
5911 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005912
5913 // Return success if the same accessor with the same attributes already exist.
5914 AccessorPair* source_accessors = NULL;
5915 if (result.IsPropertyCallbacks()) {
5916 Object* callback_value = result.GetCallbackObject();
5917 if (callback_value->IsAccessorPair()) {
5918 source_accessors = AccessorPair::cast(callback_value);
5919 Object* entry = source_accessors->get(component);
5920 if (entry == accessor && result.GetAttributes() == attributes) {
5921 return this;
5922 }
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005923 } else {
5924 return GetHeap()->null_value();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005925 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005926
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005927 int descriptor_number = result.GetDescriptorIndex();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00005928
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005929 map()->LookupTransition(this, name, &result);
5930
5931 if (result.IsFound()) {
5932 Map* target = result.GetTransitionTarget();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00005933 ASSERT(target->NumberOfOwnDescriptors() ==
5934 map()->NumberOfOwnDescriptors());
5935 // This works since descriptors are sorted in order of addition.
5936 ASSERT(map()->instance_descriptors()->GetKey(descriptor_number) == name);
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005937 return TryAccessorTransition(
5938 this, target, descriptor_number, component, accessor, attributes);
5939 }
5940 } else {
5941 // If not, lookup a transition.
5942 map()->LookupTransition(this, name, &result);
5943
5944 // If there is a transition, try to follow it.
5945 if (result.IsFound()) {
5946 Map* target = result.GetTransitionTarget();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00005947 int descriptor_number = target->LastAdded();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00005948 ASSERT(target->instance_descriptors()->GetKey(descriptor_number)
5949 ->Equals(name));
verwaest@chromium.org178fb152012-07-18 11:21:48 +00005950 return TryAccessorTransition(
5951 this, target, descriptor_number, component, accessor, attributes);
5952 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005953 }
5954
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005955 // If there is no transition yet, add a transition to the a new accessor pair
5956 // containing the accessor.
5957 AccessorPair* accessors;
5958 MaybeObject* maybe_accessors;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005959
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005960 // Allocate a new pair if there were no source accessors. Otherwise, copy the
5961 // pair and modify the accessor.
5962 if (source_accessors != NULL) {
5963 maybe_accessors = source_accessors->Copy();
5964 } else {
5965 maybe_accessors = GetHeap()->AllocateAccessorPair();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005966 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005967 if (!maybe_accessors->To(&accessors)) return maybe_accessors;
5968 accessors->set(component, accessor);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005969
verwaest@chromium.org753aee42012-07-17 16:15:42 +00005970 CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
5971
5972 Map* new_map;
5973 MaybeObject* maybe_new_map =
5974 map()->CopyInsertDescriptor(&new_accessors_desc, INSERT_TRANSITION);
5975 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
5976
5977 set_map(new_map);
5978 return this;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00005979}
5980
5981
lrn@chromium.org303ada72010-10-27 09:33:13 +00005982MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005983 Isolate* isolate = GetIsolate();
ulan@chromium.org750145a2013-03-07 15:14:13 +00005984 Name* name = Name::cast(info->name());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005985 // Check access rights if needed.
5986 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005987 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
5988 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
5989 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00005990 }
5991
5992 if (IsJSGlobalProxy()) {
5993 Object* proto = GetPrototype();
5994 if (proto->IsNull()) return this;
5995 ASSERT(proto->IsJSGlobalObject());
5996 return JSObject::cast(proto)->DefineAccessor(info);
5997 }
5998
5999 // Make sure that the top context does not change when doing callbacks or
6000 // interceptor calls.
6001 AssertNoContextChange ncc;
6002
6003 // Try to flatten before operating on the string.
ulan@chromium.org750145a2013-03-07 15:14:13 +00006004 if (name->IsString()) String::cast(name)->TryFlatten();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006005
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006006 if (!CanSetCallback(name)) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006007
6008 uint32_t index = 0;
6009 bool is_element = name->AsArrayIndex(&index);
6010
6011 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006012 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006013
6014 // Accessors overwrite previous callbacks (cf. with getters/setters).
6015 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006016 case FAST_SMI_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006017 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00006018 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00006019 case FAST_HOLEY_SMI_ELEMENTS:
6020 case FAST_HOLEY_ELEMENTS:
6021 case FAST_HOLEY_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006022 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006023 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006024 case EXTERNAL_BYTE_ELEMENTS:
6025 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6026 case EXTERNAL_SHORT_ELEMENTS:
6027 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6028 case EXTERNAL_INT_ELEMENTS:
6029 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6030 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00006031 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006032 // Ignore getters and setters on pixel and external array
6033 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006034 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006035 case DICTIONARY_ELEMENTS:
6036 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00006037 case NON_STRICT_ARGUMENTS_ELEMENTS:
6038 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006039 break;
6040 }
6041
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006042 MaybeObject* maybe_ok =
6043 SetElementCallback(index, info, info->property_attributes());
6044 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006045 } else {
6046 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006047 LookupResult result(isolate);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00006048 LocalLookup(name, &result, true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006049 // ES5 forbids turning a property into an accessor if it's not
6050 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006051 if (result.IsFound() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006053 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006054
6055 MaybeObject* maybe_ok =
6056 SetPropertyCallback(name, info, info->property_attributes());
6057 if (maybe_ok->IsFailure()) return maybe_ok;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00006058 }
6059
6060 return this;
6061}
6062
6063
ulan@chromium.org750145a2013-03-07 15:14:13 +00006064Object* JSObject::LookupAccessor(Name* name, AccessorComponent component) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 Heap* heap = GetHeap();
6066
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067 // Make sure that the top context does not change when doing callbacks or
6068 // interceptor calls.
6069 AssertNoContextChange ncc;
6070
6071 // Check access rights if needed.
6072 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006073 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
6074 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
6075 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006076 }
6077
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 // Make the lookup and include prototypes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006079 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006080 if (name->AsArrayIndex(&index)) {
6081 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006082 obj != heap->null_value();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006083 obj = JSReceiver::cast(obj)->GetPrototype()) {
6084 if (obj->IsJSObject() && JSObject::cast(obj)->HasDictionaryElements()) {
6085 JSObject* js_object = JSObject::cast(obj);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006086 SeededNumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00006087 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006088 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006089 Object* element = dictionary->ValueAt(entry);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00006090 if (dictionary->DetailsAt(entry).type() == CALLBACKS &&
6091 element->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00006092 return AccessorPair::cast(element)->GetComponent(component);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006093 }
6094 }
6095 }
6096 }
6097 } else {
6098 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006099 obj != heap->null_value();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006100 obj = JSReceiver::cast(obj)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006101 LookupResult result(heap->isolate());
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006102 JSReceiver::cast(obj)->LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006103 if (result.IsFound()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006104 if (result.IsReadOnly()) return heap->undefined_value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006105 if (result.IsPropertyCallbacks()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006106 Object* obj = result.GetCallbackObject();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00006107 if (obj->IsAccessorPair()) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00006108 return AccessorPair::cast(obj)->GetComponent(component);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006109 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006110 }
6111 }
6112 }
6113 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006114 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115}
6116
6117
6118Object* JSObject::SlowReverseLookup(Object* value) {
6119 if (HasFastProperties()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006120 int number_of_own_descriptors = map()->NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006121 DescriptorArray* descs = map()->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006122 for (int i = 0; i < number_of_own_descriptors; i++) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006123 if (descs->GetType(i) == FIELD) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006124 Object* property = RawFastPropertyAt(descs->GetFieldIndex(i));
6125 if (FLAG_track_double_fields &&
6126 descs->GetDetails(i).representation().IsDouble()) {
6127 ASSERT(property->IsHeapNumber());
6128 if (value->IsNumber() && property->Number() == value->Number()) {
6129 return descs->GetKey(i);
6130 }
6131 } else if (property == value) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006132 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006133 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006134 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
6135 if (descs->GetConstantFunction(i) == value) {
6136 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006137 }
6138 }
6139 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006140 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141 } else {
6142 return property_dictionary()->SlowReverseLookup(value);
6143 }
6144}
6145
6146
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006147MaybeObject* Map::RawCopy(int instance_size) {
6148 Map* result;
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006149 MaybeObject* maybe_result =
6150 GetHeap()->AllocateMap(instance_type(), instance_size);
6151 if (!maybe_result->To(&result)) return maybe_result;
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006152
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006153 result->set_prototype(prototype());
6154 result->set_constructor(constructor());
6155 result->set_bit_field(bit_field());
6156 result->set_bit_field2(bit_field2());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006157 int new_bit_field3 = bit_field3();
6158 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true);
6159 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0);
6160 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006161 new_bit_field3 = Deprecated::update(new_bit_field3, false);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006162 result->set_bit_field3(new_bit_field3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006163 return result;
6164}
6165
6166
lrn@chromium.org303ada72010-10-27 09:33:13 +00006167MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
6168 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00006169 int new_instance_size = instance_size();
6170 if (mode == CLEAR_INOBJECT_PROPERTIES) {
6171 new_instance_size -= inobject_properties() * kPointerSize;
6172 }
6173
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006174 Map* result;
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006175 MaybeObject* maybe_result = RawCopy(new_instance_size);
6176 if (!maybe_result->To(&result)) return maybe_result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00006177
6178 if (mode != CLEAR_INOBJECT_PROPERTIES) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006179 result->set_inobject_properties(inobject_properties());
ricow@chromium.org65fae842010-08-25 15:26:24 +00006180 }
6181
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006182 result->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
erik.corry@gmail.com88767242012-08-08 14:43:45 +00006183 result->set_dictionary_map(true);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006184
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00006185#ifdef VERIFY_HEAP
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006186 if (FLAG_verify_heap && result->is_shared()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006187 result->SharedMapVerify();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006188 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00006189#endif
6190
6191 return result;
6192}
6193
6194
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006195MaybeObject* Map::CopyDropDescriptors() {
6196 Map* result;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006197 MaybeObject* maybe_result = RawCopy(instance_size());
6198 if (!maybe_result->To(&result)) return maybe_result;
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006199
6200 // Please note instance_type and instance_size are set when allocated.
6201 result->set_inobject_properties(inobject_properties());
6202 result->set_unused_property_fields(unused_property_fields());
6203
6204 result->set_pre_allocated_property_fields(pre_allocated_property_fields());
6205 result->set_is_shared(false);
6206 result->ClearCodeCache(GetHeap());
ulan@chromium.org2e04b582013-02-21 14:06:02 +00006207 NotifyLeafMapLayoutChange();
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006208 return result;
6209}
6210
6211
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006212MaybeObject* Map::ShareDescriptor(DescriptorArray* descriptors,
6213 Descriptor* descriptor) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006214 // Sanity check. This path is only to be taken if the map owns its descriptor
6215 // array, implying that its NumberOfOwnDescriptors equals the number of
6216 // descriptors in the descriptor array.
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006217 ASSERT(NumberOfOwnDescriptors() ==
6218 instance_descriptors()->number_of_descriptors());
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006219 Map* result;
6220 MaybeObject* maybe_result = CopyDropDescriptors();
6221 if (!maybe_result->To(&result)) return maybe_result;
6222
ulan@chromium.org750145a2013-03-07 15:14:13 +00006223 Name* name = descriptor->GetKey();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006224
6225 TransitionArray* transitions;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006226 MaybeObject* maybe_transitions =
6227 AddTransition(name, result, SIMPLE_TRANSITION);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006228 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
6229
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006230 int old_size = descriptors->number_of_descriptors();
6231
6232 DescriptorArray* new_descriptors;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006233
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006234 if (descriptors->NumberOfSlackDescriptors() > 0) {
6235 new_descriptors = descriptors;
6236 new_descriptors->Append(descriptor);
6237 } else {
6238 // Descriptor arrays grow by 50%.
6239 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
6240 old_size, old_size < 4 ? 1 : old_size / 2);
6241 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006242
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006243 DescriptorArray::WhitenessWitness witness(new_descriptors);
6244
6245 // Copy the descriptors, inserting a descriptor.
6246 for (int i = 0; i < old_size; ++i) {
6247 new_descriptors->CopyFrom(i, descriptors, i, witness);
6248 }
6249
6250 new_descriptors->Append(descriptor, witness);
6251
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006252 if (old_size > 0) {
6253 // If the source descriptors had an enum cache we copy it. This ensures
6254 // that the maps to which we push the new descriptor array back can rely
6255 // on a cache always being available once it is set. If the map has more
6256 // enumerated descriptors than available in the original cache, the cache
6257 // will be lazily replaced by the extended cache when needed.
6258 if (descriptors->HasEnumCache()) {
6259 new_descriptors->CopyEnumCacheFrom(descriptors);
6260 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006261
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006262 Map* map;
6263 // Replace descriptors by new_descriptors in all maps that share it.
6264 for (Object* current = GetBackPointer();
6265 !current->IsUndefined();
6266 current = map->GetBackPointer()) {
6267 map = Map::cast(current);
6268 if (map->instance_descriptors() != descriptors) break;
6269 map->set_instance_descriptors(new_descriptors);
6270 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006271
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006272 set_instance_descriptors(new_descriptors);
6273 }
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006274 }
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006275
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006276 result->SetBackPointer(this);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006277 result->InitializeDescriptors(new_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006278 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1);
6279
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006280 set_transitions(transitions);
6281 set_owns_descriptors(false);
6282
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006283 return result;
6284}
6285
6286
6287MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors,
ulan@chromium.org750145a2013-03-07 15:14:13 +00006288 Name* name,
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006289 TransitionFlag flag,
6290 int descriptor_index) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006291 ASSERT(descriptors->IsSortedNoDuplicates());
6292
6293 Map* result;
6294 MaybeObject* maybe_result = CopyDropDescriptors();
6295 if (!maybe_result->To(&result)) return maybe_result;
6296
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006297 result->InitializeDescriptors(descriptors);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006298
verwaest@chromium.orgb6d052d2012-07-27 08:03:27 +00006299 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006300 TransitionArray* transitions;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006301 SimpleTransitionFlag simple_flag =
6302 (descriptor_index == descriptors->number_of_descriptors() - 1)
6303 ? SIMPLE_TRANSITION
6304 : FULL_TRANSITION;
danno@chromium.orgf005df62013-04-30 16:36:45 +00006305 ASSERT(name == descriptors->GetKey(descriptor_index));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006306 MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006307 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
6308
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006309 set_transitions(transitions);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006310 result->SetBackPointer(this);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006311 } else {
6312 descriptors->InitializeRepresentations(Representation::Tagged());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006313 }
6314
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006315 return result;
6316}
6317
6318
danno@chromium.orgf005df62013-04-30 16:36:45 +00006319MaybeObject* Map::CopyInstallDescriptors(int new_descriptor,
6320 DescriptorArray* descriptors) {
6321 ASSERT(descriptors->IsSortedNoDuplicates());
6322
6323 Map* result;
6324 MaybeObject* maybe_result = CopyDropDescriptors();
6325 if (!maybe_result->To(&result)) return maybe_result;
6326
6327 result->InitializeDescriptors(descriptors);
6328 result->SetNumberOfOwnDescriptors(new_descriptor + 1);
6329
6330 int unused_property_fields = this->unused_property_fields();
6331 if (descriptors->GetDetails(new_descriptor).type() == FIELD) {
6332 unused_property_fields = this->unused_property_fields() - 1;
6333 if (unused_property_fields < 0) {
6334 unused_property_fields += JSObject::kFieldsAdded;
6335 }
6336 }
6337
6338 result->set_unused_property_fields(unused_property_fields);
6339 result->set_owns_descriptors(false);
6340
6341 if (CanHaveMoreTransitions()) {
6342 Name* name = descriptors->GetKey(new_descriptor);
6343 TransitionArray* transitions;
6344 MaybeObject* maybe_transitions =
6345 AddTransition(name, result, SIMPLE_TRANSITION);
6346 if (!maybe_transitions->To(&transitions)) return maybe_transitions;
6347
6348 set_transitions(transitions);
6349 result->SetBackPointer(this);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006350 } else {
6351 descriptors->InitializeRepresentations(Representation::Tagged());
danno@chromium.orgf005df62013-04-30 16:36:45 +00006352 }
6353
6354 return result;
6355}
6356
6357
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006358MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006359 if (flag == INSERT_TRANSITION) {
6360 ASSERT(!HasElementsTransition() ||
6361 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS ||
6362 IsExternalArrayElementsKind(
6363 elements_transition_map()->elements_kind())) &&
6364 (kind == DICTIONARY_ELEMENTS ||
6365 IsExternalArrayElementsKind(kind))));
6366 ASSERT(!IsFastElementsKind(kind) ||
6367 IsMoreGeneralElementsKindTransition(elements_kind(), kind));
6368 ASSERT(kind != elements_kind());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006369 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006370
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006371 bool insert_transition =
6372 flag == INSERT_TRANSITION && !HasElementsTransition();
6373
6374 if (insert_transition && owns_descriptors()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006375 // In case the map owned its own descriptors, share the descriptors and
6376 // transfer ownership to the new map.
6377 Map* new_map;
6378 MaybeObject* maybe_new_map = CopyDropDescriptors();
6379 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
6380
6381 MaybeObject* added_elements = set_elements_transition_map(new_map);
6382 if (added_elements->IsFailure()) return added_elements;
6383
6384 new_map->set_elements_kind(kind);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006385 new_map->InitializeDescriptors(instance_descriptors());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006386 new_map->SetBackPointer(this);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006387 set_owns_descriptors(false);
6388 return new_map;
6389 }
6390
6391 // In case the map did not own its own descriptors, a split is forced by
6392 // copying the map; creating a new descriptor array cell.
6393 // Create a new free-floating map only if we are not allowed to store it.
6394 Map* new_map;
6395 MaybeObject* maybe_new_map = Copy();
6396 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006397
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006398 new_map->set_elements_kind(kind);
6399
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00006400 if (insert_transition) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006401 MaybeObject* added_elements = set_elements_transition_map(new_map);
6402 if (added_elements->IsFailure()) return added_elements;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006403 new_map->SetBackPointer(this);
6404 }
6405
6406 return new_map;
6407}
6408
6409
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006410MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() {
6411 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors();
6412
6413 // If the map has pre-allocated properties always start out with a descriptor
6414 // array describing these properties.
6415 ASSERT(constructor()->IsJSFunction());
6416 JSFunction* ctor = JSFunction::cast(constructor());
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006417 Map* map = ctor->initial_map();
6418 DescriptorArray* descriptors = map->instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006419
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006420 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
6421 DescriptorArray* new_descriptors;
6422 MaybeObject* maybe_descriptors =
6423 descriptors->CopyUpTo(number_of_own_descriptors);
6424 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
6425
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006426 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006427}
6428
6429
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006430MaybeObject* Map::Copy() {
6431 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006432 DescriptorArray* new_descriptors;
6433 int number_of_own_descriptors = NumberOfOwnDescriptors();
6434 MaybeObject* maybe_descriptors =
6435 descriptors->CopyUpTo(number_of_own_descriptors);
6436 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
6437
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006438 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006439}
6440
6441
6442MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor,
6443 TransitionFlag flag) {
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006444 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006445
ulan@chromium.org750145a2013-03-07 15:14:13 +00006446 // Ensure the key is unique.
6447 MaybeObject* maybe_failure = descriptor->KeyToUniqueName();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006448 if (maybe_failure->IsFailure()) return maybe_failure;
6449
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006450 int old_size = NumberOfOwnDescriptors();
verwaest@chromium.org652f4fa2012-10-08 08:48:51 +00006451 int new_size = old_size + 1;
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006452
6453 if (flag == INSERT_TRANSITION &&
6454 owns_descriptors() &&
6455 CanHaveMoreTransitions()) {
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006456 return ShareDescriptor(descriptors, descriptor);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006457 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006458
6459 DescriptorArray* new_descriptors;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006460 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006461 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
6462
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006463 DescriptorArray::WhitenessWitness witness(new_descriptors);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006464
6465 // Copy the descriptors, inserting a descriptor.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006466 for (int i = 0; i < old_size; ++i) {
6467 new_descriptors->CopyFrom(i, descriptors, i, witness);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006468 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006469
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006470 if (old_size != descriptors->number_of_descriptors()) {
6471 new_descriptors->SetNumberOfDescriptors(new_size);
6472 new_descriptors->Set(old_size, descriptor, witness);
6473 new_descriptors->Sort();
6474 } else {
6475 new_descriptors->Append(descriptor, witness);
6476 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006477
ulan@chromium.org750145a2013-03-07 15:14:13 +00006478 Name* key = descriptor->GetKey();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006479 int insertion_index = new_descriptors->number_of_descriptors() - 1;
6480
6481 return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006482}
6483
6484
6485MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor,
6486 TransitionFlag flag) {
6487 DescriptorArray* old_descriptors = instance_descriptors();
6488
ulan@chromium.org750145a2013-03-07 15:14:13 +00006489 // Ensure the key is unique.
6490 MaybeObject* maybe_result = descriptor->KeyToUniqueName();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006491 if (maybe_result->IsFailure()) return maybe_result;
6492
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006493 // We replace the key if it is already present.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006494 int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006495 if (index != DescriptorArray::kNotFound) {
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006496 return CopyReplaceDescriptor(old_descriptors, descriptor, index, flag);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00006497 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006498 return CopyAddDescriptor(descriptor, flag);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006499}
6500
6501
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006502MaybeObject* DescriptorArray::CopyUpTo(int enumeration_index) {
6503 if (enumeration_index == 0) return GetHeap()->empty_descriptor_array();
6504
6505 int size = enumeration_index;
6506
6507 DescriptorArray* descriptors;
6508 MaybeObject* maybe_descriptors = Allocate(size);
6509 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors;
6510 DescriptorArray::WhitenessWitness witness(descriptors);
6511
6512 for (int i = 0; i < size; ++i) {
6513 descriptors->CopyFrom(i, this, i, witness);
6514 }
6515
6516 if (number_of_descriptors() != enumeration_index) descriptors->Sort();
6517
6518 return descriptors;
6519}
6520
6521
jkummerow@chromium.orgc1956672012-10-11 15:57:38 +00006522MaybeObject* Map::CopyReplaceDescriptor(DescriptorArray* descriptors,
6523 Descriptor* descriptor,
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006524 int insertion_index,
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006525 TransitionFlag flag) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00006526 // Ensure the key is unique.
6527 MaybeObject* maybe_failure = descriptor->KeyToUniqueName();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006528 if (maybe_failure->IsFailure()) return maybe_failure;
6529
ulan@chromium.org750145a2013-03-07 15:14:13 +00006530 Name* key = descriptor->GetKey();
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006531 ASSERT(key == descriptors->GetKey(insertion_index));
6532
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006533 int new_size = NumberOfOwnDescriptors();
6534 ASSERT(0 <= insertion_index && insertion_index < new_size);
verwaest@chromium.org652f4fa2012-10-08 08:48:51 +00006535
ulan@chromium.org57ff8812013-05-10 08:16:55 +00006536 ASSERT_LT(insertion_index, new_size);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006537
6538 DescriptorArray* new_descriptors;
6539 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size);
6540 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
ulan@chromium.org56c14af2012-09-20 12:51:09 +00006541 DescriptorArray::WhitenessWitness witness(new_descriptors);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006542
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006543 for (int i = 0; i < new_size; ++i) {
6544 if (i == insertion_index) {
6545 new_descriptors->Set(i, descriptor, witness);
6546 } else {
6547 new_descriptors->CopyFrom(i, descriptors, i, witness);
6548 }
yangguo@chromium.org304cc332012-07-24 07:59:48 +00006549 }
6550
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00006551 // Re-sort if descriptors were removed.
6552 if (new_size != descriptors->length()) new_descriptors->Sort();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00006553
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00006554 return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006555}
6556
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006557
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006558void Map::UpdateCodeCache(Handle<Map> map,
ulan@chromium.org750145a2013-03-07 15:14:13 +00006559 Handle<Name> name,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006560 Handle<Code> code) {
6561 Isolate* isolate = map->GetIsolate();
6562 CALL_HEAP_FUNCTION_VOID(isolate,
6563 map->UpdateCodeCache(*name, *code));
6564}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006565
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006566
ulan@chromium.org750145a2013-03-07 15:14:13 +00006567MaybeObject* Map::UpdateCodeCache(Name* name, Code* code) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006568 ASSERT(!is_shared() || code->allowed_in_shared_map_code_cache());
6569
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006570 // Allocate the code cache if not present.
6571 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006572 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006573 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00006574 if (!maybe_result->ToObject(&result)) return maybe_result;
6575 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006576 set_code_cache(result);
6577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006579 // Update the code cache.
6580 return CodeCache::cast(code_cache())->Update(name, code);
6581}
6582
6583
ulan@chromium.org750145a2013-03-07 15:14:13 +00006584Object* Map::FindInCodeCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006585 // Do a lookup if a code cache exists.
6586 if (!code_cache()->IsFixedArray()) {
6587 return CodeCache::cast(code_cache())->Lookup(name, flags);
6588 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006589 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006590 }
6591}
6592
6593
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00006594int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006595 // Get the internal index if a code cache exists.
6596 if (!code_cache()->IsFixedArray()) {
6597 return CodeCache::cast(code_cache())->GetIndex(name, code);
6598 }
6599 return -1;
6600}
6601
6602
ulan@chromium.org750145a2013-03-07 15:14:13 +00006603void Map::RemoveFromCodeCache(Name* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006604 // No GC is supposed to happen between a call to IndexInCodeCache and
6605 // RemoveFromCodeCache so the code cache must be there.
6606 ASSERT(!code_cache()->IsFixedArray());
6607 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
6608}
6609
6610
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006611// An iterator over all map transitions in an descriptor array, reusing the map
6612// field of the contens array while it is running.
6613class IntrusiveMapTransitionIterator {
6614 public:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006615 explicit IntrusiveMapTransitionIterator(TransitionArray* transition_array)
6616 : transition_array_(transition_array) { }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00006617
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006618 void Start() {
6619 ASSERT(!IsIterating());
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006620 *TransitionArrayHeader() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006621 }
6622
6623 bool IsIterating() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006624 return (*TransitionArrayHeader())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006625 }
6626
6627 Map* Next() {
6628 ASSERT(IsIterating());
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006629 int index = Smi::cast(*TransitionArrayHeader())->value();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006630 int number_of_transitions = transition_array_->number_of_transitions();
6631 while (index < number_of_transitions) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006632 *TransitionArrayHeader() = Smi::FromInt(index + 1);
6633 return transition_array_->GetTarget(index);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006634 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006635
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006636 if (index == number_of_transitions &&
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006637 transition_array_->HasElementsTransition()) {
6638 Map* elements_transition = transition_array_->elements_transition();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00006639 *TransitionArrayHeader() = Smi::FromInt(index + 1);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006640 return elements_transition;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00006641 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006642 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006643 return NULL;
6644 }
6645
6646 private:
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006647 Object** TransitionArrayHeader() {
6648 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006649 }
6650
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006651 TransitionArray* transition_array_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006652};
6653
6654
6655// An iterator over all prototype transitions, reusing the map field of the
6656// underlying array while it is running.
6657class IntrusivePrototypeTransitionIterator {
6658 public:
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00006659 explicit IntrusivePrototypeTransitionIterator(HeapObject* proto_trans)
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006660 : proto_trans_(proto_trans) { }
6661
6662 void Start() {
6663 ASSERT(!IsIterating());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00006664 *Header() = Smi::FromInt(0);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006665 }
6666
6667 bool IsIterating() {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00006668 return (*Header())->IsSmi();
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006669 }
6670
6671 Map* Next() {
6672 ASSERT(IsIterating());
6673 int transitionNumber = Smi::cast(*Header())->value();
6674 if (transitionNumber < NumberOfTransitions()) {
6675 *Header() = Smi::FromInt(transitionNumber + 1);
6676 return GetTransition(transitionNumber);
6677 }
6678 *Header() = proto_trans_->GetHeap()->fixed_array_map();
6679 return NULL;
6680 }
6681
6682 private:
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006683 Object** Header() {
6684 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
6685 }
6686
6687 int NumberOfTransitions() {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00006688 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
6689 Object* num = proto_trans->get(Map::kProtoTransitionNumberOfEntriesOffset);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006690 return Smi::cast(num)->value();
6691 }
6692
6693 Map* GetTransition(int transitionNumber) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00006694 FixedArray* proto_trans = reinterpret_cast<FixedArray*>(proto_trans_);
6695 return Map::cast(proto_trans->get(IndexFor(transitionNumber)));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006696 }
6697
6698 int IndexFor(int transitionNumber) {
6699 return Map::kProtoTransitionHeaderSize +
6700 Map::kProtoTransitionMapOffset +
6701 transitionNumber * Map::kProtoTransitionElementsPerEntry;
6702 }
6703
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00006704 HeapObject* proto_trans_;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006705};
6706
6707
6708// To traverse the transition tree iteratively, we have to store two kinds of
6709// information in a map: The parent map in the traversal and which children of a
6710// node have already been visited. To do this without additional memory, we
6711// temporarily reuse two maps with known values:
6712//
6713// (1) The map of the map temporarily holds the parent, and is restored to the
6714// meta map afterwards.
6715//
6716// (2) The info which children have already been visited depends on which part
6717// of the map we currently iterate:
6718//
6719// (a) If we currently follow normal map transitions, we temporarily store
6720// the current index in the map of the FixedArray of the desciptor
6721// array's contents, and restore it to the fixed array map afterwards.
6722// Note that a single descriptor can have 0, 1, or 2 transitions.
6723//
6724// (b) If we currently follow prototype transitions, we temporarily store
6725// the current index in the map of the FixedArray holding the prototype
6726// transitions, and restore it to the fixed array map afterwards.
6727//
6728// Note that the child iterator is just a concatenation of two iterators: One
6729// iterating over map transitions and one iterating over prototype transisitons.
6730class TraversableMap : public Map {
6731 public:
6732 // Record the parent in the traversal within this map. Note that this destroys
6733 // this map's map!
6734 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
6735
6736 // Reset the current map's map, returning the parent previously stored in it.
6737 TraversableMap* GetAndResetParent() {
6738 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
6739 set_map_no_write_barrier(GetHeap()->meta_map());
6740 return old_parent;
6741 }
6742
6743 // Start iterating over this map's children, possibly destroying a FixedArray
6744 // map (see explanation above).
6745 void ChildIteratorStart() {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006746 if (HasTransitionArray()) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +00006747 if (HasPrototypeTransitions()) {
6748 IntrusivePrototypeTransitionIterator(GetPrototypeTransitions()).Start();
6749 }
6750
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006751 IntrusiveMapTransitionIterator(transitions()).Start();
6752 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006753 }
6754
6755 // If we have an unvisited child map, return that one and advance. If we have
6756 // none, return NULL and reset any destroyed FixedArray maps.
6757 TraversableMap* ChildIteratorNext() {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006758 TransitionArray* transition_array = unchecked_transition_array();
6759 if (!transition_array->map()->IsSmi() &&
6760 !transition_array->IsTransitionArray()) {
6761 return NULL;
6762 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00006763
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006764 if (transition_array->HasPrototypeTransitions()) {
6765 HeapObject* proto_transitions =
6766 transition_array->UncheckedPrototypeTransitions();
6767 IntrusivePrototypeTransitionIterator proto_iterator(proto_transitions);
6768 if (proto_iterator.IsIterating()) {
6769 Map* next = proto_iterator.Next();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00006770 if (next != NULL) return static_cast<TraversableMap*>(next);
6771 }
verwaest@chromium.org37141392012-05-31 13:27:02 +00006772 }
danno@chromium.org81cac2b2012-07-10 11:28:27 +00006773
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00006774 IntrusiveMapTransitionIterator transition_iterator(transition_array);
6775 if (transition_iterator.IsIterating()) {
6776 Map* next = transition_iterator.Next();
6777 if (next != NULL) return static_cast<TraversableMap*>(next);
6778 }
6779
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00006780 return NULL;
6781 }
6782};
6783
6784
6785// Traverse the transition tree in postorder without using the C++ stack by
6786// doing pointer reversal.
6787void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
6788 TraversableMap* current = static_cast<TraversableMap*>(this);
6789 current->ChildIteratorStart();
6790 while (true) {
6791 TraversableMap* child = current->ChildIteratorNext();
6792 if (child != NULL) {
6793 child->ChildIteratorStart();
6794 child->SetParent(current);
6795 current = child;
6796 } else {
6797 TraversableMap* parent = current->GetAndResetParent();
6798 callback(current, data);
6799 if (current == this) break;
6800 current = parent;
6801 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006802 }
6803}
6804
6805
ulan@chromium.org750145a2013-03-07 15:14:13 +00006806MaybeObject* CodeCache::Update(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006807 // The number of monomorphic stubs for normal load/store/call IC's can grow to
6808 // a large number and therefore they need to go into a hash table. They are
6809 // used to load global properties from cells.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00006810 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006811 // Make sure that a hash table is allocated for the normal load code cache.
6812 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006813 Object* result;
6814 { MaybeObject* maybe_result =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00006815 CodeCacheHashTable::Allocate(GetHeap(),
6816 CodeCacheHashTable::kInitialSize);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006817 if (!maybe_result->ToObject(&result)) return maybe_result;
6818 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006819 set_normal_type_cache(result);
6820 }
6821 return UpdateNormalTypeCache(name, code);
6822 } else {
6823 ASSERT(default_cache()->IsFixedArray());
6824 return UpdateDefaultCache(name, code);
6825 }
6826}
6827
6828
ulan@chromium.org750145a2013-03-07 15:14:13 +00006829MaybeObject* CodeCache::UpdateDefaultCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006830 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006831 // flags. This allows call constant stubs to overwrite call field
6832 // stubs, etc.
6833 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
6834
6835 // First check whether we can update existing code cache without
6836 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006837 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00006839 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006840 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006841 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00006842 if (key->IsNull()) {
6843 if (deleted_index < 0) deleted_index = i;
6844 continue;
6845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006847 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006848 cache->set(i + kCodeCacheEntryNameOffset, name);
6849 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 return this;
6851 }
ulan@chromium.org750145a2013-03-07 15:14:13 +00006852 if (name->Equals(Name::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006853 Code::Flags found =
6854 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006855 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006856 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006857 return this;
6858 }
6859 }
6860 }
6861
ager@chromium.org236ad962008-09-25 09:45:57 +00006862 // Reached the end of the code cache. If there were deleted
6863 // elements, reuse the space for the first of them.
6864 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006865 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
6866 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00006867 return this;
6868 }
6869
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006870 // Extend the code cache with some new entries (at least one). Must be a
6871 // multiple of the entry size.
6872 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
6873 new_length = new_length - new_length % kCodeCacheEntrySize;
6874 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006875 Object* result;
6876 { MaybeObject* maybe_result = cache->CopySize(new_length);
6877 if (!maybe_result->ToObject(&result)) return maybe_result;
6878 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006879
6880 // Add the (name, code) pair to the new cache.
6881 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006882 cache->set(length + kCodeCacheEntryNameOffset, name);
6883 cache->set(length + kCodeCacheEntryCodeOffset, code);
6884 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006885 return this;
6886}
6887
6888
ulan@chromium.org750145a2013-03-07 15:14:13 +00006889MaybeObject* CodeCache::UpdateNormalTypeCache(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006890 // Adding a new entry can cause a new cache to be allocated.
6891 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00006892 Object* new_cache;
6893 { MaybeObject* maybe_new_cache = cache->Put(name, code);
6894 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
6895 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006896 set_normal_type_cache(new_cache);
6897 return this;
6898}
6899
6900
ulan@chromium.org750145a2013-03-07 15:14:13 +00006901Object* CodeCache::Lookup(Name* name, Code::Flags flags) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00006902 if (Code::ExtractTypeFromFlags(flags) == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006903 return LookupNormalTypeCache(name, flags);
6904 } else {
6905 return LookupDefaultCache(name, flags);
6906 }
6907}
6908
6909
ulan@chromium.org750145a2013-03-07 15:14:13 +00006910Object* CodeCache::LookupDefaultCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006911 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006912 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006913 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
6914 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00006915 // Skip deleted elements.
6916 if (key->IsNull()) continue;
6917 if (key->IsUndefined()) return key;
ulan@chromium.org750145a2013-03-07 15:14:13 +00006918 if (name->Equals(Name::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006919 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
6920 if (code->flags() == flags) {
6921 return code;
6922 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006923 }
6924 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006925 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006926}
6927
6928
ulan@chromium.org750145a2013-03-07 15:14:13 +00006929Object* CodeCache::LookupNormalTypeCache(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006930 if (!normal_type_cache()->IsUndefined()) {
6931 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
6932 return cache->Lookup(name, flags);
6933 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006934 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006935 }
6936}
6937
6938
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00006939int CodeCache::GetIndex(Object* name, Code* code) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00006940 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006941 if (normal_type_cache()->IsUndefined()) return -1;
6942 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
ulan@chromium.org750145a2013-03-07 15:14:13 +00006943 return cache->GetIndex(Name::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006944 }
6945
6946 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006948 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
6949 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006951 return -1;
6952}
6953
6954
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00006955void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00006956 if (code->type() == Code::NORMAL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006957 ASSERT(!normal_type_cache()->IsUndefined());
6958 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
ulan@chromium.org750145a2013-03-07 15:14:13 +00006959 ASSERT(cache->GetIndex(Name::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006960 cache->RemoveByIndex(index);
6961 } else {
6962 FixedArray* array = default_cache();
6963 ASSERT(array->length() >= index && array->get(index)->IsCode());
6964 // Use null instead of undefined for deleted elements to distinguish
6965 // deleted elements from unused elements. This distinction is used
6966 // when looking up in the cache and when updating the cache.
6967 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
6968 array->set_null(index - 1); // Name.
6969 array->set_null(index); // Code.
6970 }
6971}
6972
6973
6974// The key in the code cache hash table consists of the property name and the
6975// code object. The actual match is on the name and the code flags. If a key
6976// is created using the flags and not a code object it can only be used for
6977// lookup not to create a new entry.
6978class CodeCacheHashTableKey : public HashTableKey {
6979 public:
ulan@chromium.org750145a2013-03-07 15:14:13 +00006980 CodeCacheHashTableKey(Name* name, Code::Flags flags)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006981 : name_(name), flags_(flags), code_(NULL) { }
6982
ulan@chromium.org750145a2013-03-07 15:14:13 +00006983 CodeCacheHashTableKey(Name* name, Code* code)
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006984 : name_(name),
6985 flags_(code->flags()),
6986 code_(code) { }
6987
6988
6989 bool IsMatch(Object* other) {
6990 if (!other->IsFixedArray()) return false;
6991 FixedArray* pair = FixedArray::cast(other);
ulan@chromium.org750145a2013-03-07 15:14:13 +00006992 Name* name = Name::cast(pair->get(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006993 Code::Flags flags = Code::cast(pair->get(1))->flags();
6994 if (flags != flags_) {
6995 return false;
6996 }
6997 return name_->Equals(name);
6998 }
6999
ulan@chromium.org750145a2013-03-07 15:14:13 +00007000 static uint32_t NameFlagsHashHelper(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007001 return name->Hash() ^ flags;
7002 }
7003
7004 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
7005
7006 uint32_t HashForObject(Object* obj) {
7007 FixedArray* pair = FixedArray::cast(obj);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007008 Name* name = Name::cast(pair->get(0));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007009 Code* code = Code::cast(pair->get(1));
7010 return NameFlagsHashHelper(name, code->flags());
7011 }
7012
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007013 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007014 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007015 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007016 { MaybeObject* maybe_obj = heap->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007017 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7018 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007019 FixedArray* pair = FixedArray::cast(obj);
7020 pair->set(0, name_);
7021 pair->set(1, code_);
7022 return pair;
7023 }
7024
7025 private:
ulan@chromium.org750145a2013-03-07 15:14:13 +00007026 Name* name_;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007027 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007028 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007029 Code* code_;
7030};
7031
7032
ulan@chromium.org750145a2013-03-07 15:14:13 +00007033Object* CodeCacheHashTable::Lookup(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007034 CodeCacheHashTableKey key(name, flags);
7035 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007036 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007037 return get(EntryToIndex(entry) + 1);
7038}
7039
7040
ulan@chromium.org750145a2013-03-07 15:14:13 +00007041MaybeObject* CodeCacheHashTable::Put(Name* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007042 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007043 Object* obj;
7044 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
7045 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7046 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007047
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007048 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007049 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
7050
7051 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007052 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007053 { MaybeObject* maybe_k = key.AsObject(GetHeap());
lrn@chromium.org303ada72010-10-27 09:33:13 +00007054 if (!maybe_k->ToObject(&k)) return maybe_k;
7055 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007056
7057 cache->set(EntryToIndex(entry), k);
7058 cache->set(EntryToIndex(entry) + 1, code);
7059 cache->ElementAdded();
7060 return cache;
7061}
7062
7063
ulan@chromium.org750145a2013-03-07 15:14:13 +00007064int CodeCacheHashTable::GetIndex(Name* name, Code::Flags flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007065 CodeCacheHashTableKey key(name, flags);
7066 int entry = FindEntry(&key);
7067 return (entry == kNotFound) ? -1 : entry;
7068}
7069
7070
7071void CodeCacheHashTable::RemoveByIndex(int index) {
7072 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007074 set(EntryToIndex(index), heap->the_hole_value());
7075 set(EntryToIndex(index) + 1, heap->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007076 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077}
7078
7079
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007080void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
7081 MapHandleList* maps,
7082 Code::Flags flags,
7083 Handle<Code> code) {
7084 Isolate* isolate = cache->GetIsolate();
7085 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
7086}
7087
7088
7089MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007090 Code::Flags flags,
7091 Code* code) {
7092 // Initialize cache if necessary.
7093 if (cache()->IsUndefined()) {
7094 Object* result;
7095 { MaybeObject* maybe_result =
7096 PolymorphicCodeCacheHashTable::Allocate(
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007097 GetHeap(),
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007098 PolymorphicCodeCacheHashTable::kInitialSize);
7099 if (!maybe_result->ToObject(&result)) return maybe_result;
7100 }
7101 set_cache(result);
7102 } else {
7103 // This entry shouldn't be contained in the cache yet.
7104 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
7105 ->Lookup(maps, flags)->IsUndefined());
7106 }
7107 PolymorphicCodeCacheHashTable* hash_table =
7108 PolymorphicCodeCacheHashTable::cast(cache());
7109 Object* new_cache;
7110 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
7111 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
7112 }
7113 set_cache(new_cache);
7114 return this;
7115}
7116
7117
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007118Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
7119 Code::Flags flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007120 if (!cache()->IsUndefined()) {
7121 PolymorphicCodeCacheHashTable* hash_table =
7122 PolymorphicCodeCacheHashTable::cast(cache());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00007123 return Handle<Object>(hash_table->Lookup(maps, flags), GetIsolate());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007124 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007125 return GetIsolate()->factory()->undefined_value();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007126 }
7127}
7128
7129
7130// Despite their name, object of this class are not stored in the actual
7131// hash table; instead they're temporarily used for lookups. It is therefore
7132// safe to have a weak (non-owning) pointer to a MapList as a member field.
7133class PolymorphicCodeCacheHashTableKey : public HashTableKey {
7134 public:
7135 // Callers must ensure that |maps| outlives the newly constructed object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007136 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007137 : maps_(maps),
7138 code_flags_(code_flags) {}
7139
7140 bool IsMatch(Object* other) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007141 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007142 int other_flags;
7143 FromObject(other, &other_flags, &other_maps);
7144 if (code_flags_ != other_flags) return false;
7145 if (maps_->length() != other_maps.length()) return false;
7146 // Compare just the hashes first because it's faster.
7147 int this_hash = MapsHashHelper(maps_, code_flags_);
7148 int other_hash = MapsHashHelper(&other_maps, other_flags);
7149 if (this_hash != other_hash) return false;
7150
7151 // Full comparison: for each map in maps_, look for an equivalent map in
7152 // other_maps. This implementation is slow, but probably good enough for
7153 // now because the lists are short (<= 4 elements currently).
7154 for (int i = 0; i < maps_->length(); ++i) {
7155 bool match_found = false;
7156 for (int j = 0; j < other_maps.length(); ++j) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00007157 if (*(maps_->at(i)) == *(other_maps.at(j))) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007158 match_found = true;
7159 break;
7160 }
7161 }
7162 if (!match_found) return false;
7163 }
7164 return true;
7165 }
7166
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007167 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007168 uint32_t hash = code_flags;
7169 for (int i = 0; i < maps->length(); ++i) {
7170 hash ^= maps->at(i)->Hash();
7171 }
7172 return hash;
7173 }
7174
7175 uint32_t Hash() {
7176 return MapsHashHelper(maps_, code_flags_);
7177 }
7178
7179 uint32_t HashForObject(Object* obj) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007180 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007181 int other_flags;
7182 FromObject(obj, &other_flags, &other_maps);
7183 return MapsHashHelper(&other_maps, other_flags);
7184 }
7185
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007186 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007187 Object* obj;
7188 // The maps in |maps_| must be copied to a newly allocated FixedArray,
7189 // both because the referenced MapList is short-lived, and because C++
7190 // objects can't be stored in the heap anyway.
7191 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007192 heap->AllocateUninitializedFixedArray(maps_->length() + 1);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007193 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7194 }
7195 FixedArray* list = FixedArray::cast(obj);
7196 list->set(0, Smi::FromInt(code_flags_));
7197 for (int i = 0; i < maps_->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007198 list->set(i + 1, *maps_->at(i));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007199 }
7200 return list;
7201 }
7202
7203 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007204 static MapHandleList* FromObject(Object* obj,
7205 int* code_flags,
7206 MapHandleList* maps) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007207 FixedArray* list = FixedArray::cast(obj);
7208 maps->Rewind(0);
7209 *code_flags = Smi::cast(list->get(0))->value();
7210 for (int i = 1; i < list->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007211 maps->Add(Handle<Map>(Map::cast(list->get(i))));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007212 }
7213 return maps;
7214 }
7215
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007216 MapHandleList* maps_; // weak.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007217 int code_flags_;
whesse@chromium.org7b260152011-06-20 15:33:18 +00007218 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007219};
7220
7221
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007222Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
7223 int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007224 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
7225 int entry = FindEntry(&key);
7226 if (entry == kNotFound) return GetHeap()->undefined_value();
7227 return get(EntryToIndex(entry) + 1);
7228}
7229
7230
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007231MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007232 int code_flags,
7233 Code* code) {
7234 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
7235 Object* obj;
7236 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
7237 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7238 }
7239 PolymorphicCodeCacheHashTable* cache =
7240 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
7241 int entry = cache->FindInsertionEntry(key.Hash());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00007242 { MaybeObject* maybe_obj = key.AsObject(GetHeap());
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007243 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7244 }
7245 cache->set(EntryToIndex(entry), obj);
7246 cache->set(EntryToIndex(entry) + 1, code);
7247 cache->ElementAdded();
7248 return cache;
7249}
7250
7251
lrn@chromium.org303ada72010-10-27 09:33:13 +00007252MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007253 ElementsAccessor* accessor = array->GetElementsAccessor();
7254 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007255 accessor->AddElementsToFixedArray(array, array, this);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007256 FixedArray* result;
7257 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
7258#ifdef DEBUG
7259 if (FLAG_enable_slow_asserts) {
7260 for (int i = 0; i < result->length(); i++) {
7261 Object* current = result->get(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007262 ASSERT(current->IsNumber() || current->IsName());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00007263 }
7264 }
7265#endif
7266 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267}
7268
7269
lrn@chromium.org303ada72010-10-27 09:33:13 +00007270MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007271 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
7272 MaybeObject* maybe_result =
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007273 accessor->AddElementsToFixedArray(NULL, NULL, this, other);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007274 FixedArray* result;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00007275 if (!maybe_result->To(&result)) return maybe_result;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007276#ifdef DEBUG
7277 if (FLAG_enable_slow_asserts) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00007278 for (int i = 0; i < result->length(); i++) {
7279 Object* current = result->get(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +00007280 ASSERT(current->IsNumber() || current->IsName());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007281 }
7282 }
7283#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 return result;
7285}
7286
7287
lrn@chromium.org303ada72010-10-27 09:33:13 +00007288MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 Heap* heap = GetHeap();
7290 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007291 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007292 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007293 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7294 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007295 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007296 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007297 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298 int len = length();
7299 if (new_length < len) len = new_length;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007300 // We are taking the map from the old fixed array so the map is sure to
7301 // be an immortal immutable object.
7302 result->set_map_no_write_barrier(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007303 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304 for (int i = 0; i < len; i++) {
7305 result->set(i, get(i), mode);
7306 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307 return result;
7308}
7309
7310
7311void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007312 AssertNoAllocation no_gc;
7313 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314 for (int index = 0; index < len; index++) {
7315 dest->set(dest_pos+index, get(pos+index), mode);
7316 }
7317}
7318
7319
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007320#ifdef DEBUG
7321bool FixedArray::IsEqualTo(FixedArray* other) {
7322 if (length() != other->length()) return false;
7323 for (int i = 0 ; i < length(); ++i) {
7324 if (get(i) != other->get(i)) return false;
7325 }
7326 return true;
7327}
7328#endif
7329
7330
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007331MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007332 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007333 // Do not use DescriptorArray::cast on incomplete object.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007334 int size = number_of_descriptors + slack;
7335 if (size == 0) return heap->empty_descriptor_array();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00007336 FixedArray* result;
verwaest@chromium.org50915592012-06-18 12:15:44 +00007337 // Allocate the array of keys.
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007338 MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size));
danno@chromium.org129d3982012-07-25 15:01:47 +00007339 if (!maybe_array->To(&result)) return maybe_array;
verwaest@chromium.org50915592012-06-18 12:15:44 +00007340
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007341 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors));
yangguo@chromium.org304cc332012-07-24 07:59:48 +00007342 result->set(kEnumCacheIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007343 return result;
7344}
7345
7346
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007347void DescriptorArray::ClearEnumCache() {
7348 set(kEnumCacheIndex, Smi::FromInt(0));
7349}
7350
7351
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007352void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007353 FixedArray* new_cache,
7354 Object* new_index_cache) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007355 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00007356 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00007357 ASSERT(!IsEmpty());
7358 ASSERT(!HasEnumCache() || new_cache->length() > GetEnumCache()->length());
7359 FixedArray::cast(bridge_storage)->
7360 set(kEnumCacheBridgeCacheIndex, new_cache);
7361 FixedArray::cast(bridge_storage)->
7362 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache);
7363 set(kEnumCacheIndex, bridge_storage);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364}
7365
7366
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007367void DescriptorArray::CopyFrom(int dst_index,
7368 DescriptorArray* src,
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007369 int src_index,
7370 const WhitenessWitness& witness) {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007371 Object* value = src->GetValue(src_index);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00007372 PropertyDetails details = src->GetDetails(src_index);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007373 Descriptor desc(src->GetKey(src_index), value, details);
7374 Set(dst_index, &desc, witness);
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007375}
7376
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007378// Generalize the |other| descriptor array by merging it into the (at least
danno@chromium.orgf005df62013-04-30 16:36:45 +00007379// partly) updated |this| descriptor array.
7380// The method merges two descriptor array in three parts. Both descriptor arrays
7381// are identical up to |verbatim|. They also overlap in keys up to |valid|.
7382// Between |verbatim| and |valid|, the resulting descriptor type as well as the
7383// representation are generalized from both |this| and |other|. Beyond |valid|,
7384// the descriptors are copied verbatim from |other| up to |new_size|.
7385// In case of incompatible types, the type and representation of |other| is
7386// used.
7387MaybeObject* DescriptorArray::Merge(int verbatim,
7388 int valid,
7389 int new_size,
7390 DescriptorArray* other) {
7391 ASSERT(verbatim <= valid);
7392 ASSERT(valid <= new_size);
7393
7394 DescriptorArray* result;
7395 // Allocate a new descriptor array large enough to hold the required
7396 // descriptors, with minimally the exact same size as this descriptor array.
7397 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007398 new_size, Max(new_size, other->number_of_descriptors()) - new_size);
danno@chromium.orgf005df62013-04-30 16:36:45 +00007399 if (!maybe_descriptors->To(&result)) return maybe_descriptors;
7400 ASSERT(result->length() > length() ||
7401 result->NumberOfSlackDescriptors() > 0 ||
7402 result->number_of_descriptors() == other->number_of_descriptors());
7403 ASSERT(result->number_of_descriptors() == new_size);
7404
7405 DescriptorArray::WhitenessWitness witness(result);
7406
7407 int descriptor;
7408
7409 // 0 -> |verbatim|
7410 int current_offset = 0;
7411 for (descriptor = 0; descriptor < verbatim; descriptor++) {
7412 if (GetDetails(descriptor).type() == FIELD) current_offset++;
7413 result->CopyFrom(descriptor, this, descriptor, witness);
7414 }
7415
7416 // |verbatim| -> |valid|
7417 for (; descriptor < valid; descriptor++) {
7418 Name* key = GetKey(descriptor);
7419 PropertyDetails details = GetDetails(descriptor);
7420 PropertyDetails other_details = other->GetDetails(descriptor);
danno@chromium.orgf005df62013-04-30 16:36:45 +00007421
7422 if (details.type() == FIELD || other_details.type() == FIELD ||
7423 (details.type() == CONSTANT_FUNCTION &&
7424 other_details.type() == CONSTANT_FUNCTION &&
7425 GetValue(descriptor) != other->GetValue(descriptor))) {
7426 Representation representation =
7427 details.representation().generalize(other_details.representation());
7428 FieldDescriptor d(key,
7429 current_offset++,
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007430 other_details.attributes(),
7431 representation);
danno@chromium.orgf005df62013-04-30 16:36:45 +00007432 result->Set(descriptor, &d, witness);
7433 } else {
7434 result->CopyFrom(descriptor, other, descriptor, witness);
7435 }
7436 }
7437
7438 // |valid| -> |new_size|
7439 for (; descriptor < new_size; descriptor++) {
7440 PropertyDetails details = other->GetDetails(descriptor);
7441 if (details.type() == FIELD) {
7442 Name* key = other->GetKey(descriptor);
7443 FieldDescriptor d(key,
7444 current_offset++,
7445 details.attributes(),
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007446 details.representation());
danno@chromium.orgf005df62013-04-30 16:36:45 +00007447 result->Set(descriptor, &d, witness);
7448 } else {
7449 result->CopyFrom(descriptor, other, descriptor, witness);
7450 }
7451 }
7452
7453 result->Sort();
7454 return result;
7455}
7456
7457
ulan@chromium.org57ff8812013-05-10 08:16:55 +00007458// Checks whether a merge of |other| into |this| would return a copy of |this|.
7459bool DescriptorArray::IsMoreGeneralThan(int verbatim,
7460 int valid,
7461 int new_size,
7462 DescriptorArray* other) {
7463 ASSERT(verbatim <= valid);
7464 ASSERT(valid <= new_size);
7465 if (valid != new_size) return false;
7466
7467 for (int descriptor = verbatim; descriptor < valid; descriptor++) {
7468 PropertyDetails details = GetDetails(descriptor);
7469 PropertyDetails other_details = other->GetDetails(descriptor);
7470 if (details.type() != other_details.type()) {
7471 if (details.type() != FIELD ||
7472 other_details.type() != CONSTANT_FUNCTION) {
7473 return false;
7474 }
7475 } else if (details.type() == CONSTANT_FUNCTION) {
7476 if (GetValue(descriptor) != other->GetValue(descriptor)) {
7477 return false;
7478 }
7479 } else if (!other_details.representation().fits_into(
7480 details.representation())) {
7481 return false;
7482 }
7483 }
7484
7485 return true;
7486}
7487
7488
verwaest@chromium.org37141392012-05-31 13:27:02 +00007489// We need the whiteness witness since sort will reshuffle the entries in the
7490// descriptor array. If the descriptor array were to be black, the shuffling
7491// would move a slot that was already recorded as pointing into an evacuation
7492// candidate. This would result in missing updates upon evacuation.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007493void DescriptorArray::Sort() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007494 // In-place heap sort.
7495 int len = number_of_descriptors();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007496 // Reset sorting since the descriptor array might contain invalid pointers.
7497 for (int i = 0; i < len; ++i) SetSortedKey(i, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007498 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007499 // Index of the last node with children
7500 const int max_parent_index = (len / 2) - 1;
7501 for (int i = max_parent_index; i >= 0; --i) {
7502 int parent_index = i;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007503 const uint32_t parent_hash = GetSortedKey(i)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007504 while (parent_index <= max_parent_index) {
7505 int child_index = 2 * parent_index + 1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007506 uint32_t child_hash = GetSortedKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007507 if (child_index + 1 < len) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007508 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007509 if (right_child_hash > child_hash) {
7510 child_index++;
7511 child_hash = right_child_hash;
7512 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007514 if (child_hash <= parent_hash) break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007515 SwapSortedKeys(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007516 // Now element at child_index could be < its children.
7517 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007518 }
7519 }
7520
7521 // Extract elements and create sorted array.
7522 for (int i = len - 1; i > 0; --i) {
7523 // Put max element at the back of the array.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007524 SwapSortedKeys(0, i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007525 // Shift down the new top element.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007526 int parent_index = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007527 const uint32_t parent_hash = GetSortedKey(parent_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007528 const int max_parent_index = (i / 2) - 1;
7529 while (parent_index <= max_parent_index) {
7530 int child_index = parent_index * 2 + 1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007531 uint32_t child_hash = GetSortedKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007532 if (child_index + 1 < i) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007533 uint32_t right_child_hash = GetSortedKey(child_index + 1)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007534 if (right_child_hash > child_hash) {
7535 child_index++;
7536 child_hash = right_child_hash;
7537 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007539 if (child_hash <= parent_hash) break;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00007540 SwapSortedKeys(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007541 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007542 }
7543 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00007544 ASSERT(IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007545}
7546
7547
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007548MaybeObject* AccessorPair::Copy() {
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007549 Heap* heap = GetHeap();
7550 AccessorPair* copy;
verwaest@chromium.org753aee42012-07-17 16:15:42 +00007551 MaybeObject* maybe_copy = heap->AllocateAccessorPair();
7552 if (!maybe_copy->To(&copy)) return maybe_copy;
7553
7554 copy->set_getter(getter());
7555 copy->set_setter(setter());
ulan@chromium.org65a89c22012-02-14 11:46:07 +00007556 return copy;
7557}
7558
7559
danno@chromium.org88aa0582012-03-23 15:11:57 +00007560Object* AccessorPair::GetComponent(AccessorComponent component) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00007561 Object* accessor = get(component);
7562 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00007563}
7564
7565
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007566MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
7567 PretenureFlag pretenure) {
7568 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007570 pretenure);
7571}
7572
7573
7574MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
7575 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007576 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
7577 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007578 pretenure);
7579}
7580
7581
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007582#ifdef DEBUG
7583bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
7584 if (IsEmpty()) return other->IsEmpty();
7585 if (other->IsEmpty()) return false;
7586 if (length() != other->length()) return false;
7587 for (int i = 0; i < length(); ++i) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +00007588 if (get(i) != other->get(i)) return false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007589 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00007590 return true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007591}
7592#endif
7593
7594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007595bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007596 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00007597 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007598}
7599
7600
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007601String::FlatContent String::GetFlatContent() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007602 int length = this->length();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007603 StringShape shape(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007604 String* string = this;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00007605 int offset = 0;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007606 if (shape.representation_tag() == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007607 ConsString* cons = ConsString::cast(string);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007608 if (cons->second()->length() != 0) {
7609 return FlatContent();
7610 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00007611 string = cons->first();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007612 shape = StringShape(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007613 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00007614 if (shape.representation_tag() == kSlicedStringTag) {
7615 SlicedString* slice = SlicedString::cast(string);
7616 offset = slice->offset();
7617 string = slice->parent();
7618 shape = StringShape(string);
7619 ASSERT(shape.representation_tag() != kConsStringTag &&
7620 shape.representation_tag() != kSlicedStringTag);
7621 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00007622 if (shape.encoding_tag() == kOneByteStringTag) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007623 const uint8_t* start;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007624 if (shape.representation_tag() == kSeqStringTag) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00007625 start = SeqOneByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007626 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00007627 start = ExternalAsciiString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007628 }
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007629 return FlatContent(Vector<const uint8_t>(start + offset, length));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007630 } else {
7631 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
7632 const uc16* start;
7633 if (shape.representation_tag() == kSeqStringTag) {
7634 start = SeqTwoByteString::cast(string)->GetChars();
7635 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00007636 start = ExternalTwoByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007637 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00007638 return FlatContent(Vector<const uc16>(start + offset, length));
ager@chromium.org7c537e22008-10-16 08:43:32 +00007639 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007640}
7641
7642
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007643SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
7644 RobustnessFlag robust_flag,
7645 int offset,
7646 int length,
7647 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007648 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007649 return SmartArrayPointer<char>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007650 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007651 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652
7653 // Negative length means the to the end of the string.
7654 if (length < 0) length = kMaxInt - offset;
7655
7656 // Compute the size of the UTF-8 string. Start at the specified offset.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007657 Access<ConsStringIteratorOp> op(
7658 heap->isolate()->objects_string_iterator());
7659 StringCharacterStream stream(this, op.value(), offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007660 int character_position = offset;
7661 int utf8_bytes = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007662 int last = unibrow::Utf16::kNoPreviousCharacter;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007663 while (stream.HasMore() && character_position++ < offset + length) {
7664 uint16_t character = stream.GetNext();
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007665 utf8_bytes += unibrow::Utf8::Length(character, last);
7666 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007667 }
7668
7669 if (length_return) {
7670 *length_return = utf8_bytes;
7671 }
7672
7673 char* result = NewArray<char>(utf8_bytes + 1);
7674
7675 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007676 stream.Reset(this, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007677 character_position = offset;
7678 int utf8_byte_position = 0;
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007679 last = unibrow::Utf16::kNoPreviousCharacter;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007680 while (stream.HasMore() && character_position++ < offset + length) {
7681 uint16_t character = stream.GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00007682 if (allow_nulls == DISALLOW_NULLS && character == 0) {
7683 character = ' ';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007684 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00007685 utf8_byte_position +=
yangguo@chromium.org154ff992012-03-13 08:09:54 +00007686 unibrow::Utf8::Encode(result + utf8_byte_position, character, last);
7687 last = character;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007688 }
7689 result[utf8_byte_position] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007690 return SmartArrayPointer<char>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007691}
7692
7693
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007694SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
7695 RobustnessFlag robust_flag,
7696 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007697 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
7698}
7699
7700
7701const uc16* String::GetTwoByteData() {
7702 return GetTwoByteData(0);
7703}
7704
7705
7706const uc16* String::GetTwoByteData(unsigned start) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00007707 ASSERT(!IsOneByteRepresentationUnderneath());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007708 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007709 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00007710 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711 case kExternalStringTag:
7712 return ExternalTwoByteString::cast(this)->
7713 ExternalTwoByteStringGetData(start);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00007714 case kSlicedStringTag: {
7715 SlicedString* slice = SlicedString::cast(this);
7716 return slice->parent()->GetTwoByteData(start + slice->offset());
7717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007718 case kConsStringTag:
7719 UNREACHABLE();
7720 return NULL;
7721 }
7722 UNREACHABLE();
7723 return NULL;
7724}
7725
7726
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007727SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007729 return SmartArrayPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007730 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007731 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007732
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007733 Access<ConsStringIteratorOp> op(
7734 heap->isolate()->objects_string_iterator());
7735 StringCharacterStream stream(this, op.value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007736
7737 uc16* result = NewArray<uc16>(length() + 1);
7738
7739 int i = 0;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00007740 while (stream.HasMore()) {
7741 uint16_t character = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742 result[i++] = character;
7743 }
7744 result[i] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007745 return SmartArrayPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007746}
7747
7748
ager@chromium.org7c537e22008-10-16 08:43:32 +00007749const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750 return reinterpret_cast<uc16*>(
7751 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
7752}
7753
7754
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007755void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007756 Isolate* isolate = Isolate::Current();
7757 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007758 while (current != NULL) {
7759 current->PostGarbageCollection();
7760 current = current->prev_;
7761 }
7762}
7763
7764
7765// Reserve space for statics needing saving and restoring.
7766int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007767 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007768}
7769
7770
7771// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00007772char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007773 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
7774 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007775 return to + ArchiveSpacePerThread();
7776}
7777
7778
7779// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00007780char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007781 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007782 return from + ArchiveSpacePerThread();
7783}
7784
7785
7786char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
7787 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
7788 Iterate(v, top);
7789 return thread_storage + ArchiveSpacePerThread();
7790}
7791
7792
7793void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007794 Isolate* isolate = Isolate::Current();
7795 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007796}
7797
7798
7799void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
7800 Relocatable* current = top;
7801 while (current != NULL) {
7802 current->IterateInstance(v);
7803 current = current->prev_;
7804 }
7805}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007806
7807
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007808FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
7809 : Relocatable(isolate),
7810 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007811 length_(str->length()) {
7812 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007813}
7814
7815
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007816FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
7817 : Relocatable(isolate),
7818 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007819 is_ascii_(true),
7820 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007821 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007822
7823
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007824void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007825 if (str_ == NULL) return;
7826 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007827 ASSERT(str->IsFlat());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007828 String::FlatContent content = str->GetFlatContent();
7829 ASSERT(content.IsFlat());
7830 is_ascii_ = content.IsAscii();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007831 if (is_ascii_) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007832 start_ = content.ToOneByteVector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007833 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007834 start_ = content.ToUC16Vector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00007835 }
7836}
7837
7838
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007839String* ConsStringIteratorOp::Operate(String* string,
7840 unsigned* offset_out,
7841 int32_t* type_out,
7842 unsigned* length_out) {
7843 ASSERT(string->IsConsString());
7844 ConsString* cons_string = ConsString::cast(string);
7845 // Set up search data.
7846 root_ = cons_string;
7847 consumed_ = *offset_out;
7848 // Now search.
7849 return Search(offset_out, type_out, length_out);
7850}
7851
7852
7853String* ConsStringIteratorOp::Search(unsigned* offset_out,
7854 int32_t* type_out,
7855 unsigned* length_out) {
7856 ConsString* cons_string = root_;
7857 // Reset the stack, pushing the root string.
7858 depth_ = 1;
7859 maximum_depth_ = 1;
7860 frames_[0] = cons_string;
7861 const unsigned consumed = consumed_;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007862 unsigned offset = 0;
7863 while (true) {
7864 // Loop until the string is found which contains the target offset.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007865 String* string = cons_string->first();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007866 unsigned length = string->length();
7867 int32_t type;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007868 if (consumed < offset + length) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007869 // Target offset is in the left branch.
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007870 // Keep going if we're still in a ConString.
7871 type = string->map()->instance_type();
7872 if ((type & kStringRepresentationMask) == kConsStringTag) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007873 cons_string = ConsString::cast(string);
7874 PushLeft(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007875 continue;
7876 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007877 // Tell the stack we're done decending.
7878 AdjustMaximumDepth();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007879 } else {
7880 // Descend right.
7881 // Update progress through the string.
7882 offset += length;
7883 // Keep going if we're still in a ConString.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007884 string = cons_string->second();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007885 type = string->map()->instance_type();
7886 if ((type & kStringRepresentationMask) == kConsStringTag) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007887 cons_string = ConsString::cast(string);
7888 PushRight(cons_string);
7889 // TODO(dcarney) Add back root optimization.
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007890 continue;
7891 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007892 // Need this to be updated for the current string.
7893 length = string->length();
7894 // Account for the possibility of an empty right leaf.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007895 // This happens only if we have asked for an offset outside the string.
7896 if (length == 0) {
7897 // Reset depth so future operations will return null immediately.
7898 Reset();
7899 return NULL;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007900 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007901 // Tell the stack we're done decending.
7902 AdjustMaximumDepth();
7903 // Pop stack so next iteration is in correct place.
7904 Pop();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007905 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007906 ASSERT(length != 0);
7907 // Adjust return values and exit.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007908 consumed_ = offset + length;
7909 *offset_out = consumed - offset;
7910 *type_out = type;
7911 *length_out = length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007912 return string;
7913 }
7914 UNREACHABLE();
7915 return NULL;
7916}
7917
7918
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007919String* ConsStringIteratorOp::NextLeaf(bool* blew_stack,
7920 int32_t* type_out,
7921 unsigned* length_out) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007922 while (true) {
7923 // Tree traversal complete.
7924 if (depth_ == 0) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007925 *blew_stack = false;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007926 return NULL;
7927 }
7928 // We've lost track of higher nodes.
7929 if (maximum_depth_ - depth_ == kStackSize) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007930 *blew_stack = true;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007931 return NULL;
7932 }
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007933 // Go right.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007934 ConsString* cons_string = frames_[OffsetForDepth(depth_ - 1)];
7935 String* string = cons_string->second();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007936 int32_t type = string->map()->instance_type();
7937 if ((type & kStringRepresentationMask) != kConsStringTag) {
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007938 // Pop stack so next iteration is in correct place.
7939 Pop();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007940 unsigned length = static_cast<unsigned>(string->length());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007941 // Could be a flattened ConsString.
7942 if (length == 0) continue;
7943 *length_out = length;
7944 *type_out = type;
7945 consumed_ += length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007946 return string;
7947 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007948 cons_string = ConsString::cast(string);
7949 // TODO(dcarney) Add back root optimization.
7950 PushRight(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007951 // Need to traverse all the way left.
7952 while (true) {
7953 // Continue left.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007954 string = cons_string->first();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007955 type = string->map()->instance_type();
7956 if ((type & kStringRepresentationMask) != kConsStringTag) {
7957 AdjustMaximumDepth();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00007958 unsigned length = static_cast<unsigned>(string->length());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007959 ASSERT(length != 0);
7960 *length_out = length;
7961 *type_out = type;
7962 consumed_ += length;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007963 return string;
7964 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00007965 cons_string = ConsString::cast(string);
7966 PushLeft(cons_string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00007967 }
7968 }
7969 UNREACHABLE();
7970 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007971}
7972
7973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974uint16_t ConsString::ConsStringGet(int index) {
7975 ASSERT(index >= 0 && index < this->length());
7976
7977 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00007978 if (second()->length() == 0) {
7979 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007980 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007981 }
7982
7983 String* string = String::cast(this);
7984
7985 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007986 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007987 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00007988 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007989 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007990 string = left;
7991 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007992 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00007993 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007994 }
7995 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007996 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007997 }
7998 }
7999
8000 UNREACHABLE();
8001 return 0;
8002}
8003
8004
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008005uint16_t SlicedString::SlicedStringGet(int index) {
8006 return parent()->Get(offset() + index);
8007}
8008
8009
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008010template <typename sinkchar>
8011void String::WriteToFlat(String* src,
8012 sinkchar* sink,
8013 int f,
8014 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008015 String* source = src;
8016 int from = f;
8017 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008018 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008019 ASSERT(0 <= from && from <= to && to <= source->length());
8020 switch (StringShape(source).full_representation_tag()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008021 case kOneByteStringTag | kExternalStringTag: {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008022 CopyChars(sink,
erikcorry0ad885c2011-11-21 13:51:57 +00008023 ExternalAsciiString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008024 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008025 return;
8026 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008027 case kTwoByteStringTag | kExternalStringTag: {
8028 const uc16* data =
erikcorry0ad885c2011-11-21 13:51:57 +00008029 ExternalTwoByteString::cast(source)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008030 CopyChars(sink,
8031 data + from,
8032 to - from);
8033 return;
8034 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008035 case kOneByteStringTag | kSeqStringTag: {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008036 CopyChars(sink,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008037 SeqOneByteString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008038 to - from);
8039 return;
8040 }
8041 case kTwoByteStringTag | kSeqStringTag: {
8042 CopyChars(sink,
8043 SeqTwoByteString::cast(source)->GetChars() + from,
8044 to - from);
8045 return;
8046 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008047 case kOneByteStringTag | kConsStringTag:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008048 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008049 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00008050 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008051 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00008052 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053 // Right hand side is longer. Recurse over left.
8054 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008055 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008056 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008057 from = 0;
8058 } else {
8059 from -= boundary;
8060 }
8061 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00008062 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008064 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00008066 String* second = cons_string->second();
ulan@chromium.org812308e2012-02-29 15:58:45 +00008067 // When repeatedly appending to a string, we get a cons string that
8068 // is unbalanced to the left, a list, essentially. We inline the
8069 // common case of sequential ascii right child.
8070 if (to - boundary == 1) {
8071 sink[boundary - from] = static_cast<sinkchar>(second->Get(0));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008072 } else if (second->IsSeqOneByteString()) {
ulan@chromium.org812308e2012-02-29 15:58:45 +00008073 CopyChars(sink + boundary - from,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00008074 SeqOneByteString::cast(second)->GetChars(),
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008075 to - boundary);
ulan@chromium.org812308e2012-02-29 15:58:45 +00008076 } else {
8077 WriteToFlat(second,
8078 sink + boundary - from,
8079 0,
8080 to - boundary);
8081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008082 to = boundary;
8083 }
8084 source = first;
8085 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008086 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008087 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00008088 case kOneByteStringTag | kSlicedStringTag:
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00008089 case kTwoByteStringTag | kSlicedStringTag: {
8090 SlicedString* slice = SlicedString::cast(source);
8091 unsigned offset = slice->offset();
8092 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
8093 return;
8094 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095 }
8096 }
8097}
8098
8099
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008100// Compares the contents of two strings by reading and comparing
8101// int-sized blocks of characters.
8102template <typename Char>
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008103static inline bool CompareRawStringContents(const Char* const a,
8104 const Char* const b,
8105 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008106 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00008107#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008108 // If this architecture isn't comfortable reading unaligned ints
8109 // then we have to check that the strings are aligned before
8110 // comparing them blockwise.
8111 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008112 uint32_t pa_addr = reinterpret_cast<uint32_t>(a);
8113 uint32_t pb_addr = reinterpret_cast<uint32_t>(b);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00008114 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008115#endif
8116 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
8117 int endpoint = length - kStepSize;
8118 // Compare blocks until we reach near the end of the string.
8119 for (; i <= endpoint; i += kStepSize) {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008120 uint32_t wa = *reinterpret_cast<const uint32_t*>(a + i);
8121 uint32_t wb = *reinterpret_cast<const uint32_t*>(b + i);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008122 if (wa != wb) {
8123 return false;
8124 }
8125 }
ager@chromium.org9085a012009-05-11 19:22:57 +00008126#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008127 }
8128#endif
8129 // Compare the remaining characters that didn't fit into a block.
8130 for (; i < length; i++) {
8131 if (a[i] != b[i]) {
8132 return false;
8133 }
8134 }
8135 return true;
8136}
8137
8138
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008139template<typename Chars1, typename Chars2>
8140class RawStringComparator : public AllStatic {
8141 public:
8142 static inline bool compare(const Chars1* a, const Chars2* b, int len) {
8143 ASSERT(sizeof(Chars1) != sizeof(Chars2));
8144 for (int i = 0; i < len; i++) {
8145 if (a[i] != b[i]) {
8146 return false;
8147 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00008148 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008149 return true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00008150 }
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008151};
8152
8153
8154template<>
8155class RawStringComparator<uint16_t, uint16_t> {
8156 public:
8157 static inline bool compare(const uint16_t* a, const uint16_t* b, int len) {
8158 return CompareRawStringContents(a, b, len);
8159 }
8160};
8161
8162
8163template<>
8164class RawStringComparator<uint8_t, uint8_t> {
8165 public:
8166 static inline bool compare(const uint8_t* a, const uint8_t* b, int len) {
8167 return CompareRawStringContents(a, b, len);
8168 }
8169};
8170
8171
8172class StringComparator {
8173 class State {
8174 public:
8175 explicit inline State(ConsStringIteratorOp* op)
8176 : op_(op), is_one_byte_(true), length_(0), buffer8_(NULL) {}
8177
8178 inline void Init(String* string, unsigned len) {
8179 op_->Reset();
8180 int32_t type = string->map()->instance_type();
8181 String::Visit(string, 0, *this, *op_, type, len);
8182 }
8183
8184 inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
8185 is_one_byte_ = true;
8186 buffer8_ = chars;
8187 length_ = length;
8188 }
8189
8190 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
8191 is_one_byte_ = false;
8192 buffer16_ = chars;
8193 length_ = length;
8194 }
8195
8196 void Advance(unsigned consumed) {
8197 ASSERT(consumed <= length_);
8198 // Still in buffer.
8199 if (length_ != consumed) {
8200 if (is_one_byte_) {
8201 buffer8_ += consumed;
8202 } else {
8203 buffer16_ += consumed;
8204 }
8205 length_ -= consumed;
8206 return;
8207 }
8208 // Advance state.
8209 ASSERT(op_->HasMore());
8210 int32_t type = 0;
8211 unsigned length = 0;
8212 String* next = op_->ContinueOperation(&type, &length);
8213 ASSERT(next != NULL);
8214 ConsStringNullOp null_op;
8215 String::Visit(next, 0, *this, null_op, type, length);
8216 }
8217
8218 ConsStringIteratorOp* const op_;
8219 bool is_one_byte_;
8220 unsigned length_;
8221 union {
8222 const uint8_t* buffer8_;
8223 const uint16_t* buffer16_;
8224 };
8225 DISALLOW_IMPLICIT_CONSTRUCTORS(State);
8226 };
8227
8228 public:
8229 inline StringComparator(ConsStringIteratorOp* op_1,
8230 ConsStringIteratorOp* op_2)
8231 : state_1_(op_1),
8232 state_2_(op_2) {
8233 }
8234
8235 template<typename Chars1, typename Chars2>
8236 static inline bool Equals(State* state_1, State* state_2, unsigned to_check) {
8237 const Chars1* a = reinterpret_cast<const Chars1*>(state_1->buffer8_);
8238 const Chars2* b = reinterpret_cast<const Chars2*>(state_2->buffer8_);
8239 return RawStringComparator<Chars1, Chars2>::compare(a, b, to_check);
8240 }
8241
8242 bool Equals(unsigned length, String* string_1, String* string_2) {
8243 ASSERT(length != 0);
8244 state_1_.Init(string_1, length);
8245 state_2_.Init(string_2, length);
8246 while (true) {
8247 unsigned to_check = Min(state_1_.length_, state_2_.length_);
8248 ASSERT(to_check > 0 && to_check <= length);
8249 bool is_equal;
8250 if (state_1_.is_one_byte_) {
8251 if (state_2_.is_one_byte_) {
8252 is_equal = Equals<uint8_t, uint8_t>(&state_1_, &state_2_, to_check);
8253 } else {
8254 is_equal = Equals<uint8_t, uint16_t>(&state_1_, &state_2_, to_check);
8255 }
8256 } else {
8257 if (state_2_.is_one_byte_) {
8258 is_equal = Equals<uint16_t, uint8_t>(&state_1_, &state_2_, to_check);
8259 } else {
8260 is_equal = Equals<uint16_t, uint16_t>(&state_1_, &state_2_, to_check);
8261 }
8262 }
8263 // Looping done.
8264 if (!is_equal) return false;
8265 length -= to_check;
8266 // Exit condition. Strings are equal.
8267 if (length == 0) return true;
8268 state_1_.Advance(to_check);
8269 state_2_.Advance(to_check);
8270 }
8271 }
8272
8273 private:
8274 State state_1_;
8275 State state_2_;
8276 DISALLOW_IMPLICIT_CONSTRUCTORS(StringComparator);
8277};
ager@chromium.org7c537e22008-10-16 08:43:32 +00008278
8279
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008280bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008281 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008282 int len = length();
8283 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284 if (len == 0) return true;
8285
8286 // Fast check: if hash code is computed for both strings
8287 // a fast negative check can be performed.
8288 if (HasHashCode() && other->HasHashCode()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008289#ifdef DEBUG
8290 if (FLAG_enable_slow_asserts) {
8291 if (Hash() != other->Hash()) {
8292 bool found_difference = false;
8293 for (int i = 0; i < len; i++) {
8294 if (Get(i) != other->Get(i)) {
8295 found_difference = true;
8296 break;
8297 }
8298 }
8299 ASSERT(found_difference);
8300 }
8301 }
8302#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303 if (Hash() != other->Hash()) return false;
8304 }
8305
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00008306 // We know the strings are both non-empty. Compare the first chars
8307 // before we try to flatten the strings.
8308 if (this->Get(0) != other->Get(0)) return false;
8309
8310 String* lhs = this->TryFlattenGetString();
8311 String* rhs = other->TryFlattenGetString();
8312
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008313 // TODO(dcarney): Compare all types of flat strings with a Visitor.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00008314 if (StringShape(lhs).IsSequentialAscii() &&
8315 StringShape(rhs).IsSequentialAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008316 const uint8_t* str1 = SeqOneByteString::cast(lhs)->GetChars();
8317 const uint8_t* str2 = SeqOneByteString::cast(rhs)->GetChars();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008318 return CompareRawStringContents(str1, str2, len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008319 }
8320
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008321 Isolate* isolate = GetIsolate();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008322 StringComparator comparator(isolate->objects_string_compare_iterator_a(),
8323 isolate->objects_string_compare_iterator_b());
8324
8325 return comparator.Equals(static_cast<unsigned>(len), lhs, rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326}
8327
8328
8329bool String::MarkAsUndetectable() {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008330 if (StringShape(this).IsInternalized()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331
8332 Map* map = this->map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008333 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008334 if (map == heap->string_map()) {
8335 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008336 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008337 } else if (map == heap->ascii_string_map()) {
8338 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008339 return true;
8340 }
8341 // Rest cannot be marked as undetectable
8342 return false;
8343}
8344
8345
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008346bool String::IsUtf8EqualTo(Vector<const char> str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008347 int slen = length();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008348 // Can't check exact length equality, but we can check bounds.
8349 int str_len = str.length();
8350 if (str_len < slen ||
8351 str_len > slen*static_cast<int>(unibrow::Utf8::kMaxEncodedSize)) {
8352 return false;
8353 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 int i;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008355 unsigned remaining_in_str = static_cast<unsigned>(str_len);
8356 const uint8_t* utf8_data = reinterpret_cast<const uint8_t*>(str.start());
8357 for (i = 0; i < slen && remaining_in_str > 0; i++) {
8358 unsigned cursor = 0;
8359 uint32_t r = unibrow::Utf8::ValueOf(utf8_data, remaining_in_str, &cursor);
8360 ASSERT(cursor > 0 && cursor <= remaining_in_str);
yangguo@chromium.org154ff992012-03-13 08:09:54 +00008361 if (r > unibrow::Utf16::kMaxNonSurrogateCharCode) {
8362 if (i > slen - 1) return false;
8363 if (Get(i++) != unibrow::Utf16::LeadSurrogate(r)) return false;
8364 if (Get(i) != unibrow::Utf16::TrailSurrogate(r)) return false;
8365 } else {
8366 if (Get(i) != r) return false;
8367 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008368 utf8_data += cursor;
8369 remaining_in_str -= cursor;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008370 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008371 return i == slen && remaining_in_str == 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008372}
8373
8374
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008375bool String::IsOneByteEqualTo(Vector<const uint8_t> str) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008376 int slen = length();
8377 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008378 FlatContent content = GetFlatContent();
8379 if (content.IsAscii()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008380 return CompareChars(content.ToOneByteVector().start(),
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008381 str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008382 }
8383 for (int i = 0; i < slen; i++) {
8384 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008385 }
8386 return true;
8387}
8388
8389
8390bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
8391 int slen = length();
8392 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008393 FlatContent content = GetFlatContent();
8394 if (content.IsTwoByte()) {
8395 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008396 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008397 for (int i = 0; i < slen; i++) {
8398 if (Get(i) != str[i]) return false;
8399 }
8400 return true;
8401}
8402
8403
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008404class IteratingStringHasher: public StringHasher {
8405 public:
8406 static inline uint32_t Hash(String* string, uint32_t seed) {
8407 const unsigned len = static_cast<unsigned>(string->length());
8408 IteratingStringHasher hasher(len, seed);
8409 if (hasher.has_trivial_hash()) {
8410 return hasher.GetHashField();
8411 }
8412 int32_t type = string->map()->instance_type();
8413 ConsStringNullOp null_op;
8414 String::Visit(string, 0, hasher, null_op, type, len);
8415 // Flat strings terminate immediately.
8416 if (hasher.consumed_ == len) {
8417 ASSERT(!string->IsConsString());
8418 return hasher.GetHashField();
8419 }
8420 ASSERT(string->IsConsString());
8421 // This is a ConsString, iterate across it.
8422 ConsStringIteratorOp op;
8423 unsigned offset = 0;
8424 unsigned leaf_length = len;
8425 string = op.Operate(string, &offset, &type, &leaf_length);
8426 while (true) {
8427 ASSERT(hasher.consumed_ < len);
8428 String::Visit(string, 0, hasher, null_op, type, leaf_length);
8429 if (hasher.consumed_ == len) break;
8430 string = op.ContinueOperation(&type, &leaf_length);
8431 // This should be taken care of by the length check.
8432 ASSERT(string != NULL);
8433 }
8434 return hasher.GetHashField();
8435 }
8436 inline void VisitOneByteString(const uint8_t* chars, unsigned length) {
8437 AddCharacters(chars, static_cast<int>(length));
8438 consumed_ += length;
8439 }
8440 inline void VisitTwoByteString(const uint16_t* chars, unsigned length) {
8441 AddCharacters(chars, static_cast<int>(length));
8442 consumed_ += length;
8443 }
8444
8445 private:
8446 inline IteratingStringHasher(int len, uint32_t seed)
8447 : StringHasher(len, seed),
8448 consumed_(0) {}
8449 unsigned consumed_;
8450 DISALLOW_COPY_AND_ASSIGN(IteratingStringHasher);
8451};
8452
8453
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008454uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008455 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008456 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008457
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008458 // Store the hash code in the object.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008459 uint32_t field = IteratingStringHasher::Hash(this, GetHeap()->HashSeed());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008460 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008461
8462 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008463 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008464 uint32_t result = field >> kHashShift;
8465 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8466 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008467}
8468
8469
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008470bool String::ComputeArrayIndex(uint32_t* index) {
8471 int length = this->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008472 if (length == 0 || length > kMaxArrayIndexSize) return false;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008473 ConsStringIteratorOp op;
8474 StringCharacterStream stream(this, &op);
8475 uint16_t ch = stream.GetNext();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008476
8477 // If the string begins with a '0' character, it must only consist
8478 // of it to be a legal array index.
8479 if (ch == '0') {
8480 *index = 0;
8481 return length == 1;
8482 }
8483
8484 // Convert string to uint32 array index; character by character.
8485 int d = ch - '0';
8486 if (d < 0 || d > 9) return false;
8487 uint32_t result = d;
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008488 while (stream.HasMore()) {
8489 d = stream.GetNext() - '0';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008490 if (d < 0 || d > 9) return false;
8491 // Check that the new result is below the 32 bit limit.
8492 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
8493 result = (result * 10) + d;
8494 }
8495
8496 *index = result;
8497 return true;
8498}
8499
8500
8501bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008502 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008503 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008504 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008505 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008506 // Isolate the array index form the full hash field.
8507 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008508 return true;
8509 } else {
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00008510 return ComputeArrayIndex(index);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008511 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008512}
8513
8514
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00008515Handle<String> SeqString::Truncate(Handle<SeqString> string, int new_length) {
8516 int new_size, old_size;
8517 int old_length = string->length();
8518 if (old_length <= new_length) return string;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008519
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00008520 if (string->IsSeqOneByteString()) {
8521 old_size = SeqOneByteString::SizeFor(old_length);
8522 new_size = SeqOneByteString::SizeFor(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008523 } else {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00008524 ASSERT(string->IsSeqTwoByteString());
8525 old_size = SeqTwoByteString::SizeFor(old_length);
8526 new_size = SeqTwoByteString::SizeFor(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008527 }
8528
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00008529 int delta = old_size - new_size;
8530 string->set_length(new_length);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008531
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00008532 Address start_of_string = string->address();
8533 ASSERT_OBJECT_ALIGNED(start_of_string);
8534 ASSERT_OBJECT_ALIGNED(start_of_string + new_size);
8535
8536 Heap* heap = string->GetHeap();
8537 NewSpace* newspace = heap->new_space();
8538 if (newspace->Contains(start_of_string) &&
8539 newspace->top() == start_of_string + old_size) {
8540 // Last allocated object in new space. Simply lower allocation top.
8541 *(newspace->allocation_top_address()) = start_of_string + new_size;
8542 } else {
8543 // Sizes are pointer size aligned, so that we can use filler objects
8544 // that are a multiple of pointer size.
8545 heap->CreateFillerObjectAt(start_of_string + new_size, delta);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008546 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00008547 if (Marking::IsBlack(Marking::MarkBitFrom(start_of_string))) {
8548 MemoryChunk::IncrementLiveBytesFromMutator(start_of_string, -delta);
8549 }
8550
8551
8552 if (new_length == 0) return heap->isolate()->factory()->empty_string();
8553 return string;
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00008554}
8555
8556
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00008557AllocationSiteInfo* AllocationSiteInfo::FindForJSObject(JSObject* object) {
8558 // Currently, AllocationSiteInfo objects are only allocated immediately
8559 // after JSArrays in NewSpace, and detecting whether a JSArray has one
8560 // involves carefully checking the object immediately after the JSArray
8561 // (if there is one) to see if it's an AllocationSiteInfo.
8562 if (FLAG_track_allocation_sites && object->GetHeap()->InNewSpace(object)) {
8563 Address ptr_end = (reinterpret_cast<Address>(object) - kHeapObjectTag) +
8564 object->Size();
8565 if ((ptr_end + AllocationSiteInfo::kSize) <=
8566 object->GetHeap()->NewSpaceTop()) {
8567 // There is room in newspace for allocation info. Do we have some?
8568 Map** possible_allocation_site_info_map =
8569 reinterpret_cast<Map**>(ptr_end);
8570 if (*possible_allocation_site_info_map ==
8571 object->GetHeap()->allocation_site_info_map()) {
8572 AllocationSiteInfo* info = AllocationSiteInfo::cast(
8573 reinterpret_cast<Object*>(ptr_end + 1));
8574 return info;
8575 }
8576 }
8577 }
8578 return NULL;
8579}
8580
8581
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00008582bool AllocationSiteInfo::GetElementsKindPayload(ElementsKind* kind) {
8583 ASSERT(kind != NULL);
8584 if (payload()->IsJSGlobalPropertyCell()) {
8585 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(payload());
8586 Object* cell_contents = cell->value();
8587 if (cell_contents->IsSmi()) {
8588 *kind = static_cast<ElementsKind>(
8589 Smi::cast(cell_contents)->value());
8590 return true;
8591 }
8592 }
8593 return false;
8594}
8595
8596
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00008597uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00008598 // For array indexes mix the length into the hash as an array index could
8599 // be zero.
8600 ASSERT(length > 0);
8601 ASSERT(length <= String::kMaxArrayIndexSize);
8602 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
8603 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00008604
8605 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00008606 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00008607
8608 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
8609 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
8610 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00008611 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612}
8613
8614
ager@chromium.org7c537e22008-10-16 08:43:32 +00008615uint32_t StringHasher::GetHashField() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008616 if (length_ <= String::kMaxHashCalcLength) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008617 if (is_array_index_) {
8618 return MakeArrayIndexHash(array_index_, length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00008619 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008620 return (GetHashCore(raw_running_hash_) << String::kHashShift) |
8621 String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00008622 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00008623 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008624 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00008625}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008626
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008627
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008628uint32_t StringHasher::ComputeUtf8Hash(Vector<const char> chars,
8629 uint32_t seed,
8630 int* utf16_length_out) {
8631 int vector_length = chars.length();
8632 // Handle some edge cases
8633 if (vector_length <= 1) {
8634 ASSERT(vector_length == 0 ||
8635 static_cast<uint8_t>(chars.start()[0]) <=
8636 unibrow::Utf8::kMaxOneByteChar);
8637 *utf16_length_out = vector_length;
8638 return HashSequentialString(chars.start(), vector_length, seed);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008639 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008640 // Start with a fake length which won't affect computation.
8641 // It will be updated later.
8642 StringHasher hasher(String::kMaxArrayIndexSize, seed);
8643 unsigned remaining = static_cast<unsigned>(vector_length);
8644 const uint8_t* stream = reinterpret_cast<const uint8_t*>(chars.start());
8645 int utf16_length = 0;
8646 bool is_index = true;
8647 ASSERT(hasher.is_array_index_);
8648 while (remaining > 0) {
8649 unsigned consumed = 0;
8650 uint32_t c = unibrow::Utf8::ValueOf(stream, remaining, &consumed);
8651 ASSERT(consumed > 0 && consumed <= remaining);
8652 stream += consumed;
8653 remaining -= consumed;
8654 bool is_two_characters = c > unibrow::Utf16::kMaxNonSurrogateCharCode;
8655 utf16_length += is_two_characters ? 2 : 1;
8656 // No need to keep hashing. But we do need to calculate utf16_length.
8657 if (utf16_length > String::kMaxHashCalcLength) continue;
8658 if (is_two_characters) {
8659 uint16_t c1 = unibrow::Utf16::LeadSurrogate(c);
8660 uint16_t c2 = unibrow::Utf16::TrailSurrogate(c);
8661 hasher.AddCharacter(c1);
8662 hasher.AddCharacter(c2);
8663 if (is_index) is_index = hasher.UpdateIndex(c1);
8664 if (is_index) is_index = hasher.UpdateIndex(c2);
8665 } else {
8666 hasher.AddCharacter(c);
8667 if (is_index) is_index = hasher.UpdateIndex(c);
8668 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008669 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00008670 *utf16_length_out = static_cast<int>(utf16_length);
8671 // Must set length here so that hash computation is correct.
8672 hasher.length_ = utf16_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00008673 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674}
8675
8676
lrn@chromium.org303ada72010-10-27 09:33:13 +00008677MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008678 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008679 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008681 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682}
8683
8684
8685void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008686 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 for (int i = 0; i < length; i++) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00008688 PrintF(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008689 }
8690}
8691
8692
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00008693static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) {
8694 int live_enum = map->EnumLength();
8695 if (live_enum == Map::kInvalidEnumCache) {
8696 live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM);
8697 }
8698 if (live_enum == 0) return descriptors->ClearEnumCache();
8699
8700 FixedArray* enum_cache = descriptors->GetEnumCache();
8701
8702 int to_trim = enum_cache->length() - live_enum;
8703 if (to_trim <= 0) return;
8704 RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim);
8705
8706 if (!descriptors->HasEnumIndicesCache()) return;
8707 FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache();
8708 RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim);
8709}
8710
8711
8712static void TrimDescriptorArray(Heap* heap,
8713 Map* map,
8714 DescriptorArray* descriptors,
8715 int number_of_own_descriptors) {
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00008716 int number_of_descriptors = descriptors->number_of_descriptors_storage();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00008717 int to_trim = number_of_descriptors - number_of_own_descriptors;
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00008718 if (to_trim == 0) return;
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00008719
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +00008720 RightTrimFixedArray<FROM_GC>(
8721 heap, descriptors, to_trim * DescriptorArray::kDescriptorSize);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00008722 descriptors->SetNumberOfDescriptors(number_of_own_descriptors);
8723
8724 if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors);
8725 descriptors->Sort();
8726}
8727
8728
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008729// Clear a possible back pointer in case the transition leads to a dead map.
8730// Return true in case a back pointer has been cleared and false otherwise.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00008731static bool ClearBackPointer(Heap* heap, Map* target) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008732 if (Marking::MarkBitFrom(target).Get()) return false;
8733 target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008734 return true;
8735}
8736
8737
8738// TODO(mstarzinger): This method should be moved into MarkCompactCollector,
8739// because it cannot be called from outside the GC and we already have methods
8740// depending on the transitions layout in the GC anyways.
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00008741void Map::ClearNonLiveTransitions(Heap* heap) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008742 // If there are no transitions to be cleared, return.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008743 // TODO(verwaest) Should be an assert, otherwise back pointers are not
8744 // properly cleared.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008745 if (!HasTransitionArray()) return;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008746
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008747 TransitionArray* t = transitions();
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00008748 MarkCompactCollector* collector = heap->mark_compact_collector();
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008749
8750 int transition_index = 0;
8751
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00008752 DescriptorArray* descriptors = instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008753 bool descriptors_owner_died = false;
8754
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008755 // Compact all live descriptors to the left.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008756 for (int i = 0; i < t->number_of_transitions(); ++i) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008757 Map* target = t->GetTarget(i);
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00008758 if (ClearBackPointer(heap, target)) {
8759 if (target->instance_descriptors() == descriptors) {
8760 descriptors_owner_died = true;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00008761 }
8762 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008763 if (i != transition_index) {
ulan@chromium.org750145a2013-03-07 15:14:13 +00008764 Name* key = t->GetKey(i);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008765 t->SetKey(transition_index, key);
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008766 Object** key_slot = t->GetKeySlot(transition_index);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008767 collector->RecordSlot(key_slot, key_slot, key);
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00008768 // Target slots do not need to be recorded since maps are not compacted.
8769 t->SetTarget(transition_index, t->GetTarget(i));
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008770 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008771 transition_index++;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008772 }
8773 }
8774
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008775 if (t->HasElementsTransition() &&
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00008776 ClearBackPointer(heap, t->elements_transition())) {
8777 if (t->elements_transition()->instance_descriptors() == descriptors) {
8778 descriptors_owner_died = true;
8779 }
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008780 t->ClearElementsTransition();
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008781 } else {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008782 // If there are no transitions to be cleared, return.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008783 // TODO(verwaest) Should be an assert, otherwise back pointers are not
8784 // properly cleared.
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008785 if (transition_index == t->number_of_transitions()) return;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008786 }
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008787
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008788 int number_of_own_descriptors = NumberOfOwnDescriptors();
8789
8790 if (descriptors_owner_died) {
8791 if (number_of_own_descriptors > 0) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00008792 TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008793 ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors);
8794 } else {
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00008795 ASSERT(descriptors == GetHeap()->empty_descriptor_array());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008796 }
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00008797 }
8798
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00008799 int trim = t->number_of_transitions() - transition_index;
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +00008800 if (trim > 0) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00008801 RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition()
8802 ? trim : trim * TransitionArray::kTransitionSize);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008803 }
8804}
8805
8806
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008807int Map::Hash() {
8808 // For performance reasons we only hash the 3 most variable fields of a map:
8809 // constructor, prototype and bit_field2.
8810
8811 // Shift away the tag.
8812 int hash = (static_cast<uint32_t>(
8813 reinterpret_cast<uintptr_t>(constructor())) >> 2);
8814
8815 // XOR-ing the prototype and constructor directly yields too many zero bits
8816 // when the two pointers are close (which is fairly common).
8817 // To avoid this we shift the prototype 4 bits relatively to the constructor.
8818 hash ^= (static_cast<uint32_t>(
8819 reinterpret_cast<uintptr_t>(prototype())) << 2);
8820
8821 return hash ^ (hash >> 16) ^ bit_field2();
8822}
8823
8824
danno@chromium.orgf005df62013-04-30 16:36:45 +00008825static bool CheckEquivalent(Map* first, Map* second) {
8826 return
8827 first->constructor() == second->constructor() &&
8828 first->prototype() == second->prototype() &&
8829 first->instance_type() == second->instance_type() &&
8830 first->bit_field() == second->bit_field() &&
8831 first->bit_field2() == second->bit_field2() &&
8832 first->is_observed() == second->is_observed() &&
8833 first->function_with_prototype() == second->function_with_prototype();
8834}
8835
8836
8837bool Map::EquivalentToForTransition(Map* other) {
8838 return CheckEquivalent(this, other);
8839}
8840
8841
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008842bool Map::EquivalentToForNormalization(Map* other,
8843 PropertyNormalizationMode mode) {
danno@chromium.orgf005df62013-04-30 16:36:45 +00008844 int properties = mode == CLEAR_INOBJECT_PROPERTIES
8845 ? 0 : other->inobject_properties();
8846 return CheckEquivalent(this, other) && inobject_properties() == properties;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008847}
8848
8849
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00008850void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
8851 // Iterate over all fields in the body but take care in dealing with
8852 // the code entry.
8853 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
8854 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
8855 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
8856}
8857
8858
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008859void JSFunction::MarkForLazyRecompilation() {
8860 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008861 ASSERT(shared()->allows_lazy_compilation() ||
8862 code()->optimizable());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008863 set_code_no_write_barrier(
8864 GetIsolate()->builtins()->builtin(Builtins::kLazyRecompile));
8865 // No write barrier required, since the builtin is part of the root set.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008866}
8867
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008868
yangguo@chromium.org304cc332012-07-24 07:59:48 +00008869void JSFunction::MarkForParallelRecompilation() {
8870 ASSERT(is_compiled() && !IsOptimized());
8871 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008872 ASSERT(FLAG_parallel_recompilation);
8873 if (FLAG_trace_parallel_recompilation) {
8874 PrintF(" ** Marking ");
8875 PrintName();
8876 PrintF(" for parallel recompilation.\n");
8877 }
8878 set_code_no_write_barrier(
8879 GetIsolate()->builtins()->builtin(Builtins::kParallelRecompile));
8880 // No write barrier required, since the builtin is part of the root set.
yangguo@chromium.org304cc332012-07-24 07:59:48 +00008881}
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008882
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00008883
8884void JSFunction::MarkForInstallingRecompiledCode() {
8885 ASSERT(is_compiled() && !IsOptimized());
8886 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
8887 ASSERT(FLAG_parallel_recompilation);
8888 set_code_no_write_barrier(
8889 GetIsolate()->builtins()->builtin(Builtins::kInstallRecompiledCode));
8890 // No write barrier required, since the builtin is part of the root set.
8891}
8892
8893
8894void JSFunction::MarkInRecompileQueue() {
8895 ASSERT(is_compiled() && !IsOptimized());
8896 ASSERT(shared()->allows_lazy_compilation() || code()->optimizable());
8897 ASSERT(FLAG_parallel_recompilation);
8898 if (FLAG_trace_parallel_recompilation) {
8899 PrintF(" ** Queueing ");
8900 PrintName();
8901 PrintF(" for parallel recompilation.\n");
8902 }
8903 set_code_no_write_barrier(
8904 GetIsolate()->builtins()->builtin(Builtins::kInRecompileQueue));
8905 // No write barrier required, since the builtin is part of the root set.
8906}
8907
8908
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008909static bool CompileLazyHelper(CompilationInfo* info,
8910 ClearExceptionFlag flag) {
8911 // Compile the source information to a code object.
8912 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
8913 ASSERT(!info->isolate()->has_pending_exception());
8914 bool result = Compiler::CompileLazy(info);
8915 ASSERT(result != Isolate::Current()->has_pending_exception());
8916 if (!result && flag == CLEAR_EXCEPTION) {
8917 info->isolate()->clear_pending_exception();
8918 }
8919 return result;
8920}
8921
8922
8923bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
8924 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008925 ASSERT(shared->allows_lazy_compilation_without_context());
8926 CompilationInfoWithZone info(shared);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008927 return CompileLazyHelper(&info, flag);
8928}
8929
8930
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008931void SharedFunctionInfo::AddToOptimizedCodeMap(
8932 Handle<SharedFunctionInfo> shared,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008933 Handle<Context> native_context,
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008934 Handle<Code> code,
8935 Handle<FixedArray> literals) {
8936 ASSERT(code->kind() == Code::OPTIMIZED_FUNCTION);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008937 ASSERT(native_context->IsNativeContext());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008938 STATIC_ASSERT(kEntryLength == 3);
8939 Object* value = shared->optimized_code_map();
8940 Handle<FixedArray> new_code_map;
8941 if (value->IsSmi()) {
8942 // No optimized code map.
8943 ASSERT_EQ(0, Smi::cast(value)->value());
8944 // Crate 3 entries per context {context, code, literals}.
8945 new_code_map = FACTORY->NewFixedArray(kEntryLength);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008946 new_code_map->set(0, *native_context);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008947 new_code_map->set(1, *code);
8948 new_code_map->set(2, *literals);
8949 } else {
8950 // Copy old map and append one new entry.
8951 Handle<FixedArray> old_code_map(FixedArray::cast(value));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008952 ASSERT_EQ(-1, shared->SearchOptimizedCodeMap(*native_context));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008953 int old_length = old_code_map->length();
8954 int new_length = old_length + kEntryLength;
8955 new_code_map = FACTORY->NewFixedArray(new_length);
8956 old_code_map->CopyTo(0, *new_code_map, 0, old_length);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008957 new_code_map->set(old_length, *native_context);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008958 new_code_map->set(old_length + 1, *code);
8959 new_code_map->set(old_length + 2, *literals);
8960 }
8961#ifdef DEBUG
8962 for (int i = 0; i < new_code_map->length(); i += kEntryLength) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008963 ASSERT(new_code_map->get(i)->IsNativeContext());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008964 ASSERT(new_code_map->get(i + 1)->IsCode());
8965 ASSERT(Code::cast(new_code_map->get(i + 1))->kind() ==
8966 Code::OPTIMIZED_FUNCTION);
8967 ASSERT(new_code_map->get(i + 2)->IsFixedArray());
8968 }
8969#endif
8970 shared->set_optimized_code_map(*new_code_map);
8971}
8972
8973
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00008974void SharedFunctionInfo::InstallFromOptimizedCodeMap(JSFunction* function,
8975 int index) {
8976 ASSERT(index > 0);
8977 ASSERT(optimized_code_map()->IsFixedArray());
8978 FixedArray* code_map = FixedArray::cast(optimized_code_map());
8979 if (!bound()) {
8980 FixedArray* cached_literals = FixedArray::cast(code_map->get(index + 1));
8981 ASSERT(cached_literals != NULL);
8982 function->set_literals(cached_literals);
8983 }
8984 Code* code = Code::cast(code_map->get(index));
8985 ASSERT(code != NULL);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00008986 ASSERT(function->context()->native_context() == code_map->get(index - 1));
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00008987 function->ReplaceCode(code);
8988}
8989
8990
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008991bool JSFunction::CompileLazy(Handle<JSFunction> function,
8992 ClearExceptionFlag flag) {
8993 bool result = true;
8994 if (function->shared()->is_compiled()) {
8995 function->ReplaceCode(function->shared()->code());
8996 function->shared()->set_code_age(0);
8997 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00008998 ASSERT(function->shared()->allows_lazy_compilation());
8999 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009000 result = CompileLazyHelper(&info, flag);
9001 ASSERT(!result || function->is_compiled());
9002 }
9003 return result;
9004}
9005
9006
9007bool JSFunction::CompileOptimized(Handle<JSFunction> function,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00009008 BailoutId osr_ast_id,
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009009 ClearExceptionFlag flag) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009010 CompilationInfoWithZone info(function);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009011 info.SetOptimizing(osr_ast_id);
9012 return CompileLazyHelper(&info, flag);
9013}
9014
9015
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009016bool JSFunction::EnsureCompiled(Handle<JSFunction> function,
9017 ClearExceptionFlag flag) {
9018 return function->is_compiled() || CompileLazy(function, flag);
9019}
9020
9021
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009022bool JSFunction::IsInlineable() {
9023 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009024 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009025 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009026 if (!shared_info->script()->IsScript()) return false;
9027 if (shared_info->optimization_disabled()) return false;
9028 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009029 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
9030 // If we never ran this (unlikely) then lets try to optimize it.
9031 if (code->kind() != Code::FUNCTION) return true;
9032 return code->optimizable();
9033}
9034
9035
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009036MaybeObject* JSObject::OptimizeAsPrototype() {
9037 if (IsGlobalObject()) return this;
9038
9039 // Make sure prototypes are fast objects and their maps have the bit set
9040 // so they remain fast.
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00009041 if (!HasFastProperties()) {
9042 MaybeObject* new_proto = TransformToFastProperties(0);
9043 if (new_proto->IsFailure()) return new_proto;
9044 ASSERT(new_proto == this);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009045 }
9046 return this;
9047}
9048
9049
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009050static MUST_USE_RESULT MaybeObject* CacheInitialJSArrayMaps(
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009051 Context* native_context, Map* initial_map) {
9052 // Replace all of the cached initial array maps in the native context with
9053 // the appropriate transitioned elements kind maps.
9054 Heap* heap = native_context->GetHeap();
9055 MaybeObject* maybe_maps =
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009056 heap->AllocateFixedArrayWithHoles(kElementsKindCount, TENURED);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009057 FixedArray* maps;
9058 if (!maybe_maps->To(&maps)) return maybe_maps;
9059
9060 Map* current_map = initial_map;
9061 ElementsKind kind = current_map->elements_kind();
9062 ASSERT(kind == GetInitialFastElementsKind());
9063 maps->set(kind, current_map);
9064 for (int i = GetSequenceIndexFromFastElementsKind(kind) + 1;
9065 i < kFastElementsKindCount; ++i) {
9066 Map* new_map;
9067 ElementsKind next_kind = GetFastElementsKindFromSequenceIndex(i);
danno@chromium.orgf005df62013-04-30 16:36:45 +00009068 if (current_map->HasElementsTransition()) {
9069 new_map = current_map->elements_transition_map();
9070 ASSERT(new_map->elements_kind() == next_kind);
9071 } else {
9072 MaybeObject* maybe_new_map =
9073 current_map->CopyAsElementsKind(next_kind, INSERT_TRANSITION);
9074 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9075 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009076 maps->set(next_kind, new_map);
9077 current_map = new_map;
9078 }
9079 native_context->set_js_array_maps(maps);
9080 return initial_map;
9081}
9082
9083
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009084Handle<Object> CacheInitialJSArrayMaps(Handle<Context> native_context,
9085 Handle<Map> initial_map) {
9086 CALL_HEAP_FUNCTION(native_context->GetIsolate(),
9087 CacheInitialJSArrayMaps(*native_context, *initial_map),
9088 Object);
9089}
9090
9091
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009092MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00009093 ASSERT(value->IsJSReceiver());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009094 Heap* heap = GetHeap();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009095
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00009096 // First some logic for the map of the prototype to make sure it is in fast
9097 // mode.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009098 if (value->IsJSObject()) {
9099 MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
9100 if (ok->IsFailure()) return ok;
9101 }
9102
9103 // Now some logic for the maps of the objects that are created by using this
9104 // function as a constructor.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009105 if (has_initial_map()) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009106 // If the function has allocated the initial map replace it with a
9107 // copy containing the new prototype. Also complete any in-object
9108 // slack tracking that is in progress at this point because it is
9109 // still tracking the old copy.
9110 if (shared()->IsInobjectSlackTrackingInProgress()) {
9111 shared()->CompleteInobjectSlackTracking();
9112 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009113 Map* new_map;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009114 MaybeObject* maybe_object = initial_map()->Copy();
9115 if (!maybe_object->To(&new_map)) return maybe_object;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009116 new_map->set_prototype(value);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009117
9118 // If the function is used as the global Array function, cache the
9119 // initial map (and transitioned versions) in the native context.
9120 Context* native_context = context()->native_context();
9121 Object* array_function = native_context->get(Context::ARRAY_FUNCTION_INDEX);
9122 if (array_function->IsJSFunction() &&
9123 this == JSFunction::cast(array_function)) {
9124 MaybeObject* ok = CacheInitialJSArrayMaps(native_context, new_map);
9125 if (ok->IsFailure()) return ok;
9126 }
9127
9128 set_initial_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009129 } else {
9130 // Put the value in the initial map field until an initial map is
9131 // needed. At that point, a new initial map is created and the
9132 // prototype is put into the initial map where it belongs.
9133 set_prototype_or_initial_map(value);
9134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009135 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 return value;
9137}
9138
9139
lrn@chromium.org303ada72010-10-27 09:33:13 +00009140MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009141 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142 Object* construct_prototype = value;
9143
danno@chromium.org88aa0582012-03-23 15:11:57 +00009144 // If the value is not a JSReceiver, store the value in the map's
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 // constructor field so it can be accessed. Also, set the prototype
9146 // used for constructing objects to the original object prototype.
9147 // See ECMA-262 13.2.2.
danno@chromium.org88aa0582012-03-23 15:11:57 +00009148 if (!value->IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009150 // Remove map transitions because they point to maps with a
9151 // different prototype.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00009152 Map* new_map;
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00009153 MaybeObject* maybe_new_map = map()->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +00009154 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9155
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009156 Heap* heap = new_map->GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009157 set_map(new_map);
9158 new_map->set_constructor(value);
9159 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009160 construct_prototype =
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009161 heap->isolate()->context()->native_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009162 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009163 } else {
9164 map()->set_non_instance_prototype(false);
9165 }
9166
9167 return SetInstancePrototype(construct_prototype);
9168}
9169
9170
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009171void JSFunction::RemovePrototype() {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009172 Context* native_context = context()->native_context();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009173 Map* no_prototype_map = shared()->is_classic_mode()
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009174 ? native_context->function_without_prototype_map()
9175 : native_context->strict_mode_function_without_prototype_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009176
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009177 if (map() == no_prototype_map) return;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009179 ASSERT(map() == (shared()->is_classic_mode()
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009180 ? native_context->function_map()
9181 : native_context->strict_mode_function_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009182
9183 set_map(no_prototype_map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009184 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009185}
9186
9187
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00009188void JSFunction::SetInstanceClassName(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 shared()->set_instance_class_name(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190}
9191
9192
whesse@chromium.org023421e2010-12-21 12:19:12 +00009193void JSFunction::PrintName(FILE* out) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009194 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00009195 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009196}
9197
9198
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009199Context* JSFunction::NativeContextFromLiterals(FixedArray* literals) {
9200 return Context::cast(literals->get(JSFunction::kLiteralNativeContextIndex));
ager@chromium.org236ad962008-09-25 09:45:57 +00009201}
9202
9203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009204MaybeObject* Oddball::Initialize(const char* to_string,
9205 Object* to_number,
9206 byte kind) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009207 String* internalized_to_string;
9208 { MaybeObject* maybe_string =
9209 Isolate::Current()->heap()->InternalizeUtf8String(
9210 CStrVector(to_string));
9211 if (!maybe_string->To(&internalized_to_string)) return maybe_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009212 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009213 set_to_string(internalized_to_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216 return this;
9217}
9218
9219
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00009220String* SharedFunctionInfo::DebugName() {
9221 Object* n = name();
9222 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
9223 return String::cast(n);
9224}
9225
9226
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227bool SharedFunctionInfo::HasSourceCode() {
9228 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009229 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009230}
9231
9232
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00009233Handle<Object> SharedFunctionInfo::GetSourceCode() {
9234 if (!HasSourceCode()) return GetIsolate()->factory()->undefined_value();
9235 Handle<String> source(String::cast(Script::cast(script())->source()));
9236 return SubString(source, start_position(), end_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009237}
9238
9239
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009240int SharedFunctionInfo::SourceSize() {
9241 return end_position() - start_position();
9242}
9243
9244
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009245int SharedFunctionInfo::CalculateInstanceSize() {
9246 int instance_size =
9247 JSObject::kHeaderSize +
9248 expected_nof_properties() * kPointerSize;
9249 if (instance_size > JSObject::kMaxInstanceSize) {
9250 instance_size = JSObject::kMaxInstanceSize;
9251 }
9252 return instance_size;
9253}
9254
9255
9256int SharedFunctionInfo::CalculateInObjectProperties() {
9257 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
9258}
9259
9260
ager@chromium.org5c838252010-02-19 08:53:10 +00009261bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
9262 // Check the basic conditions for generating inline constructor code.
9263 if (!FLAG_inline_new
9264 || !has_only_simple_this_property_assignments()
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00009265 || is_generator()
ager@chromium.org5c838252010-02-19 08:53:10 +00009266 || this_property_assignments_count() == 0) {
9267 return false;
9268 }
9269
hpayer@chromium.org8432c912013-02-28 15:55:26 +00009270 Isolate* isolate = GetIsolate();
9271 Heap* heap = isolate->heap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009272
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00009273 // Traverse the proposed prototype chain looking for properties of the
9274 // same names as are set by the inline constructor.
ager@chromium.org5c838252010-02-19 08:53:10 +00009275 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009276 obj != heap->null_value();
hpayer@chromium.org8432c912013-02-28 15:55:26 +00009277 obj = obj->GetPrototype(isolate)) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00009278 JSReceiver* receiver = JSReceiver::cast(obj);
ager@chromium.org5c838252010-02-19 08:53:10 +00009279 for (int i = 0; i < this_property_assignments_count(); i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009280 LookupResult result(heap->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00009281 String* name = GetThisPropertyAssignmentName(i);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00009282 receiver->LocalLookup(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00009283 if (result.IsFound()) {
rossberg@chromium.org657d53b2012-07-12 11:06:03 +00009284 switch (result.type()) {
9285 case NORMAL:
9286 case FIELD:
9287 case CONSTANT_FUNCTION:
9288 break;
9289 case INTERCEPTOR:
9290 case CALLBACKS:
9291 case HANDLER:
9292 return false;
9293 case TRANSITION:
9294 case NONEXISTENT:
9295 UNREACHABLE();
9296 break;
9297 }
9298 }
ager@chromium.org5c838252010-02-19 08:53:10 +00009299 }
9300 }
9301
9302 return true;
9303}
9304
9305
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00009306void SharedFunctionInfo::ForbidInlineConstructor() {
9307 set_compiler_hints(BooleanBit::set(compiler_hints(),
9308 kHasOnlySimpleThisPropertyAssignments,
9309 false));
9310}
9311
9312
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009313void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009314 bool only_simple_this_property_assignments,
9315 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009316 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009317 kHasOnlySimpleThisPropertyAssignments,
9318 only_simple_this_property_assignments));
9319 set_this_property_assignments(assignments);
9320 set_this_property_assignments_count(assignments->length() / 3);
9321}
9322
9323
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009324void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009326 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009327 kHasOnlySimpleThisPropertyAssignments,
9328 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009330 set_this_property_assignments_count(0);
9331}
9332
9333
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00009334String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
9335 Object* obj = this_property_assignments();
9336 ASSERT(obj->IsFixedArray());
9337 ASSERT(index < this_property_assignments_count());
9338 obj = FixedArray::cast(obj)->get(index * 3);
9339 ASSERT(obj->IsString());
9340 return String::cast(obj);
9341}
9342
9343
ager@chromium.org18ad94b2009-09-02 08:22:29 +00009344bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
9345 Object* obj = this_property_assignments();
9346 ASSERT(obj->IsFixedArray());
9347 ASSERT(index < this_property_assignments_count());
9348 obj = FixedArray::cast(obj)->get(index * 3 + 1);
9349 return Smi::cast(obj)->value() != -1;
9350}
9351
9352
9353int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
9354 ASSERT(IsThisPropertyAssignmentArgument(index));
9355 Object* obj =
9356 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
9357 return Smi::cast(obj)->value();
9358}
9359
9360
9361Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
9362 ASSERT(!IsThisPropertyAssignmentArgument(index));
9363 Object* obj =
9364 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
9365 return obj;
9366}
9367
9368
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009369// Support function for printing the source code to a StringStream
9370// without any allocation in the heap.
9371void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
9372 int max_length) {
9373 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009374 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 accumulator->Add("<No Source>");
9376 return;
9377 }
9378
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009379 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009380 // Don't use String::cast because we don't want more assertion errors while
9381 // we are already creating a stack dump.
9382 String* script_source =
9383 reinterpret_cast<String*>(Script::cast(script())->source());
9384
9385 if (!script_source->LooksValid()) {
9386 accumulator->Add("<Invalid Source>");
9387 return;
9388 }
9389
9390 if (!is_toplevel()) {
9391 accumulator->Add("function ");
9392 Object* name = this->name();
9393 if (name->IsString() && String::cast(name)->length() > 0) {
9394 accumulator->PrintName(name);
9395 }
9396 }
9397
9398 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009399 if (len <= max_length || max_length < 0) {
9400 accumulator->Put(script_source, start_position(), end_position());
9401 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009402 accumulator->Put(script_source,
9403 start_position(),
9404 start_position() + max_length);
9405 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 }
9407}
9408
9409
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009410static bool IsCodeEquivalent(Code* code, Code* recompiled) {
9411 if (code->instruction_size() != recompiled->instruction_size()) return false;
9412 ByteArray* code_relocation = code->relocation_info();
9413 ByteArray* recompiled_relocation = recompiled->relocation_info();
9414 int length = code_relocation->length();
9415 if (length != recompiled_relocation->length()) return false;
9416 int compare = memcmp(code_relocation->GetDataStartAddress(),
9417 recompiled_relocation->GetDataStartAddress(),
9418 length);
9419 return compare == 0;
9420}
9421
9422
9423void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
9424 ASSERT(!has_deoptimization_support());
9425 AssertNoAllocation no_allocation;
9426 Code* code = this->code();
9427 if (IsCodeEquivalent(code, recompiled)) {
9428 // Copy the deoptimization data from the recompiled code.
9429 code->set_deoptimization_data(recompiled->deoptimization_data());
9430 code->set_has_deoptimization_support(true);
9431 } else {
9432 // TODO(3025757): In case the recompiled isn't equivalent to the
9433 // old code, we have to replace it. We should try to avoid this
9434 // altogether because it flushes valuable type feedback by
9435 // effectively resetting all IC state.
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00009436 ReplaceCode(recompiled);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009437 }
9438 ASSERT(has_deoptimization_support());
9439}
9440
9441
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009442void SharedFunctionInfo::DisableOptimization(const char* reason) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009443 // Disable optimization for the shared function info and mark the
9444 // code as non-optimizable. The marker on the shared function info
9445 // is there because we flush non-optimized code thereby loosing the
9446 // non-optimizable information for the code. When the code is
9447 // regenerated and set on the shared function info it is marked as
9448 // non-optimizable if optimization is disabled for the shared
9449 // function info.
9450 set_optimization_disabled(true);
9451 // Code should be the lazy compilation stub or else unoptimized. If the
9452 // latter, disable optimization for the code too.
9453 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
9454 if (code()->kind() == Code::FUNCTION) {
9455 code()->set_optimizable(false);
9456 }
9457 if (FLAG_trace_opt) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009458 PrintF("[disabled optimization for %s, reason: %s]\n",
9459 *DebugName()->ToCString(), reason);
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009460 }
9461}
9462
9463
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00009464bool SharedFunctionInfo::VerifyBailoutId(BailoutId id) {
9465 ASSERT(!id.IsNone());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009466 Code* unoptimized = code();
9467 DeoptimizationOutputData* data =
9468 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
9469 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
9470 USE(ignore);
9471 return true; // Return true if there was no ASSERT.
9472}
9473
9474
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009475void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
9476 ASSERT(!IsInobjectSlackTrackingInProgress());
9477
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00009478 if (!FLAG_clever_optimizations) return;
9479
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009480 // Only initiate the tracking the first time.
9481 if (live_objects_may_exist()) return;
9482 set_live_objects_may_exist(true);
9483
9484 // No tracking during the snapshot construction phase.
9485 if (Serializer::enabled()) return;
9486
9487 if (map->unused_property_fields() == 0) return;
9488
9489 // Nonzero counter is a leftover from the previous attempt interrupted
9490 // by GC, keep it.
9491 if (construction_count() == 0) {
9492 set_construction_count(kGenerousAllocationCount);
9493 }
9494 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009495 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009496 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009497 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009498 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009499}
9500
9501
9502// Called from GC, hence reinterpret_cast and unchecked accessors.
9503void SharedFunctionInfo::DetachInitialMap() {
9504 Map* map = reinterpret_cast<Map*>(initial_map());
9505
9506 // Make the map remember to restore the link if it survives the GC.
9507 map->set_bit_field2(
9508 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
9509
9510 // Undo state changes made by StartInobjectTracking (except the
9511 // construction_count). This way if the initial map does not survive the GC
9512 // then StartInobjectTracking will be called again the next time the
9513 // constructor is called. The countdown will continue and (possibly after
9514 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009515 Heap* heap = map->GetHeap();
danno@chromium.org72204d52012-10-31 10:02:10 +00009516 set_initial_map(heap->undefined_value());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009517 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009518 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009519 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009520 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009521 // It is safe to clear the flag: it will be set again if the map is live.
9522 set_live_objects_may_exist(false);
9523}
9524
9525
9526// Called from GC, hence reinterpret_cast and unchecked accessors.
9527void SharedFunctionInfo::AttachInitialMap(Map* map) {
9528 map->set_bit_field2(
9529 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
9530
9531 // Resume inobject slack tracking.
9532 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009533 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009534 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009535 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009536 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009537 // The map survived the gc, so there may be objects referencing it.
9538 set_live_objects_may_exist(true);
9539}
9540
9541
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00009542void SharedFunctionInfo::ResetForNewContext(int new_ic_age) {
9543 code()->ClearInlineCaches();
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00009544 set_ic_age(new_ic_age);
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +00009545 if (code()->kind() == Code::FUNCTION) {
9546 code()->set_profiler_ticks(0);
9547 if (optimization_disabled() &&
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00009548 opt_count() >= FLAG_max_opt_count) {
ulan@chromium.org6b9c2a02012-04-02 14:52:24 +00009549 // Re-enable optimizations if they were disabled due to opt_count limit.
9550 set_optimization_disabled(false);
9551 code()->set_optimizable(true);
9552 }
9553 set_opt_count(0);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009554 set_deopt_count(0);
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00009555 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00009556}
9557
9558
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009559static void GetMinInobjectSlack(Map* map, void* data) {
9560 int slack = map->unused_property_fields();
9561 if (*reinterpret_cast<int*>(data) > slack) {
9562 *reinterpret_cast<int*>(data) = slack;
9563 }
9564}
9565
9566
9567static void ShrinkInstanceSize(Map* map, void* data) {
9568 int slack = *reinterpret_cast<int*>(data);
9569 map->set_inobject_properties(map->inobject_properties() - slack);
9570 map->set_unused_property_fields(map->unused_property_fields() - slack);
9571 map->set_instance_size(map->instance_size() - slack * kPointerSize);
9572
9573 // Visitor id might depend on the instance size, recalculate it.
9574 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
9575}
9576
9577
9578void SharedFunctionInfo::CompleteInobjectSlackTracking() {
9579 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
9580 Map* map = Map::cast(initial_map());
9581
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009582 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009583 set_initial_map(heap->undefined_value());
9584 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009585 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009586 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009587 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009588
9589 int slack = map->unused_property_fields();
9590 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
9591 if (slack != 0) {
9592 // Resize the initial map and all maps in its transition tree.
9593 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00009594
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009595 // Give the correct expected_nof_properties to initial maps created later.
9596 ASSERT(expected_nof_properties() >= slack);
9597 set_expected_nof_properties(expected_nof_properties() - slack);
9598 }
9599}
9600
9601
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009602int SharedFunctionInfo::SearchOptimizedCodeMap(Context* native_context) {
9603 ASSERT(native_context->IsNativeContext());
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00009604 if (!FLAG_cache_optimized_code) return -1;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009605 Object* value = optimized_code_map();
9606 if (!value->IsSmi()) {
9607 FixedArray* optimized_code_map = FixedArray::cast(value);
9608 int length = optimized_code_map->length();
9609 for (int i = 0; i < length; i += 3) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00009610 if (optimized_code_map->get(i) == native_context) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00009611 return i + 1;
9612 }
9613 }
9614 }
9615 return -1;
9616}
9617
9618
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009619#define DECLARE_TAG(ignore1, name, ignore2) name,
9620const char* const VisitorSynchronization::kTags[
9621 VisitorSynchronization::kNumberOfSyncTags] = {
9622 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
9623};
9624#undef DECLARE_TAG
9625
9626
9627#define DECLARE_TAG(ignore1, ignore2, name) name,
9628const char* const VisitorSynchronization::kTagNames[
9629 VisitorSynchronization::kNumberOfSyncTags] = {
9630 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
9631};
9632#undef DECLARE_TAG
9633
9634
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009635void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009636 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009637 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
9638 Object* old_target = target;
9639 VisitPointer(&target);
9640 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009641}
9642
9643
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009644void ObjectVisitor::VisitCodeAgeSequence(RelocInfo* rinfo) {
9645 ASSERT(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
9646 Object* stub = rinfo->code_age_stub();
9647 if (stub) {
9648 VisitPointer(&stub);
9649 }
9650}
9651
9652
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00009653void ObjectVisitor::VisitCodeEntry(Address entry_address) {
9654 Object* code = Code::GetObjectFromEntryAddress(entry_address);
9655 Object* old_code = code;
9656 VisitPointer(&code);
9657 if (code != old_code) {
9658 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
9659 }
9660}
9661
9662
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009663void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
9664 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
9665 Object* cell = rinfo->target_cell();
9666 Object* old_cell = cell;
9667 VisitPointer(&cell);
9668 if (cell != old_cell) {
9669 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
9670 }
9671}
9672
9673
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009674void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00009675 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
9676 rinfo->IsPatchedReturnSequence()) ||
9677 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
9678 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009679 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
9680 Object* old_target = target;
9681 VisitPointer(&target);
9682 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009683}
9684
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00009685void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
9686 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
9687 VisitPointer(rinfo->target_object_address());
9688}
9689
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009690void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
9691 Address* p = rinfo->target_reference_address();
9692 VisitExternalReferences(p, p + 1);
9693}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00009694
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009695byte Code::compare_nil_state() {
9696 ASSERT(is_compare_nil_ic_stub());
9697 return CompareNilICStub::TypesFromExtraICState(extended_extra_ic_state());
9698}
9699
9700
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009701void Code::InvalidateRelocation() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009702 set_relocation_info(GetHeap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009703}
9704
9705
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009706void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009707 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
9708 it.rinfo()->apply(delta);
9709 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009710 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009711}
9712
9713
9714void Code::CopyFrom(const CodeDesc& desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009715 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
9716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009717 // copy code
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009718 CopyBytes(instruction_start(), desc.buffer,
9719 static_cast<size_t>(desc.instr_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009721 // copy reloc info
danno@chromium.orgc99cd482013-03-21 15:26:42 +00009722 CopyBytes(relocation_start(),
9723 desc.buffer + desc.buffer_size - desc.reloc_size,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00009724 static_cast<size_t>(desc.reloc_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009725
9726 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00009727 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00009729 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009730 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009731 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009732 RelocInfo::kApplyMask;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009733 // Needed to find target_object and runtime_entry on X64
9734 Assembler* origin = desc.origin;
ulan@chromium.org32d7dba2013-04-24 10:59:06 +00009735 ALLOW_HANDLE_DEREF(GetIsolate(), "embedding raw addresses into code");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009736 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009737 RelocInfo::Mode mode = it.rinfo()->rmode();
9738 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009739 Handle<Object> p = it.rinfo()->target_object_handle(origin);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009740 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009741 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009742 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009743 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
ager@chromium.org236ad962008-09-25 09:45:57 +00009744 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009745 // rewrite code handles in inline cache targets to direct
9746 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009747 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009748 Code* code = Code::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009749 it.rinfo()->set_target_address(code->instruction_start(),
9750 SKIP_WRITE_BARRIER);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +00009751 } else if (RelocInfo::IsRuntimeEntry(mode)) {
9752 Address p = it.rinfo()->target_runtime_entry(origin);
9753 it.rinfo()->set_target_runtime_entry(p, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009754 } else {
9755 it.rinfo()->apply(delta);
9756 }
9757 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009758 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759}
9760
9761
9762// Locate the source position which is closest to the address in the code. This
9763// is using the source position information embedded in the relocation info.
9764// The position returned is relative to the beginning of the script where the
9765// source for this function is found.
9766int Code::SourcePosition(Address pc) {
9767 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00009768 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769 // Run through all the relocation info to find the best matching source
9770 // position. All the code needs to be considered as the sequence of the
9771 // instructions in the code does not necessarily follow the same order as the
9772 // source.
9773 RelocIterator it(this, RelocInfo::kPositionMask);
9774 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009775 // Only look at positions after the current pc.
9776 if (it.rinfo()->pc() < pc) {
9777 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009778
9779 int dist = static_cast<int>(pc - it.rinfo()->pc());
9780 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00009781 // If this position is closer than the current candidate or if it has the
9782 // same distance as the current candidate and the position is higher then
9783 // this position is the new candidate.
9784 if ((dist < distance) ||
9785 (dist == distance && pos > position)) {
9786 position = pos;
9787 distance = dist;
9788 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789 }
9790 it.next();
9791 }
9792 return position;
9793}
9794
9795
9796// Same as Code::SourcePosition above except it only looks for statement
9797// positions.
9798int Code::SourceStatementPosition(Address pc) {
9799 // First find the position as close as possible using all position
9800 // information.
9801 int position = SourcePosition(pc);
9802 // Now find the closest statement position before the position.
9803 int statement_position = 0;
9804 RelocIterator it(this, RelocInfo::kPositionMask);
9805 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009806 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009807 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009808 if (statement_position < p && p <= position) {
9809 statement_position = p;
9810 }
9811 }
9812 it.next();
9813 }
9814 return statement_position;
9815}
9816
9817
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00009818SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009819 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00009820 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009821}
9822
9823
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009824Map* Code::FindFirstMap() {
9825 ASSERT(is_inline_cache_stub());
9826 AssertNoAllocation no_allocation;
9827 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
9828 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9829 RelocInfo* info = it.rinfo();
9830 Object* object = info->target_object();
9831 if (object->IsMap()) return Map::cast(object);
9832 }
9833 return NULL;
9834}
9835
9836
danno@chromium.orgca29dd82013-04-26 11:59:48 +00009837void Code::ReplaceFirstMap(Map* replace_with) {
9838 ASSERT(is_inline_cache_stub());
9839 AssertNoAllocation no_allocation;
9840 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
9841 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9842 RelocInfo* info = it.rinfo();
9843 Object* object = info->target_object();
9844 if (object->IsMap()) {
9845 info->set_target_object(replace_with);
9846 return;
9847 }
9848 }
9849 UNREACHABLE();
9850}
9851
9852
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009853void Code::FindAllMaps(MapHandleList* maps) {
9854 ASSERT(is_inline_cache_stub());
9855 AssertNoAllocation no_allocation;
9856 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
9857 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9858 RelocInfo* info = it.rinfo();
9859 Object* object = info->target_object();
9860 if (object->IsMap()) maps->Add(Handle<Map>(Map::cast(object)));
9861 }
9862}
9863
9864
9865Code* Code::FindFirstCode() {
9866 ASSERT(is_inline_cache_stub());
9867 AssertNoAllocation no_allocation;
9868 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
9869 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9870 RelocInfo* info = it.rinfo();
9871 return Code::GetCodeFromTargetAddress(info->target_address());
9872 }
9873 return NULL;
9874}
9875
9876
9877void Code::FindAllCode(CodeHandleList* code_list, int length) {
9878 ASSERT(is_inline_cache_stub());
9879 AssertNoAllocation no_allocation;
9880 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET);
9881 int i = 0;
9882 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9883 if (i++ == length) return;
9884 RelocInfo* info = it.rinfo();
9885 Code* code = Code::GetCodeFromTargetAddress(info->target_address());
ulan@chromium.org750145a2013-03-07 15:14:13 +00009886 ASSERT(code->kind() == Code::STUB);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00009887 code_list->Add(Handle<Code>(code));
9888 }
9889 UNREACHABLE();
9890}
9891
9892
ulan@chromium.org57ff8812013-05-10 08:16:55 +00009893Name* Code::FindFirstName() {
9894 ASSERT(is_inline_cache_stub());
9895 AssertNoAllocation no_allocation;
9896 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
9897 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9898 RelocInfo* info = it.rinfo();
9899 Object* object = info->target_object();
9900 if (object->IsName()) return Name::cast(object);
9901 }
9902 return NULL;
9903}
9904
9905
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00009906void Code::ClearInlineCaches() {
9907 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
9908 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
9909 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
9910 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
9911 for (RelocIterator it(this, mask); !it.done(); it.next()) {
9912 RelocInfo* info = it.rinfo();
9913 Code* target(Code::GetCodeFromTargetAddress(info->target_address()));
9914 if (target->is_inline_cache_stub()) {
9915 IC::Clear(info->pc());
9916 }
9917 }
9918}
9919
9920
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00009921void Code::ClearTypeFeedbackCells(Heap* heap) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009922 if (kind() != FUNCTION) return;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00009923 Object* raw_info = type_feedback_info();
9924 if (raw_info->IsTypeFeedbackInfo()) {
9925 TypeFeedbackCells* type_feedback_cells =
9926 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells();
9927 for (int i = 0; i < type_feedback_cells->CellCount(); i++) {
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00009928 JSGlobalPropertyCell* cell = type_feedback_cells->Cell(i);
9929 cell->set_value(TypeFeedbackCells::RawUninitializedSentinel(heap));
9930 }
9931 }
9932}
9933
9934
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009935bool Code::allowed_in_shared_map_code_cache() {
mstarzinger@chromium.org06e015b2012-06-14 15:34:20 +00009936 return is_keyed_load_stub() || is_keyed_store_stub() ||
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00009937 (is_compare_ic_stub() &&
hpayer@chromium.org8432c912013-02-28 15:55:26 +00009938 ICCompareStub::CompareState(stub_info()) == CompareIC::KNOWN_OBJECT);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00009939}
9940
9941
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009942void Code::MakeCodeAgeSequenceYoung(byte* sequence) {
9943 PatchPlatformCodeAge(sequence, kNoAge, NO_MARKING_PARITY);
9944}
9945
9946
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009947void Code::MakeOlder(MarkingParity current_parity) {
9948 byte* sequence = FindCodeAgeSequence();
9949 if (sequence != NULL) {
9950 Age age;
9951 MarkingParity code_parity;
9952 GetCodeAgeAndParity(sequence, &age, &code_parity);
9953 if (age != kLastCodeAge && code_parity != current_parity) {
9954 PatchPlatformCodeAge(sequence, static_cast<Age>(age + 1),
9955 current_parity);
9956 }
9957 }
9958}
9959
9960
9961bool Code::IsOld() {
9962 byte* sequence = FindCodeAgeSequence();
9963 if (sequence == NULL) return false;
9964 Age age;
9965 MarkingParity parity;
9966 GetCodeAgeAndParity(sequence, &age, &parity);
9967 return age >= kSexagenarianCodeAge;
9968}
9969
9970
9971byte* Code::FindCodeAgeSequence() {
9972 return FLAG_age_code &&
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00009973 prologue_offset() != kPrologueOffsetNotSet &&
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009974 (kind() == OPTIMIZED_FUNCTION ||
9975 (kind() == FUNCTION && !has_debug_break_slots()))
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00009976 ? instruction_start() + prologue_offset()
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00009977 : NULL;
9978}
9979
9980
9981void Code::GetCodeAgeAndParity(Code* code, Age* age,
9982 MarkingParity* parity) {
9983 Isolate* isolate = Isolate::Current();
9984 Builtins* builtins = isolate->builtins();
9985 Code* stub = NULL;
9986#define HANDLE_CODE_AGE(AGE) \
9987 stub = *builtins->Make##AGE##CodeYoungAgainEvenMarking(); \
9988 if (code == stub) { \
9989 *age = k##AGE##CodeAge; \
9990 *parity = EVEN_MARKING_PARITY; \
9991 return; \
9992 } \
9993 stub = *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
9994 if (code == stub) { \
9995 *age = k##AGE##CodeAge; \
9996 *parity = ODD_MARKING_PARITY; \
9997 return; \
9998 }
9999 CODE_AGE_LIST(HANDLE_CODE_AGE)
10000#undef HANDLE_CODE_AGE
10001 UNREACHABLE();
10002}
10003
10004
10005Code* Code::GetCodeAgeStub(Age age, MarkingParity parity) {
10006 Isolate* isolate = Isolate::Current();
10007 Builtins* builtins = isolate->builtins();
10008 switch (age) {
10009#define HANDLE_CODE_AGE(AGE) \
10010 case k##AGE##CodeAge: { \
10011 Code* stub = parity == EVEN_MARKING_PARITY \
10012 ? *builtins->Make##AGE##CodeYoungAgainEvenMarking() \
10013 : *builtins->Make##AGE##CodeYoungAgainOddMarking(); \
10014 return stub; \
10015 }
10016 CODE_AGE_LIST(HANDLE_CODE_AGE)
10017#undef HANDLE_CODE_AGE
10018 default:
10019 UNREACHABLE();
10020 break;
10021 }
10022 return NULL;
10023}
10024
10025
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010026void Code::PrintDeoptLocation(int bailout_id) {
10027 const char* last_comment = NULL;
10028 int mask = RelocInfo::ModeMask(RelocInfo::COMMENT)
10029 | RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
10030 for (RelocIterator it(this, mask); !it.done(); it.next()) {
10031 RelocInfo* info = it.rinfo();
10032 if (info->rmode() == RelocInfo::COMMENT) {
10033 last_comment = reinterpret_cast<const char*>(info->data());
10034 } else if (last_comment != NULL &&
10035 bailout_id == Deoptimizer::GetDeoptimizationId(
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000010036 GetIsolate(), info->target_address(), Deoptimizer::EAGER)) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +000010037 CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010038 PrintF(" %s\n", last_comment);
10039 return;
10040 }
10041 }
10042}
10043
10044
10045// Identify kind of code.
10046const char* Code::Kind2String(Kind kind) {
10047 switch (kind) {
10048 case FUNCTION: return "FUNCTION";
10049 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010050 case STUB: return "STUB";
10051 case BUILTIN: return "BUILTIN";
10052 case LOAD_IC: return "LOAD_IC";
10053 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
10054 case STORE_IC: return "STORE_IC";
10055 case KEYED_STORE_IC: return "KEYED_STORE_IC";
10056 case CALL_IC: return "CALL_IC";
10057 case KEYED_CALL_IC: return "KEYED_CALL_IC";
10058 case UNARY_OP_IC: return "UNARY_OP_IC";
10059 case BINARY_OP_IC: return "BINARY_OP_IC";
10060 case COMPARE_IC: return "COMPARE_IC";
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010061 case COMPARE_NIL_IC: return "COMPARE_NIL_IC";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010062 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
10063 }
10064 UNREACHABLE();
10065 return NULL;
10066}
10067
10068
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010069#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010070
whesse@chromium.org023421e2010-12-21 12:19:12 +000010071void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010072 disasm::NameConverter converter;
10073 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +000010074 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010075 if (0 == deopt_count) return;
10076
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010077 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010078 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010079 for (int i = 0; i < deopt_count; i++) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010080 PrintF(out, "%6d %6d %6d %6d",
10081 i,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010082 AstId(i).ToInt(),
ricow@chromium.org27bf2882011-11-17 08:34:43 +000010083 ArgumentsStackHeight(i)->value(),
10084 Pc(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010085
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010086 if (!FLAG_print_code_verbose) {
10087 PrintF(out, "\n");
10088 continue;
10089 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010090 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010091 int translation_index = TranslationIndex(i)->value();
10092 TranslationIterator iterator(TranslationByteArray(), translation_index);
10093 Translation::Opcode opcode =
10094 static_cast<Translation::Opcode>(iterator.Next());
10095 ASSERT(Translation::BEGIN == opcode);
10096 int frame_count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010097 int jsframe_count = iterator.Next();
10098 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
10099 Translation::StringFor(opcode),
10100 frame_count,
10101 jsframe_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010102
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010103 while (iterator.HasNext() &&
10104 Translation::BEGIN !=
10105 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
10106 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
10107
10108 switch (opcode) {
10109 case Translation::BEGIN:
10110 UNREACHABLE();
10111 break;
10112
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010113 case Translation::JS_FRAME: {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010114 int ast_id = iterator.Next();
10115 int function_id = iterator.Next();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010116 unsigned height = iterator.Next();
fschneider@chromium.org1805e212011-09-05 10:49:12 +000010117 PrintF(out, "{ast_id=%d, function=", ast_id);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +000010118 if (function_id != Translation::kSelfLiteralId) {
10119 Object* function = LiteralArray()->get(function_id);
10120 JSFunction::cast(function)->PrintName(out);
10121 } else {
10122 PrintF(out, "<self>");
10123 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010124 PrintF(out, ", height=%u}", height);
10125 break;
10126 }
10127
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010128 case Translation::COMPILED_STUB_FRAME: {
10129 Code::Kind stub_kind = static_cast<Code::Kind>(iterator.Next());
10130 PrintF(out, "{kind=%d}", stub_kind);
10131 break;
10132 }
10133
ulan@chromium.org967e2702012-02-28 09:49:15 +000010134 case Translation::ARGUMENTS_ADAPTOR_FRAME:
10135 case Translation::CONSTRUCT_STUB_FRAME: {
10136 int function_id = iterator.Next();
10137 JSFunction* function =
10138 JSFunction::cast(LiteralArray()->get(function_id));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010139 unsigned height = iterator.Next();
ulan@chromium.org967e2702012-02-28 09:49:15 +000010140 PrintF(out, "{function=");
10141 function->PrintName(out);
10142 PrintF(out, ", height=%u}", height);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010143 break;
10144 }
10145
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000010146 case Translation::GETTER_STUB_FRAME:
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010147 case Translation::SETTER_STUB_FRAME: {
10148 int function_id = iterator.Next();
10149 JSFunction* function =
10150 JSFunction::cast(LiteralArray()->get(function_id));
10151 PrintF(out, "{function=");
10152 function->PrintName(out);
10153 PrintF(out, "}");
10154 break;
10155 }
10156
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010157 case Translation::DUPLICATE:
10158 break;
10159
10160 case Translation::REGISTER: {
10161 int reg_code = iterator.Next();
10162 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
10163 break;
10164 }
10165
10166 case Translation::INT32_REGISTER: {
10167 int reg_code = iterator.Next();
10168 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
10169 break;
10170 }
10171
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010172 case Translation::UINT32_REGISTER: {
10173 int reg_code = iterator.Next();
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010174 PrintF(out, "{input=%s (unsigned)}",
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010175 converter.NameOfCPURegister(reg_code));
10176 break;
10177 }
10178
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010179 case Translation::DOUBLE_REGISTER: {
10180 int reg_code = iterator.Next();
10181 PrintF(out, "{input=%s}",
10182 DoubleRegister::AllocationIndexToString(reg_code));
10183 break;
10184 }
10185
10186 case Translation::STACK_SLOT: {
10187 int input_slot_index = iterator.Next();
10188 PrintF(out, "{input=%d}", input_slot_index);
10189 break;
10190 }
10191
10192 case Translation::INT32_STACK_SLOT: {
10193 int input_slot_index = iterator.Next();
10194 PrintF(out, "{input=%d}", input_slot_index);
10195 break;
10196 }
10197
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000010198 case Translation::UINT32_STACK_SLOT: {
10199 int input_slot_index = iterator.Next();
10200 PrintF(out, "{input=%d (unsigned)}", input_slot_index);
10201 break;
10202 }
10203
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010204 case Translation::DOUBLE_STACK_SLOT: {
10205 int input_slot_index = iterator.Next();
10206 PrintF(out, "{input=%d}", input_slot_index);
10207 break;
10208 }
10209
10210 case Translation::LITERAL: {
10211 unsigned literal_index = iterator.Next();
10212 PrintF(out, "{literal_id=%u}", literal_index);
10213 break;
10214 }
10215
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010216 case Translation::ARGUMENTS_OBJECT: {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010217 bool args_known = iterator.Next();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010218 int args_index = iterator.Next();
10219 int args_length = iterator.Next();
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010220 PrintF(out, "{index=%d, length=%d, known=%d}",
10221 args_index, args_length, args_known);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010222 break;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010223 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010224 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010225 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010226 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010227 }
10228}
10229
10230
whesse@chromium.org023421e2010-12-21 12:19:12 +000010231void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
10232 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010233 this->DeoptPoints());
10234 if (this->DeoptPoints() == 0) return;
10235
10236 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
10237 for (int i = 0; i < this->DeoptPoints(); i++) {
10238 int pc_and_state = this->PcAndState(i)->value();
10239 PrintF("%6d %8d %s\n",
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +000010240 this->AstId(i).ToInt(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010241 FullCodeGenerator::PcField::decode(pc_and_state),
10242 FullCodeGenerator::State2String(
10243 FullCodeGenerator::StateField::decode(pc_and_state)));
10244 }
10245}
10246
whesse@chromium.org7b260152011-06-20 15:33:18 +000010247
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010248const char* Code::ICState2String(InlineCacheState state) {
10249 switch (state) {
10250 case UNINITIALIZED: return "UNINITIALIZED";
10251 case PREMONOMORPHIC: return "PREMONOMORPHIC";
10252 case MONOMORPHIC: return "MONOMORPHIC";
10253 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000010254 case POLYMORPHIC: return "POLYMORPHIC";
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010255 case MEGAMORPHIC: return "MEGAMORPHIC";
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000010256 case GENERIC: return "GENERIC";
yangguo@chromium.org9768bf12013-01-11 14:51:07 +000010257 case DEBUG_STUB: return "DEBUG_STUB";
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010258 }
10259 UNREACHABLE();
10260 return NULL;
10261}
10262
10263
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010264const char* Code::StubType2String(StubType type) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010265 switch (type) {
10266 case NORMAL: return "NORMAL";
10267 case FIELD: return "FIELD";
10268 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
10269 case CALLBACKS: return "CALLBACKS";
10270 case INTERCEPTOR: return "INTERCEPTOR";
10271 case MAP_TRANSITION: return "MAP_TRANSITION";
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010272 case NONEXISTENT: return "NONEXISTENT";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010273 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010274 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010275 return NULL;
10276}
10277
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010278
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010279void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
10280 const char* name = NULL;
10281 switch (kind) {
10282 case CALL_IC:
10283 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
10284 name = "STRING_INDEX_OUT_OF_BOUNDS";
10285 }
10286 break;
10287 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010288 case KEYED_STORE_IC:
10289 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010290 name = "STRICT";
10291 }
10292 break;
10293 default:
10294 break;
10295 }
10296 if (name != NULL) {
10297 PrintF(out, "extra_ic_state = %s\n", name);
10298 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +000010299 PrintF(out, "extra_ic_state = %d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010300 }
10301}
10302
10303
whesse@chromium.org023421e2010-12-21 12:19:12 +000010304void Code::Disassemble(const char* name, FILE* out) {
10305 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010306 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010307 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010308 PrintExtraICState(out, kind(), extra_ic_state());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010309 if (ic_state() == MONOMORPHIC) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000010310 PrintF(out, "type = %s\n", StubType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010311 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010312 if (is_call_stub() || is_keyed_call_stub()) {
10313 PrintF(out, "argc = %d\n", arguments_count());
10314 }
danno@chromium.org1044a4d2012-04-30 12:34:39 +000010315 if (is_compare_ic_stub()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010316 ASSERT(major_key() == CodeStub::CompareIC);
10317 CompareIC::State left_state, right_state, handler_state;
10318 Token::Value op;
10319 ICCompareStub::DecodeMinorKey(stub_info(), &left_state, &right_state,
10320 &handler_state, &op);
10321 PrintF(out, "compare_state = %s*%s -> %s\n",
10322 CompareIC::GetStateName(left_state),
10323 CompareIC::GetStateName(right_state),
10324 CompareIC::GetStateName(handler_state));
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010325 PrintF(out, "compare_operation = %s\n", Token::Name(op));
10326 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010327 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010328 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010329 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010330 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010331 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010332 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010333 }
mads.s.ager31e71382008-08-13 09:32:07 +000010334
whesse@chromium.org023421e2010-12-21 12:19:12 +000010335 PrintF(out, "Instructions (size = %d)\n", instruction_size());
10336 Disassembler::Decode(out, this);
10337 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +000010338
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010339 if (kind() == FUNCTION) {
10340 DeoptimizationOutputData* data =
10341 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +000010342 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010343 } else if (kind() == OPTIMIZED_FUNCTION) {
10344 DeoptimizationInputData* data =
10345 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +000010346 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010347 }
10348 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010349
mstarzinger@chromium.orgb228be02013-04-18 14:56:59 +000010350 if (is_crankshafted()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010351 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +000010352 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010353 for (unsigned i = 0; i < table.length(); i++) {
10354 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +000010355 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010356 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +000010357 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010358 SafepointEntry entry = table.GetEntry(i);
10359 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
10360 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010361 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010362 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010363 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000010364 if (entry.argument_count() > 0) {
10365 PrintF(out, " argc: %d", entry.argument_count());
10366 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010367 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010368 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010369 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010370 } else if (kind() == FUNCTION) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000010371 unsigned offset = back_edge_table_offset();
10372 // If there is no back edge table, the "table start" will be at or after
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010373 // (due to alignment) the end of the instruction stream.
10374 if (static_cast<int>(offset) < instruction_size()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000010375 Address back_edge_cursor = instruction_start() + offset;
10376 uint32_t table_length = Memory::uint32_at(back_edge_cursor);
10377 PrintF(out, "Back edges (size = %u)\n", table_length);
10378 PrintF(out, "ast_id pc_offset loop_depth\n");
10379 for (uint32_t i = 0; i < table_length; ++i) {
10380 uint32_t ast_id = Memory::uint32_at(back_edge_cursor);
10381 uint32_t pc_offset = Memory::uint32_at(back_edge_cursor + kIntSize);
10382 uint8_t loop_depth = Memory::uint8_at(back_edge_cursor + 2 * kIntSize);
10383 PrintF(out, "%6u %9u %10u\n", ast_id, pc_offset, loop_depth);
10384 back_edge_cursor += FullCodeGenerator::kBackEdgeEntrySize;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010385 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010386 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010387 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000010388#ifdef OBJECT_PRINT
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +000010389 if (!type_feedback_info()->IsUndefined()) {
10390 TypeFeedbackInfo::cast(type_feedback_info())->TypeFeedbackInfoPrint(out);
10391 PrintF(out, "\n");
10392 }
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000010393#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010394 }
10395
mads.s.ager31e71382008-08-13 09:32:07 +000010396 PrintF("RelocInfo (size = %d)\n", relocation_size());
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000010397 for (RelocIterator it(this); !it.done(); it.next()) {
10398 it.rinfo()->Print(GetIsolate(), out);
10399 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010400 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +000010401}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +000010402#endif // ENABLE_DISASSEMBLER
10403
10404
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010405MaybeObject* JSObject::SetFastElementsCapacityAndLength(
10406 int capacity,
10407 int length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010408 SetFastElementsCapacitySmiMode smi_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010409 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010410 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010411 ASSERT(!HasExternalArrayElements());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010412 ASSERT(!map()->is_observed());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010413
whesse@chromium.org7b260152011-06-20 15:33:18 +000010414 // Allocate a new fast elements backing store.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010415 FixedArray* new_elements;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000010416 MaybeObject* maybe = heap->AllocateUninitializedFixedArray(capacity);
10417 if (!maybe->To(&new_elements)) return maybe;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010418
jkummerow@chromium.orgf3eae902012-05-24 16:42:53 +000010419 ElementsKind elements_kind = GetElementsKind();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010420 ElementsKind new_elements_kind;
10421 // The resized array has FAST_*_SMI_ELEMENTS if the capacity mode forces it,
10422 // or if it's allowed and the old elements array contained only SMIs.
10423 bool has_fast_smi_elements =
10424 (smi_mode == kForceSmiElements) ||
10425 ((smi_mode == kAllowSmiElements) && HasFastSmiElements());
10426 if (has_fast_smi_elements) {
10427 if (IsHoleyElementsKind(elements_kind)) {
10428 new_elements_kind = FAST_HOLEY_SMI_ELEMENTS;
10429 } else {
10430 new_elements_kind = FAST_SMI_ELEMENTS;
10431 }
10432 } else {
10433 if (IsHoleyElementsKind(elements_kind)) {
10434 new_elements_kind = FAST_HOLEY_ELEMENTS;
10435 } else {
10436 new_elements_kind = FAST_ELEMENTS;
10437 }
10438 }
10439 FixedArrayBase* old_elements = elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010440 ElementsAccessor* accessor = ElementsAccessor::ForKind(new_elements_kind);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000010441 MaybeObject* maybe_obj =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010442 accessor->CopyElements(this, new_elements, elements_kind);
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000010443 if (maybe_obj->IsFailure()) return maybe_obj;
10444
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000010445 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010446 Map* new_map = map();
10447 if (new_elements_kind != elements_kind) {
10448 MaybeObject* maybe =
10449 GetElementsTransitionMap(GetIsolate(), new_elements_kind);
10450 if (!maybe->To(&new_map)) return maybe;
10451 }
10452 ValidateElements();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000010453 set_map_and_elements(new_map, new_elements);
10454 } else {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000010455 FixedArray* parameter_map = FixedArray::cast(old_elements);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000010456 parameter_map->set(1, new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010457 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010458
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010459 if (FLAG_trace_elements_transitions) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000010460 PrintElementsTransition(stdout, elements_kind, old_elements,
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010461 GetElementsKind(), new_elements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010462 }
10463
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010464 if (IsJSArray()) {
10465 JSArray::cast(this)->set_length(Smi::FromInt(length));
10466 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010467 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010468}
10469
10470
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010471MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
10472 int capacity,
10473 int length) {
10474 Heap* heap = GetHeap();
10475 // We should never end in here with a pixel or external array.
10476 ASSERT(!HasExternalArrayElements());
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000010477 ASSERT(!map()->is_observed());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010478
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010479 FixedArrayBase* elems;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010480 { MaybeObject* maybe_obj =
10481 heap->AllocateUninitializedFixedDoubleArray(capacity);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010482 if (!maybe_obj->To(&elems)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010483 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010484
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010485 ElementsKind elements_kind = GetElementsKind();
10486 ElementsKind new_elements_kind = elements_kind;
10487 if (IsHoleyElementsKind(elements_kind)) {
10488 new_elements_kind = FAST_HOLEY_DOUBLE_ELEMENTS;
10489 } else {
10490 new_elements_kind = FAST_DOUBLE_ELEMENTS;
10491 }
10492
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010493 Map* new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010494 { MaybeObject* maybe_obj =
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010495 GetElementsTransitionMap(heap->isolate(), new_elements_kind);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010496 if (!maybe_obj->To(&new_map)) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010497 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010498
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010499 FixedArrayBase* old_elements = elements();
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010500 ElementsAccessor* accessor = ElementsAccessor::ForKind(FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010501 { MaybeObject* maybe_obj =
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +000010502 accessor->CopyElements(this, elems, elements_kind);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000010503 if (maybe_obj->IsFailure()) return maybe_obj;
10504 }
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000010505 if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010506 ValidateElements();
rossberg@chromium.org2c067b12012-03-19 11:01:52 +000010507 set_map_and_elements(new_map, elems);
10508 } else {
10509 FixedArray* parameter_map = FixedArray::cast(old_elements);
10510 parameter_map->set(1, elems);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010511 }
10512
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010513 if (FLAG_trace_elements_transitions) {
10514 PrintElementsTransition(stdout, elements_kind, old_elements,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000010515 GetElementsKind(), elems);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010516 }
10517
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010518 if (IsJSArray()) {
10519 JSArray::cast(this)->set_length(Smi::FromInt(length));
10520 }
10521
10522 return this;
10523}
10524
10525
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010526MaybeObject* JSArray::Initialize(int capacity, int length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010527 ASSERT(capacity >= 0);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010528 return GetHeap()->AllocateJSArrayStorage(this, length, capacity,
10529 INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010530}
10531
10532
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010533void JSArray::Expand(int required_size) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010534 GetIsolate()->factory()->SetElementsCapacityAndLength(
10535 Handle<JSArray>(this), required_size, required_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000010536}
10537
10538
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000010539// Returns false if the passed-in index is marked non-configurable,
10540// which will cause the ES5 truncation operation to halt, and thus
10541// no further old values need be collected.
10542static bool GetOldValue(Isolate* isolate,
10543 Handle<JSObject> object,
10544 uint32_t index,
10545 List<Handle<Object> >* old_values,
10546 List<Handle<String> >* indices) {
10547 PropertyAttributes attributes = object->GetLocalElementAttribute(index);
10548 ASSERT(attributes != ABSENT);
10549 if (attributes == DONT_DELETE) return false;
10550 old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
10551 ? Object::GetElement(object, index)
10552 : Handle<Object>::cast(isolate->factory()->the_hole_value()));
10553 indices->Add(isolate->factory()->Uint32ToString(index));
10554 return true;
10555}
10556
10557
ricow@chromium.org7ad65222011-12-19 12:13:11 +000010558MaybeObject* JSArray::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010559 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +000010560 ASSERT(AllowsSetElementsLength());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010561 if (!(FLAG_harmony_observation && map()->is_observed()))
10562 return GetElementsAccessor()->SetLength(this, len);
10563
10564 Isolate* isolate = GetIsolate();
10565 HandleScope scope(isolate);
10566 Handle<JSArray> self(this);
10567 List<Handle<String> > indices;
10568 List<Handle<Object> > old_values;
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010569 Handle<Object> old_length_handle(self->length(), isolate);
10570 Handle<Object> new_length_handle(len, isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010571 uint32_t old_length = 0;
10572 CHECK(old_length_handle->ToArrayIndex(&old_length));
10573 uint32_t new_length = 0;
10574 if (!new_length_handle->ToArrayIndex(&new_length))
10575 return Failure::InternalError();
10576
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +000010577 // Observed arrays should always be in dictionary mode;
10578 // if they were in fast mode, the below is slower than necessary
10579 // as it iterates over the array backing store multiple times.
10580 ASSERT(self->HasDictionaryElements());
10581 static const PropertyAttributes kNoAttrFilter = NONE;
10582 int num_elements = self->NumberOfLocalElements(kNoAttrFilter);
10583 if (num_elements > 0) {
10584 if (old_length == static_cast<uint32_t>(num_elements)) {
10585 // Simple case for arrays without holes.
10586 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
10587 if (!GetOldValue(isolate, self, i, &old_values, &indices)) break;
10588 }
10589 } else {
10590 // For sparse arrays, only iterate over existing elements.
10591 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
10592 self->GetLocalElementKeys(*keys, kNoAttrFilter);
10593 while (num_elements-- > 0) {
10594 uint32_t index = NumberToUint32(keys->get(num_elements));
10595 if (index < new_length) break;
10596 if (!GetOldValue(isolate, self, index, &old_values, &indices)) break;
10597 }
10598 }
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010599 }
10600
10601 MaybeObject* result =
10602 self->GetElementsAccessor()->SetLength(*self, *new_length_handle);
10603 Handle<Object> hresult;
10604 if (!result->ToHandle(&hresult, isolate)) return result;
10605
10606 CHECK(self->length()->ToArrayIndex(&new_length));
10607 if (old_length != new_length) {
10608 for (int i = 0; i < indices.length(); ++i) {
10609 JSObject::EnqueueChangeRecord(
10610 self, "deleted", indices[i], old_values[i]);
10611 }
10612 JSObject::EnqueueChangeRecord(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000010613 self, "updated", isolate->factory()->length_string(),
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010614 old_length_handle);
10615 }
10616 return *hresult;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010617}
10618
10619
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010620Map* Map::GetPrototypeTransition(Object* prototype) {
danno@chromium.org81cac2b2012-07-10 11:28:27 +000010621 FixedArray* cache = GetPrototypeTransitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010622 int number_of_transitions = NumberOfProtoTransitions();
10623 const int proto_offset =
10624 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
10625 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
10626 const int step = kProtoTransitionElementsPerEntry;
10627 for (int i = 0; i < number_of_transitions; i++) {
10628 if (cache->get(proto_offset + i * step) == prototype) {
10629 Object* map = cache->get(map_offset + i * step);
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010630 return Map::cast(map);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010631 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010632 }
10633 return NULL;
10634}
10635
10636
10637MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010638 ASSERT(map->IsMap());
10639 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010640 // Don't cache prototype transition if this map is shared.
10641 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
10642
danno@chromium.org81cac2b2012-07-10 11:28:27 +000010643 FixedArray* cache = GetPrototypeTransitions();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010644
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010645 const int step = kProtoTransitionElementsPerEntry;
10646 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010647
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010648 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010649
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010650 int transitions = NumberOfProtoTransitions() + 1;
10651
10652 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010653 if (capacity > kMaxCachedPrototypeTransitions) return this;
10654
10655 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010656 // Grow array by factor 2 over and above what we need.
10657 { MaybeObject* maybe_cache =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010658 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000010659 if (!maybe_cache->To(&new_cache)) return maybe_cache;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010660 }
10661
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010662 for (int i = 0; i < capacity * step; i++) {
10663 new_cache->set(i + header, cache->get(i + header));
10664 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010665 cache = new_cache;
danno@chromium.org81cac2b2012-07-10 11:28:27 +000010666 MaybeObject* set_result = SetPrototypeTransitions(cache);
10667 if (set_result->IsFailure()) return set_result;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010668 }
10669
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010670 int last = transitions - 1;
10671
10672 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
10673 cache->set(header + last * step + kProtoTransitionMapOffset, map);
10674 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010675
10676 return cache;
10677}
10678
10679
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000010680void Map::ZapTransitions() {
10681 TransitionArray* transition_array = transitions();
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000010682 // TODO(mstarzinger): Temporarily use a slower version instead of the faster
10683 // MemsetPointer to investigate a crasher. Switch back to MemsetPointer.
10684 Object** data = transition_array->data_start();
10685 Object* the_hole = GetHeap()->the_hole_value();
10686 int length = transition_array->length();
10687 for (int i = 0; i < length; i++) {
10688 data[i] = the_hole;
10689 }
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +000010690}
10691
10692
10693void Map::ZapPrototypeTransitions() {
10694 FixedArray* proto_transitions = GetPrototypeTransitions();
10695 MemsetPointer(proto_transitions->data_start(),
10696 GetHeap()->the_hole_value(),
10697 proto_transitions->length());
10698}
10699
10700
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010701DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
10702 Recompute(entries);
yangguo@chromium.org003650e2013-01-24 16:31:08 +000010703}
10704
10705
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010706void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
10707 start_indexes_[0] = 0;
10708 for (int g = 1; g <= kGroupCount; g++) {
10709 int count = entries->number_of_entries(static_cast<DependencyGroup>(g - 1));
10710 start_indexes_[g] = start_indexes_[g - 1] + count;
10711 }
10712}
10713
10714
10715Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
10716 DependencyGroup group,
10717 Handle<Code> value) {
10718 GroupStartIndexes starts(*entries);
10719 int start = starts.at(group);
10720 int end = starts.at(group + 1);
10721 int number_of_entries = starts.number_of_entries();
10722 if (start < end && entries->code_at(end - 1) == *value) {
10723 // Do not append the code if it is already in the array.
10724 // It is sufficient to just check only the last element because
10725 // we process embedded maps of an optimized code in one batch.
10726 return entries;
10727 }
10728 if (entries->length() < kCodesStartIndex + number_of_entries + 1) {
10729 Factory* factory = entries->GetIsolate()->factory();
10730 int capacity = kCodesStartIndex + number_of_entries + 1;
10731 if (capacity > 5) capacity = capacity * 5 / 4;
10732 Handle<DependentCode> new_entries = Handle<DependentCode>::cast(
10733 factory->CopySizeFixedArray(entries, capacity));
10734 // The number of codes can change after GC.
10735 starts.Recompute(*entries);
10736 start = starts.at(group);
10737 end = starts.at(group + 1);
10738 number_of_entries = starts.number_of_entries();
10739 for (int i = 0; i < number_of_entries; i++) {
10740 entries->clear_code_at(i);
10741 }
10742 // If the old fixed array was empty, we need to reset counters of the
10743 // new array.
10744 if (number_of_entries == 0) {
10745 for (int g = 0; g < kGroupCount; g++) {
10746 new_entries->set_number_of_entries(static_cast<DependencyGroup>(g), 0);
10747 }
10748 }
10749 entries = new_entries;
10750 }
10751 entries->ExtendGroup(group);
10752 entries->set_code_at(end, *value);
10753 entries->set_number_of_entries(group, end + 1 - start);
10754 return entries;
10755}
10756
10757
10758bool DependentCode::Contains(DependencyGroup group, Code* code) {
10759 GroupStartIndexes starts(this);
10760 int number_of_entries = starts.at(kGroupCount);
10761 for (int i = 0; i < number_of_entries; i++) {
danno@chromium.org94b0d6f2013-02-04 13:33:20 +000010762 if (code_at(i) == code) return true;
10763 }
10764 return false;
10765}
10766
10767
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010768class DeoptimizeDependentCodeFilter : public OptimizedFunctionFilter {
10769 public:
10770 virtual bool TakeFunction(JSFunction* function) {
10771 return function->code()->marked_for_deoptimization();
10772 }
10773};
10774
10775
10776void DependentCode::DeoptimizeDependentCodeGroup(
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000010777 Isolate* isolate,
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010778 DependentCode::DependencyGroup group) {
10779 AssertNoAllocation no_allocation_scope;
10780 DependentCode::GroupStartIndexes starts(this);
10781 int start = starts.at(group);
10782 int end = starts.at(group + 1);
10783 int number_of_entries = starts.at(DependentCode::kGroupCount);
10784 if (start == end) return;
10785 for (int i = start; i < end; i++) {
10786 Code* code = code_at(i);
10787 code->set_marked_for_deoptimization(true);
10788 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010789 // Compact the array by moving all subsequent groups to fill in the new holes.
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010790 for (int src = end, dst = start; src < number_of_entries; src++, dst++) {
10791 set_code_at(dst, code_at(src));
10792 }
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000010793 // Now the holes are at the end of the array, zap them for heap-verifier.
10794 int removed = end - start;
10795 for (int i = number_of_entries - removed; i < number_of_entries; i++) {
10796 clear_code_at(i);
10797 }
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010798 set_number_of_entries(group, 0);
10799 DeoptimizeDependentCodeFilter filter;
svenpanne@chromium.org876cca82013-03-18 14:43:20 +000010800 Deoptimizer::DeoptimizeAllFunctionsWith(isolate, &filter);
ulan@chromium.org2e04b582013-02-21 14:06:02 +000010801}
10802
10803
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010804MaybeObject* JSReceiver::SetPrototype(Object* value,
10805 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010806#ifdef DEBUG
10807 int size = Size();
10808#endif
10809
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010810 Isolate* isolate = GetIsolate();
10811 Heap* heap = isolate->heap();
ager@chromium.org5c838252010-02-19 08:53:10 +000010812 // Silently ignore the change if value is not a JSObject or null.
10813 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010814 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +000010815
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010816 // From 8.6.2 Object Internal Methods
10817 // ...
10818 // In addition, if [[Extensible]] is false the value of the [[Class]] and
10819 // [[Prototype]] internal properties of the object may not be modified.
10820 // ...
10821 // Implementation specific extensions that modify [[Class]], [[Prototype]]
10822 // or [[Extensible]] must not violate the invariants defined in the preceding
10823 // paragraph.
10824 if (!this->map()->is_extensible()) {
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010825 HandleScope scope(isolate);
10826 Handle<Object> handle(this, isolate);
10827 return isolate->Throw(
10828 *isolate->factory()->NewTypeError("non_extensible_proto",
10829 HandleVector<Object>(&handle, 1)));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010830 }
10831
ager@chromium.org5c838252010-02-19 08:53:10 +000010832 // Before we can set the prototype we need to be sure
10833 // prototype cycles are prevented.
10834 // It is sufficient to validate that the receiver is not in the new prototype
10835 // chain.
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010836 for (Object* pt = value;
10837 pt != heap->null_value();
10838 pt = pt->GetPrototype(isolate)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010839 if (JSReceiver::cast(pt) == this) {
ager@chromium.org5c838252010-02-19 08:53:10 +000010840 // Cycle detected.
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010841 HandleScope scope(isolate);
10842 return isolate->Throw(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +000010844 }
10845 }
10846
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010847 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +000010848
10849 if (skip_hidden_prototypes) {
10850 // Find the first object in the chain whose prototype object is not
10851 // hidden and set the new prototype on that object.
10852 Object* current_proto = real_receiver->GetPrototype();
10853 while (current_proto->IsJSObject() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010854 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
10855 real_receiver = JSReceiver::cast(current_proto);
hpayer@chromium.org8432c912013-02-28 15:55:26 +000010856 current_proto = current_proto->GetPrototype(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +000010857 }
10858 }
10859
10860 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010861 Map* map = real_receiver->map();
10862
10863 // Nothing to do if prototype is already set.
10864 if (map->prototype() == value) return value;
10865
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010866 if (value->IsJSObject()) {
10867 MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
10868 if (ok->IsFailure()) return ok;
10869 }
10870
10871 Map* new_map = map->GetPrototypeTransition(value);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010872 if (new_map == NULL) {
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000010873 MaybeObject* maybe_new_map = map->Copy();
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010874 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010875
verwaest@chromium.org753aee42012-07-17 16:15:42 +000010876 MaybeObject* maybe_new_cache =
10877 map->PutPrototypeTransition(value, new_map);
10878 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010879
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010880 new_map->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010881 }
mmassi@chromium.org7028c052012-06-13 11:51:58 +000010882 ASSERT(new_map->prototype() == value);
10883 real_receiver->set_map(new_map);
ager@chromium.org5c838252010-02-19 08:53:10 +000010884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010885 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +000010886 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +000010887 return value;
10888}
10889
10890
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010891MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
10892 uint32_t first_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010893 uint32_t arg_count,
10894 EnsureElementsMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010895 // Elements in |Arguments| are ordered backwards (because they're on the
10896 // stack), but the method that's called here iterates over them in forward
10897 // direction.
10898 return EnsureCanContainElements(
10899 args->arguments() - first_arg - (arg_count - 1),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000010900 arg_count, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010901}
10902
10903
ulan@chromium.org750145a2013-03-07 15:14:13 +000010904PropertyType JSObject::GetLocalPropertyType(Name* name) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010905 uint32_t index = 0;
10906 if (name->AsArrayIndex(&index)) {
10907 return GetLocalElementType(index);
10908 }
10909 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010910 LocalLookup(name, &lookup, true);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010911 return lookup.type();
10912}
10913
10914
10915PropertyType JSObject::GetLocalElementType(uint32_t index) {
10916 return GetElementsAccessor()->GetType(this, this, index);
10917}
10918
10919
ulan@chromium.org750145a2013-03-07 15:14:13 +000010920AccessorPair* JSObject::GetLocalPropertyAccessorPair(Name* name) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010921 uint32_t index = 0;
10922 if (name->AsArrayIndex(&index)) {
10923 return GetLocalElementAccessorPair(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010924 }
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010925
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010926 LookupResult lookup(GetIsolate());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010927 LocalLookupRealNamedProperty(name, &lookup);
10928
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000010929 if (lookup.IsPropertyCallbacks() &&
10930 lookup.GetCallbackObject()->IsAccessorPair()) {
10931 return AccessorPair::cast(lookup.GetCallbackObject());
10932 }
10933 return NULL;
10934}
10935
10936
10937AccessorPair* JSObject::GetLocalElementAccessorPair(uint32_t index) {
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000010938 if (IsJSGlobalProxy()) {
10939 Object* proto = GetPrototype();
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010940 if (proto->IsNull()) return NULL;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000010941 ASSERT(proto->IsJSGlobalObject());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010942 return JSObject::cast(proto)->GetLocalElementAccessorPair(index);
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000010943 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010944
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010945 // Check for lookup interceptor.
10946 if (HasIndexedInterceptor()) return NULL;
mstarzinger@chromium.orgf4f94992012-11-19 15:39:24 +000010947
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000010948 return GetElementsAccessor()->GetAccessorPair(this, this, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949}
10950
10951
lrn@chromium.org303ada72010-10-27 09:33:13 +000010952MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +000010953 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010954 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010955 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010956 bool check_prototype,
10957 SetPropertyMode set_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010958 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010959 // Make sure that the top context does not change when doing
10960 // callbacks or interceptor calls.
10961 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
10964 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010965 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966 if (!interceptor->setter()->IsUndefined()) {
10967 v8::IndexedPropertySetter setter =
10968 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010969 LOG(isolate,
10970 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
10971 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010972 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010973 v8::Handle<v8::Value> result;
10974 {
10975 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +000010976 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977 result = setter(index, v8::Utils::ToLocal(value_handle), info);
10978 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010979 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010980 if (!result.IsEmpty()) return *value_handle;
10981 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010982 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +000010983 this_handle->SetElementWithoutInterceptor(index,
10984 *value_handle,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010985 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010986 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000010987 check_prototype,
10988 set_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010989 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 return raw_result;
10991}
10992
10993
lrn@chromium.org303ada72010-10-27 09:33:13 +000010994MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
10995 Object* structure,
10996 uint32_t index,
10997 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010998 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010999 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011000
11001 // api style callbacks.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011002 if (structure->IsExecutableAccessorInfo()) {
11003 Handle<ExecutableAccessorInfo> data(
11004 ExecutableAccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011005 Object* fun_obj = data->getter();
11006 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000011007 if (call_fun == NULL) return isolate->heap()->undefined_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011008 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011009 Handle<JSObject> self(JSObject::cast(receiver));
11010 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011011 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011012 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
11014 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011015 v8::AccessorInfo info(args.end());
11016 v8::Handle<v8::Value> result;
11017 {
11018 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +000011019 VMState<EXTERNAL> state(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011020 result = call_fun(v8::Utils::ToLocal(key), info);
11021 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011022 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
11023 if (result.IsEmpty()) return isolate->heap()->undefined_value();
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000011024 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
11025 result_internal->VerifyApiCallResultType();
11026 return *result_internal;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011027 }
11028
11029 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011030 if (structure->IsAccessorPair()) {
11031 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011032 if (getter->IsSpecFunction()) {
11033 // TODO(rossberg): nicer would be to cast to some JSCallable here...
11034 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011035 }
11036 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011037 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011038 }
11039
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011040 if (structure->IsDeclaredAccessorInfo()) {
ulan@chromium.org750145a2013-03-07 15:14:13 +000011041 return GetDeclaredAccessorProperty(receiver,
11042 DeclaredAccessorInfo::cast(structure),
11043 isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011044 }
11045
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011046 UNREACHABLE();
11047 return NULL;
11048}
11049
11050
lrn@chromium.org303ada72010-10-27 09:33:13 +000011051MaybeObject* JSObject::SetElementWithCallback(Object* structure,
11052 uint32_t index,
11053 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000011054 JSObject* holder,
11055 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011056 Isolate* isolate = GetIsolate();
11057 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011058
11059 // We should never get here to initialize a const with the hole
11060 // value since a const declaration would conflict with the setter.
11061 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011062 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011063
11064 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +000011065 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011066 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +000011067 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011068
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011069 if (structure->IsExecutableAccessorInfo()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011070 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000011071 Handle<JSObject> self(this);
11072 Handle<JSObject> holder_handle(JSObject::cast(holder));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011073 Handle<ExecutableAccessorInfo> data(
11074 ExecutableAccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011075 Object* call_obj = data->setter();
11076 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
11077 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011078 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11079 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +000011080 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
11081 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011082 v8::AccessorInfo info(args.end());
11083 {
11084 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +000011085 VMState<EXTERNAL> state(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011086 call_fun(v8::Utils::ToLocal(key),
11087 v8::Utils::ToLocal(value_handle),
11088 info);
11089 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011090 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011091 return *value_handle;
11092 }
11093
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011094 if (structure->IsAccessorPair()) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011095 Handle<Object> setter(AccessorPair::cast(structure)->setter(), isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011096 if (setter->IsSpecFunction()) {
11097 // TODO(rossberg): nicer would be to cast to some JSCallable here...
11098 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011099 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000011100 if (strict_mode == kNonStrictMode) {
11101 return value;
11102 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011103 Handle<Object> holder_handle(holder, isolate);
11104 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011105 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011106 return isolate->Throw(
11107 *isolate->factory()->NewTypeError("no_setter_in_callback",
11108 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011109 }
11110 }
11111
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011112 // TODO(dcarney): Handle correctly.
11113 if (structure->IsDeclaredAccessorInfo()) return value;
11114
kmillikin@chromium.org9155e252010-05-26 13:27:57 +000011115 UNREACHABLE();
11116 return NULL;
11117}
11118
11119
whesse@chromium.org7b260152011-06-20 15:33:18 +000011120bool JSObject::HasFastArgumentsElements() {
11121 Heap* heap = GetHeap();
11122 if (!elements()->IsFixedArray()) return false;
11123 FixedArray* elements = FixedArray::cast(this->elements());
11124 if (elements->map() != heap->non_strict_arguments_elements_map()) {
11125 return false;
11126 }
11127 FixedArray* arguments = FixedArray::cast(elements->get(1));
11128 return !arguments->IsDictionary();
11129}
11130
11131
11132bool JSObject::HasDictionaryArgumentsElements() {
11133 Heap* heap = GetHeap();
11134 if (!elements()->IsFixedArray()) return false;
11135 FixedArray* elements = FixedArray::cast(this->elements());
11136 if (elements->map() != heap->non_strict_arguments_elements_map()) {
11137 return false;
11138 }
11139 FixedArray* arguments = FixedArray::cast(elements->get(1));
11140 return arguments->IsDictionary();
11141}
11142
11143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011144// Adding n elements in fast case is O(n*n).
11145// Note: revisit design to have dual undefined values to capture absent
11146// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011147MaybeObject* JSObject::SetFastElement(uint32_t index,
11148 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011149 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011150 bool check_prototype) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011151 ASSERT(HasFastSmiOrObjectElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011152 HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011153
whesse@chromium.org7b260152011-06-20 15:33:18 +000011154 FixedArray* backing_store = FixedArray::cast(elements());
11155 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
11156 backing_store = FixedArray::cast(backing_store->get(1));
11157 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011158 MaybeObject* maybe = EnsureWritableFastElements();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011159 if (!maybe->To(&backing_store)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +000011160 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011161 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011162
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011163 if (check_prototype &&
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011164 (index >= capacity || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000011165 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +000011166 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
11167 value,
11168 &found,
11169 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +000011170 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011171 }
11172
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011173 uint32_t new_capacity = capacity;
11174 // Check if the length property of this object needs to be updated.
11175 uint32_t array_length = 0;
11176 bool must_update_array_length = false;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011177 bool introduces_holes = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011178 if (IsJSArray()) {
11179 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011180 introduces_holes = index > array_length;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011181 if (index >= array_length) {
11182 must_update_array_length = true;
11183 array_length = index + 1;
11184 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011185 } else {
11186 introduces_holes = index >= capacity;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011187 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011188
11189 // If the array is growing, and it's not growth by a single element at the
11190 // end, make sure that the ElementsKind is HOLEY.
11191 ElementsKind elements_kind = GetElementsKind();
11192 if (introduces_holes &&
11193 IsFastElementsKind(elements_kind) &&
11194 !IsFastHoleyElementsKind(elements_kind)) {
11195 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
11196 MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
11197 if (maybe->IsFailure()) return maybe;
11198 }
11199
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011200 // Check if the capacity of the backing store needs to be increased, or if
11201 // a transition to slow elements is necessary.
11202 if (index >= capacity) {
11203 bool convert_to_slow = true;
11204 if ((index - capacity) < kMaxGap) {
11205 new_capacity = NewElementsCapacity(index + 1);
11206 ASSERT(new_capacity > index);
11207 if (!ShouldConvertToSlowElements(new_capacity)) {
11208 convert_to_slow = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011209 }
11210 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011211 if (convert_to_slow) {
11212 MaybeObject* result = NormalizeElements();
11213 if (result->IsFailure()) return result;
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011214 return SetDictionaryElement(index, value, NONE, strict_mode,
11215 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011216 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011217 }
11218 // Convert to fast double elements if appropriate.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011219 if (HasFastSmiElements() && !value->IsSmi() && value->IsNumber()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000011220 // Consider fixing the boilerplate as well if we have one.
11221 ElementsKind to_kind = IsHoleyElementsKind(elements_kind)
11222 ? FAST_HOLEY_DOUBLE_ELEMENTS
11223 : FAST_DOUBLE_ELEMENTS;
11224
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011225 MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
11226 if (maybe_failure->IsFailure()) return maybe_failure;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000011227
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011228 MaybeObject* maybe =
11229 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
11230 if (maybe->IsFailure()) return maybe;
11231 FixedDoubleArray::cast(elements())->set(index, value->Number());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011232 ValidateElements();
ager@chromium.orgbdf2f942008-10-17 07:23:00 +000011233 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011234 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011235 // Change elements kind from Smi-only to generic FAST if necessary.
11236 if (HasFastSmiElements() && !value->IsSmi()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011237 Map* new_map;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011238 ElementsKind kind = HasFastHoleyElements()
11239 ? FAST_HOLEY_ELEMENTS
11240 : FAST_ELEMENTS;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011241
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011242 MaybeObject* maybe_failure = UpdateAllocationSiteInfo(kind);
11243 if (maybe_failure->IsFailure()) return maybe_failure;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011244
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011245 MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
11246 kind);
11247 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
11248
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011249 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011250 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011251 // Increase backing store capacity if that's been decided previously.
11252 if (new_capacity != capacity) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011253 FixedArray* new_elements;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011254 SetFastElementsCapacitySmiMode smi_mode =
11255 value->IsSmi() && HasFastSmiElements()
11256 ? kAllowSmiElements
11257 : kDontAllowSmiElements;
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011258 { MaybeObject* maybe =
11259 SetFastElementsCapacityAndLength(new_capacity,
11260 array_length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011261 smi_mode);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011262 if (!maybe->To(&new_elements)) return maybe;
11263 }
11264 new_elements->set(index, value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011265 ValidateElements();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011266 return value;
11267 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011268
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011269 // Finally, set the new element and length.
11270 ASSERT(elements()->IsFixedArray());
11271 backing_store->set(index, value);
11272 if (must_update_array_length) {
11273 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
11274 }
11275 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +000011276}
11277
11278
11279MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011280 Object* value_raw,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011281 PropertyAttributes attributes,
whesse@chromium.org7b260152011-06-20 15:33:18 +000011282 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011283 bool check_prototype,
11284 SetPropertyMode set_mode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011285 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
11286 Isolate* isolate = GetIsolate();
11287 Heap* heap = isolate->heap();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011288 Handle<JSObject> self(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011289 Handle<Object> value(value_raw, isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011290
11291 // Insert element in the dictionary.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011292 Handle<FixedArray> elements(FixedArray::cast(this->elements()));
whesse@chromium.org7b260152011-06-20 15:33:18 +000011293 bool is_arguments =
11294 (elements->map() == heap->non_strict_arguments_elements_map());
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011295 Handle<SeededNumberDictionary> dictionary(is_arguments
11296 ? SeededNumberDictionary::cast(elements->get(1))
11297 : SeededNumberDictionary::cast(*elements));
whesse@chromium.org7b260152011-06-20 15:33:18 +000011298
11299 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011300 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011301 Object* element = dictionary->ValueAt(entry);
11302 PropertyDetails details = dictionary->DetailsAt(entry);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011303 if (details.type() == CALLBACKS && set_mode == SET_PROPERTY) {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011304 return SetElementWithCallback(element, index, *value, this, strict_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011305 } else {
11306 dictionary->UpdateMaxNumberKey(index);
jkummerow@chromium.orgf7a58842012-02-21 10:08:21 +000011307 // If a value has not been initialized we allow writing to it even if it
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011308 // is read-only (a declared const that has not been initialized). If a
11309 // value is being defined we skip attribute checks completely.
11310 if (set_mode == DEFINE_PROPERTY) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +000011311 details = PropertyDetails(
11312 attributes, NORMAL, details.dictionary_index());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011313 dictionary->DetailsAtPut(entry, details);
11314 } else if (details.IsReadOnly() && !element->IsTheHole()) {
11315 if (strict_mode == kNonStrictMode) {
11316 return isolate->heap()->undefined_value();
11317 } else {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011318 Handle<Object> holder(this, isolate);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011319 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11320 Handle<Object> args[2] = { number, holder };
11321 Handle<Object> error =
11322 isolate->factory()->NewTypeError("strict_read_only_property",
11323 HandleVector(args, 2));
11324 return isolate->Throw(*error);
11325 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000011326 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011327 // Elements of the arguments object in slow mode might be slow aliases.
11328 if (is_arguments && element->IsAliasedArgumentsEntry()) {
11329 AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(element);
11330 Context* context = Context::cast(elements->get(0));
11331 int context_index = entry->aliased_context_slot();
11332 ASSERT(!context->get(context_index)->IsTheHole());
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011333 context->set(context_index, *value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011334 // For elements that are still writable we keep slow aliasing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011335 if (!details.IsReadOnly()) value = handle(element, isolate);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011336 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011337 dictionary->ValueAtPut(entry, *value);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011338 }
11339 } else {
11340 // Index not already used. Look for an accessor in the prototype chain.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011341 // Can cause GC!
whesse@chromium.org7b260152011-06-20 15:33:18 +000011342 if (check_prototype) {
11343 bool found;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011344 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(
11345 index, *value, &found, strict_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011346 if (found) return result;
11347 }
11348 // When we set the is_extensible flag to false we always force the
11349 // element into dictionary mode (and force them to stay there).
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011350 if (!self->map()->is_extensible()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011351 if (strict_mode == kNonStrictMode) {
11352 return isolate->heap()->undefined_value();
11353 } else {
11354 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
11355 Handle<String> name = isolate->factory()->NumberToString(number);
11356 Handle<Object> args[1] = { name };
11357 Handle<Object> error =
11358 isolate->factory()->NewTypeError("object_not_extensible",
11359 HandleVector(args, 1));
11360 return isolate->Throw(*error);
11361 }
11362 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011363 FixedArrayBase* new_dictionary;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000011364 PropertyDetails details = PropertyDetails(attributes, NORMAL, 0);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011365 MaybeObject* maybe = dictionary->AddNumberEntry(index, *value, details);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011366 if (!maybe->To(&new_dictionary)) return maybe;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011367 if (*dictionary != SeededNumberDictionary::cast(new_dictionary)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011368 if (is_arguments) {
11369 elements->set(1, new_dictionary);
11370 } else {
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011371 self->set_elements(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011372 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011373 dictionary =
11374 handle(SeededNumberDictionary::cast(new_dictionary), isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011375 }
11376 }
11377
11378 // Update the array length if this JSObject is an array.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011379 if (self->IsJSArray()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011380 MaybeObject* result =
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011381 JSArray::cast(*self)->JSArrayUpdateLengthFromIndex(index, *value);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011382 if (result->IsFailure()) return result;
11383 }
11384
11385 // Attempt to put this object back in fast case.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011386 if (self->ShouldConvertToFastElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000011387 uint32_t new_length = 0;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011388 if (self->IsJSArray()) {
11389 CHECK(JSArray::cast(*self)->length()->ToArrayIndex(&new_length));
whesse@chromium.org7b260152011-06-20 15:33:18 +000011390 } else {
11391 new_length = dictionary->max_number_key() + 1;
11392 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011393 SetFastElementsCapacitySmiMode smi_mode = FLAG_smi_only_arrays
11394 ? kAllowSmiElements
11395 : kDontAllowSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000011396 bool has_smi_only_elements = false;
11397 bool should_convert_to_fast_double_elements =
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011398 self->ShouldConvertToFastDoubleElements(&has_smi_only_elements);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000011399 if (has_smi_only_elements) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011400 smi_mode = kForceSmiElements;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000011401 }
11402 MaybeObject* result = should_convert_to_fast_double_elements
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011403 ? self->SetFastDoubleElementsCapacityAndLength(new_length, new_length)
11404 : self->SetFastElementsCapacityAndLength(
11405 new_length, new_length, smi_mode);
11406 self->ValidateElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000011407 if (result->IsFailure()) return result;
11408#ifdef DEBUG
11409 if (FLAG_trace_normalization) {
11410 PrintF("Object elements are fast case again:\n");
11411 Print();
11412 }
11413#endif
11414 }
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000011415 return *value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011416}
11417
ricow@chromium.org0b9f8502010-08-18 07:45:01 +000011418
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011419MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
11420 uint32_t index,
11421 Object* value,
11422 StrictModeFlag strict_mode,
11423 bool check_prototype) {
11424 ASSERT(HasFastDoubleElements());
11425
yangguo@chromium.org56454712012-02-16 15:33:53 +000011426 FixedArrayBase* base_elms = FixedArrayBase::cast(elements());
11427 uint32_t elms_length = static_cast<uint32_t>(base_elms->length());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011428
11429 // If storing to an element that isn't in the array, pass the store request
11430 // up the prototype chain before storing in the receiver's elements.
11431 if (check_prototype &&
yangguo@chromium.org56454712012-02-16 15:33:53 +000011432 (index >= elms_length ||
11433 FixedDoubleArray::cast(base_elms)->is_the_hole(index))) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011434 bool found;
11435 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
11436 value,
11437 &found,
11438 strict_mode);
11439 if (found) return result;
11440 }
11441
11442 // If the value object is not a heap number, switch to fast elements and try
11443 // again.
11444 bool value_is_smi = value->IsSmi();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011445 bool introduces_holes = true;
11446 uint32_t length = elms_length;
11447 if (IsJSArray()) {
11448 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
11449 introduces_holes = index > length;
11450 } else {
11451 introduces_holes = index >= elms_length;
11452 }
11453
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011454 if (!value->IsNumber()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011455 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
11456 elms_length,
11457 length,
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011458 kDontAllowSmiElements);
11459 if (maybe_obj->IsFailure()) return maybe_obj;
11460 maybe_obj = SetFastElement(index, value, strict_mode, check_prototype);
11461 if (maybe_obj->IsFailure()) return maybe_obj;
11462 ValidateElements();
11463 return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011464 }
11465
11466 double double_value = value_is_smi
11467 ? static_cast<double>(Smi::cast(value)->value())
11468 : HeapNumber::cast(value)->value();
11469
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011470 // If the array is growing, and it's not growth by a single element at the
11471 // end, make sure that the ElementsKind is HOLEY.
11472 ElementsKind elements_kind = GetElementsKind();
11473 if (introduces_holes && !IsFastHoleyElementsKind(elements_kind)) {
11474 ElementsKind transitioned_kind = GetHoleyElementsKind(elements_kind);
11475 MaybeObject* maybe = TransitionElementsKind(transitioned_kind);
11476 if (maybe->IsFailure()) return maybe;
11477 }
11478
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011479 // Check whether there is extra space in the fixed array.
11480 if (index < elms_length) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000011481 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011482 elms->set(index, double_value);
11483 if (IsJSArray()) {
11484 // Update the length of the array if needed.
11485 uint32_t array_length = 0;
11486 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
11487 if (index >= array_length) {
11488 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
11489 }
11490 }
11491 return value;
11492 }
11493
11494 // Allow gap in fast case.
11495 if ((index - elms_length) < kMaxGap) {
11496 // Try allocating extra space.
11497 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +000011498 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011499 ASSERT(static_cast<uint32_t>(new_capacity) > index);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011500 MaybeObject* maybe_obj =
11501 SetFastDoubleElementsCapacityAndLength(new_capacity, index + 1);
11502 if (maybe_obj->IsFailure()) return maybe_obj;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011503 FixedDoubleArray::cast(elements())->set(index, double_value);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011504 ValidateElements();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011505 return value;
11506 }
11507 }
11508
11509 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011510 ASSERT(HasFastDoubleElements());
11511 ASSERT(map()->has_fast_double_elements());
11512 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011513 Object* obj;
11514 { MaybeObject* maybe_obj = NormalizeElements();
11515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11516 }
11517 ASSERT(HasDictionaryElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011518 return SetElement(index, value, NONE, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011519}
11520
11521
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011522MaybeObject* JSReceiver::SetElement(uint32_t index,
11523 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011524 PropertyAttributes attributes,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011525 StrictModeFlag strict_mode,
11526 bool check_proto) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011527 if (IsJSProxy()) {
11528 return JSProxy::cast(this)->SetElementWithHandler(
verwaest@chromium.org37141392012-05-31 13:27:02 +000011529 this, index, value, strict_mode);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011530 } else {
11531 return JSObject::cast(this)->SetElement(
11532 index, value, attributes, strict_mode, check_proto);
11533 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011534}
11535
11536
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011537Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
11538 uint32_t index,
11539 Handle<Object> value,
11540 StrictModeFlag strict_mode) {
11541 ASSERT(!object->HasExternalArrayElements());
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011542 CALL_HEAP_FUNCTION(
11543 object->GetIsolate(),
11544 object->SetElement(index, *value, NONE, strict_mode, false),
11545 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011546}
11547
11548
11549Handle<Object> JSObject::SetElement(Handle<JSObject> object,
11550 uint32_t index,
11551 Handle<Object> value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011552 PropertyAttributes attr,
11553 StrictModeFlag strict_mode,
11554 SetPropertyMode set_mode) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011555 if (object->HasExternalArrayElements()) {
11556 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
11557 bool has_exception;
11558 Handle<Object> number = Execution::ToNumber(value, &has_exception);
11559 if (has_exception) return Handle<Object>();
11560 value = number;
11561 }
11562 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011563 CALL_HEAP_FUNCTION(
11564 object->GetIsolate(),
11565 object->SetElement(index, *value, attr, strict_mode, true, set_mode),
11566 Object);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011567}
11568
11569
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011570MaybeObject* JSObject::SetElement(uint32_t index,
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011571 Object* value_raw,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011572 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011573 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011574 bool check_prototype,
11575 SetPropertyMode set_mode) {
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011576 Isolate* isolate = GetIsolate();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011577
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011578 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011579 if (IsAccessCheckNeeded()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011580 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
11581 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
11582 return value_raw;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011583 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011584 }
11585
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011586 if (IsJSGlobalProxy()) {
11587 Object* proto = GetPrototype();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011588 if (proto->IsNull()) return value_raw;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011589 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011590 return JSObject::cast(proto)->SetElement(index,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011591 value_raw,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011592 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011593 strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011594 check_prototype,
11595 set_mode);
11596 }
11597
11598 // Don't allow element properties to be redefined for external arrays.
11599 if (HasExternalArrayElements() && set_mode == DEFINE_PROPERTY) {
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011600 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011601 Handle<Object> args[] = { handle(this, isolate), number };
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011602 Handle<Object> error = isolate->factory()->NewTypeError(
11603 "redef_external_array_element", HandleVector(args, ARRAY_SIZE(args)));
11604 return isolate->Throw(*error);
11605 }
11606
11607 // Normalize the elements to enable attributes on the property.
11608 if ((attributes & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) {
11609 SeededNumberDictionary* dictionary;
11610 MaybeObject* maybe_object = NormalizeElements();
11611 if (!maybe_object->To(&dictionary)) return maybe_object;
11612 // Make sure that we never go back to fast case.
11613 dictionary->set_requires_slow_elements();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011614 }
11615
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011616 if (!(FLAG_harmony_observation && map()->is_observed())) {
11617 return HasIndexedInterceptor()
11618 ? SetElementWithInterceptor(
11619 index, value_raw, attributes, strict_mode, check_prototype, set_mode)
11620 : SetElementWithoutInterceptor(
11621 index, value_raw, attributes, strict_mode, check_prototype, set_mode);
11622 }
11623
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011624 // From here on, everything has to be handlified.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011625 Handle<JSObject> self(this);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000011626 Handle<Object> value(value_raw, isolate);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011627 PropertyAttributes old_attributes = self->GetLocalElementAttribute(index);
11628 Handle<Object> old_value = isolate->factory()->the_hole_value();
11629 Handle<Object> old_length;
11630
11631 if (old_attributes != ABSENT) {
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000011632 if (self->GetLocalElementAccessorPair(index) == NULL)
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011633 old_value = Object::GetElement(self, index);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011634 } else if (self->IsJSArray()) {
11635 // Store old array length in case adding an element grows the array.
11636 old_length = handle(Handle<JSArray>::cast(self)->length(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637 }
11638
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011639 // Check for lookup interceptor
11640 MaybeObject* result = self->HasIndexedInterceptor()
11641 ? self->SetElementWithInterceptor(
11642 index, *value, attributes, strict_mode, check_prototype, set_mode)
11643 : self->SetElementWithoutInterceptor(
11644 index, *value, attributes, strict_mode, check_prototype, set_mode);
11645
11646 Handle<Object> hresult;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011647 if (!result->ToHandle(&hresult, isolate)) return result;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011648
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011649 Handle<String> name = isolate->factory()->Uint32ToString(index);
11650 PropertyAttributes new_attributes = self->GetLocalElementAttribute(index);
11651 if (old_attributes == ABSENT) {
11652 EnqueueChangeRecord(self, "new", name, old_value);
11653 if (self->IsJSArray() &&
11654 !old_length->SameValue(Handle<JSArray>::cast(self)->length())) {
11655 EnqueueChangeRecord(
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011656 self, "updated", isolate->factory()->length_string(), old_length);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011657 }
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000011658 } else if (old_value->IsTheHole()) {
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000011659 EnqueueChangeRecord(self, "reconfigured", name, old_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000011660 } else {
danno@chromium.orgca29dd82013-04-26 11:59:48 +000011661 Handle<Object> new_value = Object::GetElement(self, index);
11662 bool value_changed = !old_value->SameValue(*new_value);
mstarzinger@chromium.orge3b8d0f2013-02-01 09:06:41 +000011663 if (old_attributes != new_attributes) {
11664 if (!value_changed) old_value = isolate->factory()->the_hole_value();
11665 EnqueueChangeRecord(self, "reconfigured", name, old_value);
11666 } else if (value_changed) {
11667 EnqueueChangeRecord(self, "updated", name, old_value);
11668 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +000011669 }
11670
11671 return *hresult;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011672}
11673
11674
lrn@chromium.org303ada72010-10-27 09:33:13 +000011675MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +000011676 Object* value,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011677 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011678 StrictModeFlag strict_mode,
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011679 bool check_prototype,
11680 SetPropertyMode set_mode) {
11681 ASSERT(HasDictionaryElements() ||
11682 HasDictionaryArgumentsElements() ||
11683 (attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011684 Isolate* isolate = GetIsolate();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +000011685 if (FLAG_trace_external_array_abuse &&
11686 IsExternalArrayElementsKind(GetElementsKind())) {
11687 CheckArrayAbuse(this, "external elements write", index);
11688 }
11689 if (FLAG_trace_js_array_abuse &&
11690 !IsExternalArrayElementsKind(GetElementsKind())) {
11691 if (IsJSArray()) {
11692 CheckArrayAbuse(this, "elements write", index, true);
11693 }
11694 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011695 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011696 case FAST_SMI_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011697 case FAST_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011698 case FAST_HOLEY_SMI_ELEMENTS:
11699 case FAST_HOLEY_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000011700 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011701 case FAST_DOUBLE_ELEMENTS:
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011702 case FAST_HOLEY_DOUBLE_ELEMENTS:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011703 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011704 case EXTERNAL_PIXEL_ELEMENTS: {
11705 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011706 return pixels->SetValue(index, value);
11707 }
ager@chromium.org3811b432009-10-28 14:53:37 +000011708 case EXTERNAL_BYTE_ELEMENTS: {
11709 ExternalByteArray* array = ExternalByteArray::cast(elements());
11710 return array->SetValue(index, value);
11711 }
11712 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
11713 ExternalUnsignedByteArray* array =
11714 ExternalUnsignedByteArray::cast(elements());
11715 return array->SetValue(index, value);
11716 }
11717 case EXTERNAL_SHORT_ELEMENTS: {
11718 ExternalShortArray* array = ExternalShortArray::cast(elements());
11719 return array->SetValue(index, value);
11720 }
11721 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
11722 ExternalUnsignedShortArray* array =
11723 ExternalUnsignedShortArray::cast(elements());
11724 return array->SetValue(index, value);
11725 }
11726 case EXTERNAL_INT_ELEMENTS: {
11727 ExternalIntArray* array = ExternalIntArray::cast(elements());
11728 return array->SetValue(index, value);
11729 }
11730 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
11731 ExternalUnsignedIntArray* array =
11732 ExternalUnsignedIntArray::cast(elements());
11733 return array->SetValue(index, value);
11734 }
11735 case EXTERNAL_FLOAT_ELEMENTS: {
11736 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
11737 return array->SetValue(index, value);
11738 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011739 case EXTERNAL_DOUBLE_ELEMENTS: {
11740 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
11741 return array->SetValue(index, value);
11742 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000011743 case DICTIONARY_ELEMENTS:
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011744 return SetDictionaryElement(index, value, attr, strict_mode,
11745 check_prototype, set_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +000011746 case NON_STRICT_ARGUMENTS_ELEMENTS: {
11747 FixedArray* parameter_map = FixedArray::cast(elements());
11748 uint32_t length = parameter_map->length();
11749 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +000011750 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000011751 if (probe != NULL && !probe->IsTheHole()) {
11752 Context* context = Context::cast(parameter_map->get(0));
11753 int context_index = Smi::cast(probe)->value();
11754 ASSERT(!context->get(context_index)->IsTheHole());
11755 context->set(context_index, value);
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011756 // Redefining attributes of an aliased element destroys fast aliasing.
11757 if (set_mode == SET_PROPERTY || attr == NONE) return value;
11758 parameter_map->set_the_hole(index + 2);
11759 // For elements that are still writable we re-establish slow aliasing.
11760 if ((attr & READ_ONLY) == 0) {
11761 MaybeObject* maybe_entry =
11762 isolate->heap()->AllocateAliasedArgumentsEntry(context_index);
11763 if (!maybe_entry->ToObject(&value)) return maybe_entry;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011764 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011765 }
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +000011766 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
11767 if (arguments->IsDictionary()) {
11768 return SetDictionaryElement(index, value, attr, strict_mode,
11769 check_prototype, set_mode);
11770 } else {
11771 return SetFastElement(index, value, strict_mode, check_prototype);
11772 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011773 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011774 }
11775 // All possible cases have been handled above. Add a return to avoid the
11776 // complaints from the compiler.
11777 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011778 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011779}
11780
11781
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011782Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
11783 ElementsKind to_kind) {
11784 CALL_HEAP_FUNCTION(object->GetIsolate(),
11785 object->TransitionElementsKind(to_kind),
11786 Object);
11787}
11788
11789
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011790MaybeObject* JSObject::UpdateAllocationSiteInfo(ElementsKind to_kind) {
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011791 if (!FLAG_track_allocation_sites || !IsJSArray()) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011792 return this;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011793 }
11794
11795 AllocationSiteInfo* info = AllocationSiteInfo::FindForJSObject(this);
11796 if (info == NULL) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011797 return this;
yangguo@chromium.org46a2a512013-01-18 16:29:40 +000011798 }
11799
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011800 if (info->payload()->IsJSArray()) {
11801 JSArray* payload = JSArray::cast(info->payload());
11802 ElementsKind kind = payload->GetElementsKind();
11803 if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
11804 // If the array is huge, it's not likely to be defined in a local
11805 // function, so we shouldn't make new instances of it very often.
11806 uint32_t length = 0;
11807 CHECK(payload->length()->ToArrayIndex(&length));
11808 if (length <= AllocationSiteInfo::kMaximumArrayBytesToPretransition) {
11809 if (FLAG_trace_track_allocation_sites) {
11810 PrintF(
11811 "AllocationSiteInfo: JSArray %p boilerplate updated %s->%s\n",
11812 reinterpret_cast<void*>(this),
11813 ElementsKindToString(kind),
11814 ElementsKindToString(to_kind));
11815 }
11816 return payload->TransitionElementsKind(to_kind);
11817 }
11818 }
11819 } else if (info->payload()->IsJSGlobalPropertyCell()) {
11820 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(info->payload());
11821 Object* cell_contents = cell->value();
11822 if (cell_contents->IsSmi()) {
11823 ElementsKind kind = static_cast<ElementsKind>(
11824 Smi::cast(cell_contents)->value());
11825 if (AllocationSiteInfo::GetMode(kind, to_kind) == TRACK_ALLOCATION_SITE) {
11826 if (FLAG_trace_track_allocation_sites) {
11827 PrintF("AllocationSiteInfo: JSArray %p info updated %s->%s\n",
11828 reinterpret_cast<void*>(this),
11829 ElementsKindToString(kind),
11830 ElementsKindToString(to_kind));
11831 }
11832 cell->set_value(Smi::FromInt(to_kind));
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000011833 }
11834 }
11835 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011836 return this;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000011837}
11838
11839
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011840MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000011841 ASSERT(!map()->is_observed());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011842 ElementsKind from_kind = map()->elements_kind();
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011843
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011844 if (IsFastHoleyElementsKind(from_kind)) {
11845 to_kind = GetHoleyElementsKind(to_kind);
11846 }
11847
ulan@chromium.org8e8d8822012-11-23 14:36:46 +000011848 if (from_kind == to_kind) return this;
11849
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000011850 MaybeObject* maybe_failure = UpdateAllocationSiteInfo(to_kind);
11851 if (maybe_failure->IsFailure()) return maybe_failure;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000011852
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011853 Isolate* isolate = GetIsolate();
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011854 if (elements() == isolate->heap()->empty_fixed_array() ||
11855 (IsFastSmiOrObjectElementsKind(from_kind) &&
11856 IsFastSmiOrObjectElementsKind(to_kind)) ||
11857 (from_kind == FAST_DOUBLE_ELEMENTS &&
11858 to_kind == FAST_HOLEY_DOUBLE_ELEMENTS)) {
11859 ASSERT(from_kind != TERMINAL_FAST_ELEMENTS_KIND);
11860 // No change is needed to the elements() buffer, the transition
11861 // only requires a map change.
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011862 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
11863 Map* new_map;
11864 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
11865 set_map(new_map);
11866 if (FLAG_trace_elements_transitions) {
11867 FixedArrayBase* elms = FixedArrayBase::cast(elements());
11868 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
11869 }
11870 return this;
11871 }
11872
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011873 FixedArrayBase* elms = FixedArrayBase::cast(elements());
11874 uint32_t capacity = static_cast<uint32_t>(elms->length());
11875 uint32_t length = capacity;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011876
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011877 if (IsJSArray()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011878 Object* raw_length = JSArray::cast(this)->length();
11879 if (raw_length->IsUndefined()) {
11880 // If length is undefined, then JSArray is being initialized and has no
11881 // elements, assume a length of zero.
11882 length = 0;
11883 } else {
11884 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011885 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011886 }
11887
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011888 if (IsFastSmiElementsKind(from_kind) &&
11889 IsFastDoubleElementsKind(to_kind)) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011890 MaybeObject* maybe_result =
11891 SetFastDoubleElementsCapacityAndLength(capacity, length);
11892 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011893 ValidateElements();
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011894 return this;
11895 }
11896
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011897 if (IsFastDoubleElementsKind(from_kind) &&
11898 IsFastObjectElementsKind(to_kind)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011899 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011900 capacity, length, kDontAllowSmiElements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011901 if (maybe_result->IsFailure()) return maybe_result;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011902 ValidateElements();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011903 return this;
11904 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011905
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011906 // This method should never be called for any other case than the ones
11907 // handled above.
11908 UNREACHABLE();
11909 return GetIsolate()->heap()->null_value();
11910}
11911
11912
11913// static
11914bool Map::IsValidElementsTransition(ElementsKind from_kind,
11915 ElementsKind to_kind) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000011916 // Transitions can't go backwards.
11917 if (!IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
11918 return false;
11919 }
11920
11921 // Transitions from HOLEY -> PACKED are not allowed.
11922 return !IsFastHoleyElementsKind(from_kind) ||
11923 IsFastHoleyElementsKind(to_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011924}
11925
11926
lrn@chromium.org303ada72010-10-27 09:33:13 +000011927MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
11928 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011929 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000011930 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011931 // Check to see if we need to update the length. For now, we make
11932 // sure that the length stays within 32-bits (unsigned).
11933 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011934 Object* len;
11935 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011937 if (!maybe_len->ToObject(&len)) return maybe_len;
11938 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011939 set_length(len);
11940 }
11941 return value;
11942}
11943
11944
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000011945MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000011946 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 // Make sure that the top context does not change when doing
11949 // callbacks or interceptor calls.
11950 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011951 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000011952 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
11953 Handle<Object> this_handle(receiver, isolate);
11954 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011955 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011956 v8::IndexedPropertyGetter getter =
11957 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011958 LOG(isolate,
11959 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
11960 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000011961 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962 v8::Handle<v8::Value> result;
11963 {
11964 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +000011965 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966 result = getter(index, info);
11967 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011968 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000011969 if (!result.IsEmpty()) {
11970 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
11971 result_internal->VerifyApiCallResultType();
11972 return *result_internal;
11973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974 }
11975
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011976 Heap* heap = holder_handle->GetHeap();
11977 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011978 MaybeObject* raw_result = handler->Get(*this_handle,
rossberg@chromium.org28a37082011-08-22 11:03:23 +000011979 *holder_handle,
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000011980 index);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011981 if (raw_result != heap->the_hole_value()) return raw_result;
11982
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011983 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011985 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 if (pt == heap->null_value()) return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011987 return pt->GetElementWithReceiver(*this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988}
11989
11990
11991bool JSObject::HasDenseElements() {
11992 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000011993 int used = 0;
11994 GetElementsCapacityAndUsage(&capacity, &used);
11995 return (capacity == 0) || (used > (capacity / 2));
11996}
11997
11998
11999void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
12000 *capacity = 0;
12001 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012002
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012003 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
12004 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012005 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012006 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012007 backing_store_base =
12008 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
12009 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012010 if (backing_store->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012011 SeededNumberDictionary* dictionary =
12012 SeededNumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012013 *capacity = dictionary->Capacity();
12014 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000012015 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012016 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012017 // Fall through.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012018 case FAST_SMI_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +000012019 case FAST_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012020 if (IsJSArray()) {
12021 *capacity = backing_store_base->length();
12022 *used = Smi::cast(JSArray::cast(this)->length())->value();
12023 break;
12024 }
12025 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012026 case FAST_HOLEY_SMI_ELEMENTS:
12027 case FAST_HOLEY_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012028 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012029 *capacity = backing_store->length();
12030 for (int i = 0; i < *capacity; ++i) {
12031 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012032 }
12033 break;
12034 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012035 SeededNumberDictionary* dictionary =
12036 SeededNumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012037 *capacity = dictionary->Capacity();
12038 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012039 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012040 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012041 case FAST_DOUBLE_ELEMENTS:
mmassi@chromium.org7028c052012-06-13 11:51:58 +000012042 if (IsJSArray()) {
12043 *capacity = backing_store_base->length();
12044 *used = Smi::cast(JSArray::cast(this)->length())->value();
12045 break;
12046 }
12047 // Fall through if packing is not guaranteed.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012048 case FAST_HOLEY_DOUBLE_ELEMENTS: {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012049 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012050 *capacity = elms->length();
12051 for (int i = 0; i < *capacity; i++) {
12052 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012053 }
12054 break;
12055 }
ager@chromium.org3811b432009-10-28 14:53:37 +000012056 case EXTERNAL_BYTE_ELEMENTS:
12057 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
12058 case EXTERNAL_SHORT_ELEMENTS:
12059 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
12060 case EXTERNAL_INT_ELEMENTS:
12061 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012062 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012063 case EXTERNAL_DOUBLE_ELEMENTS:
12064 case EXTERNAL_PIXEL_ELEMENTS:
12065 // External arrays are considered 100% used.
12066 ExternalArray* external_array = ExternalArray::cast(elements());
12067 *capacity = external_array->length();
12068 *used = external_array->length();
12069 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012070 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012071}
12072
12073
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012074bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012075 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
12076 kMaxUncheckedFastElementsLength);
12077 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
12078 (new_capacity <= kMaxUncheckedFastElementsLength &&
12079 GetHeap()->InNewSpace(this))) {
12080 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012081 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012082 // If the fast-case backing storage takes up roughly three times as
12083 // much space (in machine words) as a dictionary backing storage
12084 // would, the object should have slow elements.
12085 int old_capacity = 0;
12086 int used_elements = 0;
12087 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012088 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
12089 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012090 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012091}
12092
12093
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012094bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +000012095 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012096 // If the elements are sparse, we should not go back to fast case.
12097 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012098 // An object requiring access checks is never allowed to have fast
12099 // elements. If it had fast elements we would skip security checks.
12100 if (IsAccessCheckNeeded()) return false;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000012101 // Observed objects may not go to fast mode because they rely on map checks,
12102 // and for fast element accesses we sometimes check element kinds only.
12103 if (FLAG_harmony_observation && map()->is_observed()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012104
12105 FixedArray* elements = FixedArray::cast(this->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012106 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012107 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012108 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012109 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012110 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +000012111 }
12112 // If an element has been added at a very high index in the elements
12113 // dictionary, we cannot go back to fast case.
12114 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012116 // space (in machine words) as a fast-case backing storage would,
12117 // the object should have fast elements.
12118 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012120 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012122 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012124 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012125 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000012126 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127}
12128
12129
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012130bool JSObject::ShouldConvertToFastDoubleElements(
12131 bool* has_smi_only_elements) {
12132 *has_smi_only_elements = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012133 if (FLAG_unbox_double_arrays) {
12134 ASSERT(HasDictionaryElements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012135 SeededNumberDictionary* dictionary =
12136 SeededNumberDictionary::cast(elements());
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012137 bool found_double = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012138 for (int i = 0; i < dictionary->Capacity(); i++) {
12139 Object* key = dictionary->KeyAt(i);
12140 if (key->IsNumber()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012141 Object* value = dictionary->ValueAt(i);
12142 if (!value->IsNumber()) return false;
12143 if (!value->IsSmi()) {
12144 found_double = true;
12145 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012146 }
12147 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000012148 *has_smi_only_elements = !found_double;
12149 return found_double;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012150 } else {
12151 return false;
12152 }
12153}
12154
12155
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012156// Certain compilers request function template instantiation when they
12157// see the definition of the other template functions in the
12158// class. This requires us to have the template functions put
12159// together, so even though this function belongs in objects-debug.cc,
12160// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +000012161#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012162template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +000012163void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012164 int capacity = HashTable<Shape, Key>::Capacity();
12165 for (int i = 0; i < capacity; i++) {
12166 Object* k = HashTable<Shape, Key>::KeyAt(i);
12167 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000012168 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012169 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000012170 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012171 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000012172 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012173 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000012174 PrintF(out, ": ");
12175 ValueAt(i)->ShortPrint(out);
12176 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012177 }
12178 }
12179}
12180#endif
12181
12182
12183template<typename Shape, typename Key>
12184void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012185 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012186 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012187 AssertNoAllocation no_gc;
12188 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012189 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012190 Object* k = Dictionary<Shape, Key>::KeyAt(i);
12191 if (Dictionary<Shape, Key>::IsKey(k)) {
12192 elements->set(pos++, ValueAt(i), mode);
12193 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 }
12195 ASSERT(pos == elements->length());
12196}
12197
12198
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199InterceptorInfo* JSObject::GetNamedInterceptor() {
12200 ASSERT(map()->has_named_interceptor());
12201 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012202 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012204 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205 return InterceptorInfo::cast(result);
12206}
12207
12208
12209InterceptorInfo* JSObject::GetIndexedInterceptor() {
12210 ASSERT(map()->has_indexed_interceptor());
12211 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012212 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012213 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012214 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012215 return InterceptorInfo::cast(result);
12216}
12217
12218
lrn@chromium.org303ada72010-10-27 09:33:13 +000012219MaybeObject* JSObject::GetPropertyPostInterceptor(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012220 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000012221 Name* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000012222 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012224 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012225 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012226 if (result.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +000012227 return GetProperty(receiver, &result, name, attributes);
12228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012229 // Continue searching via the prototype chain.
12230 Object* pt = GetPrototype();
12231 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012232 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233 return pt->GetPropertyWithReceiver(receiver, name, attributes);
12234}
12235
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012236
lrn@chromium.org303ada72010-10-27 09:33:13 +000012237MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012238 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000012239 Name* name,
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012240 PropertyAttributes* attributes) {
12241 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012242 LookupResult result(GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012243 LocalLookupRealNamedProperty(name, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012244 if (result.IsFound()) {
ager@chromium.org5c838252010-02-19 08:53:10 +000012245 return GetProperty(receiver, &result, name, attributes);
12246 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012247 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000012248}
12249
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250
lrn@chromium.org303ada72010-10-27 09:33:13 +000012251MaybeObject* JSObject::GetPropertyWithInterceptor(
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012252 Object* receiver,
ulan@chromium.org750145a2013-03-07 15:14:13 +000012253 Name* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000012254 PropertyAttributes* attributes) {
ulan@chromium.org750145a2013-03-07 15:14:13 +000012255 // TODO(rossberg): Support symbols in the API.
12256 if (name->IsSymbol()) return GetHeap()->undefined_value();
12257
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012258 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012259 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012260 HandleScope scope(isolate);
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000012261 Handle<Object> receiver_handle(receiver, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012262 Handle<JSObject> holder_handle(this);
ulan@chromium.org750145a2013-03-07 15:14:13 +000012263 Handle<String> name_handle(String::cast(name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264
12265 if (!interceptor->getter()->IsUndefined()) {
12266 v8::NamedPropertyGetter getter =
12267 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012268 LOG(isolate,
12269 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
12270 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000012271 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272 v8::Handle<v8::Value> result;
12273 {
12274 // Leaving JavaScript.
danno@chromium.orgca29dd82013-04-26 11:59:48 +000012275 VMState<EXTERNAL> state(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012276 result = getter(v8::Utils::ToLocal(name_handle), info);
12277 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012278 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012279 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012280 *attributes = NONE;
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +000012281 Handle<Object> result_internal = v8::Utils::OpenHandle(*result);
12282 result_internal->VerifyApiCallResultType();
12283 return *result_internal;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012284 }
12285 }
12286
lrn@chromium.org303ada72010-10-27 09:33:13 +000012287 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 *receiver_handle,
12289 *name_handle,
12290 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012291 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +000012292 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012293}
12294
12295
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000012296bool JSObject::HasRealNamedProperty(Isolate* isolate, Name* key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012297 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012298 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012299 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
12300 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012301 return false;
12302 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012303 }
12304
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012305 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012306 LocalLookupRealNamedProperty(key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012307 return result.IsFound() && !result.IsInterceptor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012308}
12309
12310
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000012311bool JSObject::HasRealElementProperty(Isolate* isolate, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012312 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012313 if (IsAccessCheckNeeded()) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000012314 if (!isolate->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
12315 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012316 return false;
12317 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318 }
12319
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000012320 return GetElementAttributeWithoutInterceptor(this, index, false) != ABSENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012321}
12322
12323
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000012324bool JSObject::HasRealNamedCallbackProperty(Isolate* isolate, Name* key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012326 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012327 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
12328 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012329 return false;
12330 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012331 }
12332
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012333 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012334 LocalLookupRealNamedProperty(key, &result);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000012335 return result.IsPropertyCallbacks();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336}
12337
12338
12339int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012340 if (HasFastProperties()) {
12341 Map* map = this->map();
12342 if (filter == NONE) return map->NumberOfOwnDescriptors();
ulan@chromium.org750145a2013-03-07 15:14:13 +000012343 if (filter & DONT_ENUM) {
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012344 int result = map->EnumLength();
12345 if (result != Map::kInvalidEnumCache) return result;
12346 }
12347 return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter);
12348 }
12349 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012350}
12351
12352
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012353void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012354 Object* temp = get(i);
12355 set(i, get(j));
12356 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012357 if (this != numbers) {
12358 temp = numbers->get(i);
erikcorry0ad885c2011-11-21 13:51:57 +000012359 numbers->set(i, Smi::cast(numbers->get(j)));
12360 numbers->set(j, Smi::cast(temp));
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012362}
12363
12364
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012365static void InsertionSortPairs(FixedArray* content,
12366 FixedArray* numbers,
12367 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012368 for (int i = 1; i < len; i++) {
12369 int j = i;
12370 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012371 (NumberToUint32(numbers->get(j - 1)) >
12372 NumberToUint32(numbers->get(j)))) {
12373 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012374 j--;
12375 }
12376 }
12377}
12378
12379
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012380void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012381 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012382 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012383
12384 // Bottom-up max-heap construction.
12385 for (int i = 1; i < len; ++i) {
12386 int child_index = i;
12387 while (child_index > 0) {
12388 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012389 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
12390 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012391 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012392 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012393 } else {
12394 break;
12395 }
12396 child_index = parent_index;
12397 }
12398 }
12399
12400 // Extract elements and create sorted array.
12401 for (int i = len - 1; i > 0; --i) {
12402 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012403 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012404 // Sift down the new top element.
12405 int parent_index = 0;
12406 while (true) {
12407 int child_index = ((parent_index + 1) << 1) - 1;
12408 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012409 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
12410 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
12411 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012412 if (child_index + 1 >= i || child1_value > child2_value) {
12413 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012414 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012415 parent_index = child_index;
12416 } else {
12417 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012418 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012419 parent_index = child_index + 1;
12420 }
12421 }
12422 }
12423}
12424
12425
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012426// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
12427void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
12428 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012429 // For small arrays, simply use insertion sort.
12430 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012431 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012432 return;
12433 }
12434 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012435 uint32_t min_index = NumberToUint32(numbers->get(0));
12436 uint32_t max_index = min_index;
12437 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012438 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012439 if (NumberToUint32(numbers->get(i)) < min_index) {
12440 min_index = NumberToUint32(numbers->get(i));
12441 } else if (NumberToUint32(numbers->get(i)) > max_index) {
12442 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012443 }
12444 }
12445 if (max_index - min_index + 1 == len) {
12446 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012447 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012448 // avoid hanging in case they are not.
12449 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012450 uint32_t p;
12451 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012452 // While the current element at i is not at its correct position p,
12453 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012454 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012455 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012456 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012457 }
12458 }
12459 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012460 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012461 return;
12462 }
12463}
12464
12465
12466// Fill in the names of local properties into the supplied storage. The main
12467// purpose of this function is to provide reflection information for the object
12468// mirrors.
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000012469void JSObject::GetLocalPropertyNames(
12470 FixedArray* storage, int index, PropertyAttributes filter) {
12471 ASSERT(storage->length() >= (NumberOfLocalProperties(filter) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472 if (HasFastProperties()) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000012473 int real_size = map()->NumberOfOwnDescriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012474 DescriptorArray* descs = map()->instance_descriptors();
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000012475 for (int i = 0; i < real_size; i++) {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000012476 if ((descs->GetDetails(i).attributes() & filter) == 0 &&
12477 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) {
12478 storage->set(index++, descs->GetKey(i));
12479 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012481 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012482 property_dictionary()->CopyKeysTo(storage,
12483 index,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000012484 filter,
ulan@chromium.org750145a2013-03-07 15:14:13 +000012485 NameDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012486 }
12487}
12488
12489
12490int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
12491 return GetLocalElementKeys(NULL, filter);
12492}
12493
12494
12495int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012496 // Fast case for objects with no elements.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012497 if (!IsJSValue() && HasFastObjectElements()) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012498 uint32_t length = IsJSArray() ?
12499 static_cast<uint32_t>(
12500 Smi::cast(JSArray::cast(this)->length())->value()) :
12501 static_cast<uint32_t>(FixedArray::cast(elements())->length());
12502 if (length == 0) return 0;
12503 }
12504 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012505 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
12506}
12507
12508
12509int JSObject::GetLocalElementKeys(FixedArray* storage,
12510 PropertyAttributes filter) {
12511 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012512 switch (GetElementsKind()) {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012513 case FAST_SMI_ELEMENTS:
12514 case FAST_ELEMENTS:
12515 case FAST_HOLEY_SMI_ELEMENTS:
12516 case FAST_HOLEY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012517 int length = IsJSArray() ?
12518 Smi::cast(JSArray::cast(this)->length())->value() :
12519 FixedArray::cast(elements())->length();
12520 for (int i = 0; i < length; i++) {
12521 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
12522 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012523 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012524 }
12525 counter++;
12526 }
12527 }
12528 ASSERT(!storage || storage->length() >= counter);
12529 break;
12530 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000012531 case FAST_DOUBLE_ELEMENTS:
12532 case FAST_HOLEY_DOUBLE_ELEMENTS: {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012533 int length = IsJSArray() ?
12534 Smi::cast(JSArray::cast(this)->length())->value() :
12535 FixedDoubleArray::cast(elements())->length();
12536 for (int i = 0; i < length; i++) {
12537 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
12538 if (storage != NULL) {
12539 storage->set(counter, Smi::FromInt(i));
12540 }
12541 counter++;
12542 }
12543 }
12544 ASSERT(!storage || storage->length() >= counter);
12545 break;
12546 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000012547 case EXTERNAL_PIXEL_ELEMENTS: {
12548 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012549 while (counter < length) {
12550 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012551 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012552 }
12553 counter++;
12554 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012555 ASSERT(!storage || storage->length() >= counter);
12556 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012557 }
ager@chromium.org3811b432009-10-28 14:53:37 +000012558 case EXTERNAL_BYTE_ELEMENTS:
12559 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
12560 case EXTERNAL_SHORT_ELEMENTS:
12561 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
12562 case EXTERNAL_INT_ELEMENTS:
12563 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000012564 case EXTERNAL_FLOAT_ELEMENTS:
12565 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000012566 int length = ExternalArray::cast(elements())->length();
12567 while (counter < length) {
12568 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012569 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +000012570 }
12571 counter++;
12572 }
12573 ASSERT(!storage || storage->length() >= counter);
12574 break;
12575 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012576 case DICTIONARY_ELEMENTS: {
12577 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012578 element_dictionary()->CopyKeysTo(storage,
12579 filter,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012580 SeededNumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012581 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012582 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012583 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012584 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012585 case NON_STRICT_ARGUMENTS_ELEMENTS: {
12586 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012587 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012588 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
12589 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012590 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
12591 // will insert in storage starting at index 0.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012592 SeededNumberDictionary* dictionary =
12593 SeededNumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012594 if (storage != NULL) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012595 dictionary->CopyKeysTo(
12596 storage, filter, SeededNumberDictionary::UNSORTED);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012597 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012598 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012599 for (int i = 0; i < mapped_length; ++i) {
12600 if (!parameter_map->get(i + 2)->IsTheHole()) {
12601 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +000012602 ++counter;
12603 }
12604 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012605 if (storage != NULL) storage->SortPairs(storage, counter);
12606
12607 } else {
12608 int backing_length = arguments->length();
12609 int i = 0;
12610 for (; i < mapped_length; ++i) {
12611 if (!parameter_map->get(i + 2)->IsTheHole()) {
12612 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
12613 ++counter;
12614 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
12615 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
12616 ++counter;
12617 }
12618 }
12619 for (; i < backing_length; ++i) {
12620 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
12621 ++counter;
12622 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000012623 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012624 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +000012625 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012626 }
12627
12628 if (this->IsJSValue()) {
12629 Object* val = JSValue::cast(this)->value();
12630 if (val->IsString()) {
12631 String* str = String::cast(val);
12632 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012633 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012634 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012635 }
12636 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012637 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012638 }
12639 }
12640 ASSERT(!storage || storage->length() == counter);
12641 return counter;
12642}
12643
12644
12645int JSObject::GetEnumElementKeys(FixedArray* storage) {
12646 return GetLocalElementKeys(storage,
12647 static_cast<PropertyAttributes>(DONT_ENUM));
12648}
12649
12650
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012651// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000012652class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012653 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012654 explicit StringKey(String* string) :
12655 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012656 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012657
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012658 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012659 // We know that all entries in a hash table had their hash keys created.
12660 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012661 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012662 return false;
12663 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012664 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012665 }
12666
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012667 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012668
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012669 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012670
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012671 Object* AsObject(Heap* heap) { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012672
12673 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012674 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012675};
12676
ager@chromium.org381abbb2009-02-25 13:23:22 +000012677
12678// StringSharedKeys are used as keys in the eval cache.
12679class StringSharedKey : public HashTableKey {
12680 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012681 StringSharedKey(String* source,
12682 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012683 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012684 int scope_position)
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012685 : source_(source),
12686 shared_(shared),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012687 language_mode_(language_mode),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012688 scope_position_(scope_position) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012689
12690 bool IsMatch(Object* other) {
12691 if (!other->IsFixedArray()) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012692 FixedArray* other_array = FixedArray::cast(other);
12693 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
ager@chromium.org381abbb2009-02-25 13:23:22 +000012694 if (shared != shared_) return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012695 int language_unchecked = Smi::cast(other_array->get(2))->value();
12696 ASSERT(language_unchecked == CLASSIC_MODE ||
12697 language_unchecked == STRICT_MODE ||
12698 language_unchecked == EXTENDED_MODE);
12699 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
12700 if (language_mode != language_mode_) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012701 int scope_position = Smi::cast(other_array->get(3))->value();
12702 if (scope_position != scope_position_) return false;
12703 String* source = String::cast(other_array->get(1));
ager@chromium.org381abbb2009-02-25 13:23:22 +000012704 return source->Equals(source_);
12705 }
12706
ager@chromium.org381abbb2009-02-25 13:23:22 +000012707 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012708 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012709 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012710 int scope_position) {
ager@chromium.org381abbb2009-02-25 13:23:22 +000012711 uint32_t hash = source->Hash();
12712 if (shared->HasSourceCode()) {
12713 // Instead of using the SharedFunctionInfo pointer in the hash
12714 // code computation, we use a combination of the hash of the
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012715 // script source code and the start position of the calling scope.
12716 // We do this to ensure that the cache entries can survive garbage
ager@chromium.org381abbb2009-02-25 13:23:22 +000012717 // collection.
12718 Script* script = Script::cast(shared->script());
12719 hash ^= String::cast(script->source())->Hash();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012720 if (language_mode == STRICT_MODE) hash ^= 0x8000;
12721 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012722 hash += scope_position;
ager@chromium.org381abbb2009-02-25 13:23:22 +000012723 }
12724 return hash;
12725 }
12726
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012727 uint32_t Hash() {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012728 return StringSharedHashHelper(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012729 source_, shared_, language_mode_, scope_position_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012730 }
12731
12732 uint32_t HashForObject(Object* obj) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012733 FixedArray* other_array = FixedArray::cast(obj);
12734 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
12735 String* source = String::cast(other_array->get(1));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012736 int language_unchecked = Smi::cast(other_array->get(2))->value();
12737 ASSERT(language_unchecked == CLASSIC_MODE ||
12738 language_unchecked == STRICT_MODE ||
12739 language_unchecked == EXTENDED_MODE);
12740 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012741 int scope_position = Smi::cast(other_array->get(3))->value();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012742 return StringSharedHashHelper(
12743 source, shared, language_mode, scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012744 }
12745
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012746 MUST_USE_RESULT MaybeObject* AsObject(Heap* heap) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012747 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012748 { MaybeObject* maybe_obj = heap->AllocateFixedArray(4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012749 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12750 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012751 FixedArray* other_array = FixedArray::cast(obj);
12752 other_array->set(0, shared_);
12753 other_array->set(1, source_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012754 other_array->set(2, Smi::FromInt(language_mode_));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012755 other_array->set(3, Smi::FromInt(scope_position_));
12756 return other_array;
ager@chromium.org381abbb2009-02-25 13:23:22 +000012757 }
12758
ager@chromium.org381abbb2009-02-25 13:23:22 +000012759 private:
12760 String* source_;
12761 SharedFunctionInfo* shared_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012762 LanguageMode language_mode_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012763 int scope_position_;
ager@chromium.org381abbb2009-02-25 13:23:22 +000012764};
12765
12766
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012767// RegExpKey carries the source and flags of a regular expression as key.
12768class RegExpKey : public HashTableKey {
12769 public:
12770 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000012771 : string_(string),
12772 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012773
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000012774 // Rather than storing the key in the hash table, a pointer to the
12775 // stored value is stored where the key should be. IsMatch then
12776 // compares the search key to the found object, rather than comparing
12777 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012778 bool IsMatch(Object* obj) {
12779 FixedArray* val = FixedArray::cast(obj);
12780 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
12781 && (flags_ == val->get(JSRegExp::kFlagsIndex));
12782 }
12783
12784 uint32_t Hash() { return RegExpHash(string_, flags_); }
12785
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012786 Object* AsObject(Heap* heap) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012787 // Plain hash maps, which is where regexp keys are used, don't
12788 // use this function.
12789 UNREACHABLE();
12790 return NULL;
12791 }
12792
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012793 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012794 FixedArray* val = FixedArray::cast(obj);
12795 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
12796 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
12797 }
12798
12799 static uint32_t RegExpHash(String* string, Smi* flags) {
12800 return string->Hash() + flags->value();
12801 }
12802
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012803 String* string_;
12804 Smi* flags_;
12805};
12806
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012807// Utf8StringKey carries a vector of chars as key.
12808class Utf8StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012809 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012810 explicit Utf8StringKey(Vector<const char> string, uint32_t seed)
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000012811 : string_(string), hash_field_(0), seed_(seed) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012812
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012813 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012814 return String::cast(string)->IsUtf8EqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012815 }
12816
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012817 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012818 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000012819 hash_field_ = StringHasher::ComputeUtf8Hash(string_, seed_, &chars_);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012820 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000012821 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
12822 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012823 }
12824
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012825 uint32_t HashForObject(Object* other) {
12826 return String::cast(other)->Hash();
12827 }
12828
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012829 MaybeObject* AsObject(Heap* heap) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012830 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012831 return heap->AllocateInternalizedStringFromUtf8(string_,
12832 chars_,
12833 hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012834 }
12835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012836 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012837 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012838 int chars_; // Caches the number of characters when computing the hash code.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000012839 uint32_t seed_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012840};
12841
12842
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012843template <typename Char>
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012844class SequentialStringKey : public HashTableKey {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012845 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012846 explicit SequentialStringKey(Vector<const Char> string, uint32_t seed)
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000012847 : string_(string), hash_field_(0), seed_(seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012848
12849 uint32_t Hash() {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000012850 hash_field_ = StringHasher::HashSequentialString<Char>(string_.start(),
12851 string_.length(),
12852 seed_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012853
12854 uint32_t result = hash_field_ >> String::kHashShift;
12855 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
12856 return result;
12857 }
12858
12859
12860 uint32_t HashForObject(Object* other) {
12861 return String::cast(other)->Hash();
12862 }
12863
12864 Vector<const Char> string_;
12865 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000012866 uint32_t seed_;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012867};
12868
12869
12870
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012871class OneByteStringKey : public SequentialStringKey<uint8_t> {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012872 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012873 OneByteStringKey(Vector<const uint8_t> str, uint32_t seed)
12874 : SequentialStringKey<uint8_t>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012875
12876 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012877 return String::cast(string)->IsOneByteEqualTo(string_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012878 }
12879
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012880 MaybeObject* AsObject(Heap* heap) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012881 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012882 return heap->AllocateOneByteInternalizedString(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012883 }
12884};
12885
12886
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012887class SubStringOneByteStringKey : public HashTableKey {
danno@chromium.org40cb8782011-05-25 07:58:50 +000012888 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012889 explicit SubStringOneByteStringKey(Handle<SeqOneByteString> string,
12890 int from,
12891 int length)
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000012892 : string_(string), from_(from), length_(length) { }
danno@chromium.org40cb8782011-05-25 07:58:50 +000012893
12894 uint32_t Hash() {
12895 ASSERT(length_ >= 0);
12896 ASSERT(from_ + length_ <= string_->length());
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012897 uint8_t* chars = string_->GetChars() + from_;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000012898 hash_field_ = StringHasher::HashSequentialString(
12899 chars, length_, string_->GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000012900 uint32_t result = hash_field_ >> String::kHashShift;
12901 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
12902 return result;
12903 }
12904
12905
12906 uint32_t HashForObject(Object* other) {
12907 return String::cast(other)->Hash();
12908 }
12909
12910 bool IsMatch(Object* string) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012911 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
12912 return String::cast(string)->IsOneByteEqualTo(chars);
danno@chromium.org40cb8782011-05-25 07:58:50 +000012913 }
12914
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012915 MaybeObject* AsObject(Heap* heap) {
danno@chromium.org40cb8782011-05-25 07:58:50 +000012916 if (hash_field_ == 0) Hash();
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000012917 Vector<const uint8_t> chars(string_->GetChars() + from_, length_);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012918 return heap->AllocateOneByteInternalizedString(chars, hash_field_);
danno@chromium.org40cb8782011-05-25 07:58:50 +000012919 }
12920
12921 private:
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000012922 Handle<SeqOneByteString> string_;
danno@chromium.org40cb8782011-05-25 07:58:50 +000012923 int from_;
12924 int length_;
12925 uint32_t hash_field_;
12926};
12927
12928
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012929class TwoByteStringKey : public SequentialStringKey<uc16> {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012930 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012931 explicit TwoByteStringKey(Vector<const uc16> str, uint32_t seed)
12932 : SequentialStringKey<uc16>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012933
12934 bool IsMatch(Object* string) {
12935 return String::cast(string)->IsTwoByteEqualTo(string_);
12936 }
12937
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012938 MaybeObject* AsObject(Heap* heap) {
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012939 if (hash_field_ == 0) Hash();
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012940 return heap->AllocateTwoByteInternalizedString(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000012941 }
12942};
12943
12944
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012945// InternalizedStringKey carries a string/internalized-string object as key.
12946class InternalizedStringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012947 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012948 explicit InternalizedStringKey(String* string)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012950
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012951 bool IsMatch(Object* string) {
12952 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012953 }
12954
12955 uint32_t Hash() { return string_->Hash(); }
12956
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012957 uint32_t HashForObject(Object* other) {
12958 return String::cast(other)->Hash();
12959 }
12960
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000012961 MaybeObject* AsObject(Heap* heap) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012962 // Attempt to flatten the string, so that internalized strings will most
12963 // often be flat strings.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000012964 string_ = string_->TryFlattenGetString();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012965 // Internalize the string if possible.
12966 Map* map = heap->InternalizedStringMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012967 if (map != NULL) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000012968 string_->set_map_no_write_barrier(map);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012969 ASSERT(string_->IsInternalizedString());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012970 return string_;
12971 }
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000012972 // Otherwise allocate a new internalized string.
12973 return heap->AllocateInternalizedStringImpl(
12974 string_, string_->length(), string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012975 }
12976
12977 static uint32_t StringHash(Object* obj) {
12978 return String::cast(obj)->Hash();
12979 }
12980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012981 String* string_;
12982};
12983
12984
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012985template<typename Shape, typename Key>
12986void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012987 IteratePointers(v, 0, kElementsStartOffset);
12988}
12989
12990
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012991template<typename Shape, typename Key>
12992void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012993 IteratePointers(v,
12994 kElementsStartOffset,
12995 kHeaderSize + length() * kPointerSize);
12996}
12997
12998
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012999template<typename Shape, typename Key>
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013000MaybeObject* HashTable<Shape, Key>::Allocate(Heap* heap,
13001 int at_least_space_for,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000013002 MinimumCapacity capacity_option,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013003 PretenureFlag pretenure) {
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000013004 ASSERT(!capacity_option || IS_POWER_OF_TWO(at_least_space_for));
13005 int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
13006 ? at_least_space_for
13007 : ComputeCapacity(at_least_space_for);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000013008 if (capacity > HashTable::kMaxCapacity) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013009 return Failure::OutOfMemoryException(0x10);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013010 }
13011
lrn@chromium.org303ada72010-10-27 09:33:13 +000013012 Object* obj;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013013 { MaybeObject* maybe_obj =
13014 heap-> AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013015 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013016 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000013017 HashTable::cast(obj)->SetNumberOfElements(0);
13018 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
13019 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013020 return obj;
13021}
13022
13023
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013024// Find entry for key otherwise return kNotFound.
ulan@chromium.org750145a2013-03-07 15:14:13 +000013025int NameDictionary::FindEntry(Name* key) {
13026 if (!key->IsUniqueName()) {
13027 return HashTable<NameDictionaryShape, Name*>::FindEntry(key);
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013028 }
13029
ulan@chromium.org750145a2013-03-07 15:14:13 +000013030 // Optimized for unique names. Knowledge of the key type allows:
13031 // 1. Move the check if the key is unique out of the loop.
13032 // 2. Avoid comparing hash codes in unique-to-unique comparison.
13033 // 3. Detect a case when a dictionary key is not unique but the key is.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013034 // In case of positive result the dictionary key may be replaced by the
13035 // internalized string with minimal performance penalty. It gives a chance
13036 // to perform further lookups in code stubs (and significant performance
13037 // boost a certain style of code).
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013038
13039 // EnsureCapacity will guarantee the hash table is never full.
13040 uint32_t capacity = Capacity();
13041 uint32_t entry = FirstProbe(key->Hash(), capacity);
13042 uint32_t count = 1;
13043
13044 while (true) {
13045 int index = EntryToIndex(entry);
13046 Object* element = get(index);
13047 if (element->IsUndefined()) break; // Empty entry.
13048 if (key == element) return entry;
ulan@chromium.org750145a2013-03-07 15:14:13 +000013049 if (!element->IsUniqueName() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013050 !element->IsTheHole() &&
ulan@chromium.org750145a2013-03-07 15:14:13 +000013051 Name::cast(element)->Equals(key)) {
13052 // Replace a key that is a non-internalized string by the equivalent
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013053 // internalized string for faster further lookups.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013054 set(index, key);
13055 return entry;
13056 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000013057 ASSERT(element->IsTheHole() || !Name::cast(element)->Equals(key));
ricow@chromium.org4980dff2010-07-19 08:33:45 +000013058 entry = NextProbe(entry, count++, capacity);
13059 }
13060 return kNotFound;
13061}
13062
13063
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013064template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000013065MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
13066 ASSERT(NumberOfElements() < new_table->Capacity());
13067
13068 AssertNoAllocation no_gc;
13069 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
13070
13071 // Copy prefix to new array.
13072 for (int i = kPrefixStartIndex;
13073 i < kPrefixStartIndex + Shape::kPrefixSize;
13074 i++) {
13075 new_table->set(i, get(i), mode);
13076 }
13077
13078 // Rehash the elements.
13079 int capacity = Capacity();
13080 for (int i = 0; i < capacity; i++) {
13081 uint32_t from_index = EntryToIndex(i);
13082 Object* k = get(from_index);
13083 if (IsKey(k)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013084 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
ager@chromium.org04921a82011-06-27 13:21:41 +000013085 uint32_t insertion_index =
13086 EntryToIndex(new_table->FindInsertionEntry(hash));
13087 for (int j = 0; j < Shape::kEntrySize; j++) {
13088 new_table->set(insertion_index + j, get(from_index + j), mode);
13089 }
13090 }
13091 }
13092 new_table->SetNumberOfElements(NumberOfElements());
13093 new_table->SetNumberOfDeletedElements(0);
13094 return new_table;
13095}
13096
13097
13098template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000013099MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013100 int capacity = Capacity();
13101 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000013102 int nod = NumberOfDeletedElements();
13103 // Return if:
13104 // 50% is still free after adding n elements and
13105 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013106 if (nod <= (capacity - nof) >> 1) {
13107 int needed_free = nof >> 1;
13108 if (nof + needed_free <= capacity) return this;
13109 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013110
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013111 const int kMinCapacityForPretenure = 256;
13112 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013113 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013114 Object* obj;
13115 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013116 Allocate(GetHeap(),
13117 nof * 2,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000013118 USE_DEFAULT_MINIMUM_CAPACITY,
13119 pretenure ? TENURED : NOT_TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013120 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13121 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013122
ager@chromium.org04921a82011-06-27 13:21:41 +000013123 return Rehash(HashTable::cast(obj), key);
13124}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013125
ager@chromium.org04921a82011-06-27 13:21:41 +000013126
13127template<typename Shape, typename Key>
13128MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
13129 int capacity = Capacity();
13130 int nof = NumberOfElements();
13131
13132 // Shrink to fit the number of elements if only a quarter of the
13133 // capacity is filled with elements.
13134 if (nof > (capacity >> 2)) return this;
13135 // Allocate a new dictionary with room for at least the current
13136 // number of elements. The allocation method will make sure that
13137 // there is extra room in the dictionary for additions. Don't go
13138 // lower than room for 16 elements.
13139 int at_least_room_for = nof;
13140 if (at_least_room_for < 16) return this;
13141
13142 const int kMinCapacityForPretenure = 256;
13143 bool pretenure =
13144 (at_least_room_for > kMinCapacityForPretenure) &&
13145 !GetHeap()->InNewSpace(this);
13146 Object* obj;
13147 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013148 Allocate(GetHeap(),
13149 at_least_room_for,
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000013150 USE_DEFAULT_MINIMUM_CAPACITY,
13151 pretenure ? TENURED : NOT_TENURED);
ager@chromium.org04921a82011-06-27 13:21:41 +000013152 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013153 }
ager@chromium.org04921a82011-06-27 13:21:41 +000013154
13155 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013156}
13157
13158
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013159template<typename Shape, typename Key>
13160uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013161 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013162 uint32_t entry = FirstProbe(hash, capacity);
13163 uint32_t count = 1;
13164 // EnsureCapacity will guarantee the hash table is never full.
13165 while (true) {
13166 Object* element = KeyAt(entry);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000013167 if (element->IsUndefined() || element->IsTheHole()) break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013168 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013169 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013170 return entry;
13171}
13172
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013173// Force instantiation of template instances class.
13174// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013175
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013176template class HashTable<StringTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013177
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013178template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013179
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013180template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013181
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013182template class HashTable<ObjectHashTableShape<1>, Object*>;
13183
13184template class HashTable<ObjectHashTableShape<2>, Object*>;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000013185
ulan@chromium.org750145a2013-03-07 15:14:13 +000013186template class Dictionary<NameDictionaryShape, Name*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013187
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013188template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000013189
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013190template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
13191
13192template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013193 Allocate(Heap* heap, int at_least_space_for);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013194
13195template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013196 Allocate(Heap* heap, int at_least_space_for);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013197
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013198template MaybeObject* Dictionary<NameDictionaryShape, Name*>::
13199 Allocate(Heap* heap, int n);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013200
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013201template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013202 uint32_t, Object*);
13203
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013204template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
13205 AtPut(uint32_t, Object*);
13206
ulan@chromium.org65a89c22012-02-14 11:46:07 +000013207template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
13208 SlowReverseLookup(Object* value);
13209
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013210template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
13211 SlowReverseLookup(Object* value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013212
ulan@chromium.org750145a2013-03-07 15:14:13 +000013213template Object* Dictionary<NameDictionaryShape, Name*>::SlowReverseLookup(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013214 Object*);
13215
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013216template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013217 FixedArray*,
13218 PropertyAttributes,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013219 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013220
ulan@chromium.org750145a2013-03-07 15:14:13 +000013221template Object* Dictionary<NameDictionaryShape, Name*>::DeleteProperty(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013222 int, JSObject::DeleteMode);
13223
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013224template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
13225 DeleteProperty(int, JSObject::DeleteMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013226
ulan@chromium.org750145a2013-03-07 15:14:13 +000013227template MaybeObject* Dictionary<NameDictionaryShape, Name*>::Shrink(Name* n);
ager@chromium.org04921a82011-06-27 13:21:41 +000013228
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013229template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
ager@chromium.org04921a82011-06-27 13:21:41 +000013230 uint32_t);
13231
ulan@chromium.org750145a2013-03-07 15:14:13 +000013232template void Dictionary<NameDictionaryShape, Name*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000013233 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013234 int,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000013235 PropertyAttributes,
ulan@chromium.org750145a2013-03-07 15:14:13 +000013236 Dictionary<NameDictionaryShape, Name*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013237
13238template int
ulan@chromium.org750145a2013-03-07 15:14:13 +000013239Dictionary<NameDictionaryShape, Name*>::NumberOfElementsFilterAttributes(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013240 PropertyAttributes);
13241
ulan@chromium.org750145a2013-03-07 15:14:13 +000013242template MaybeObject* Dictionary<NameDictionaryShape, Name*>::Add(
13243 Name*, Object*, PropertyDetails);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013244
lrn@chromium.org303ada72010-10-27 09:33:13 +000013245template MaybeObject*
ulan@chromium.org750145a2013-03-07 15:14:13 +000013246Dictionary<NameDictionaryShape, Name*>::GenerateNewEnumerationIndices();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013247
13248template int
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013249Dictionary<SeededNumberDictionaryShape, uint32_t>::
13250 NumberOfElementsFilterAttributes(PropertyAttributes);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013251
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013252template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013253 uint32_t, Object*, PropertyDetails);
13254
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013255template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
13256 uint32_t, Object*, PropertyDetails);
13257
13258template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
13259 EnsureCapacity(int, uint32_t);
13260
13261template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
lrn@chromium.org303ada72010-10-27 09:33:13 +000013262 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013263
ulan@chromium.org750145a2013-03-07 15:14:13 +000013264template MaybeObject* Dictionary<NameDictionaryShape, Name*>::
13265 EnsureCapacity(int, Name*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013266
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013267template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
13268 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
13269
13270template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
13271 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013272
ulan@chromium.org750145a2013-03-07 15:14:13 +000013273template MaybeObject* Dictionary<NameDictionaryShape, Name*>::AddEntry(
13274 Name*, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013275
13276template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013277int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013278
13279template
ulan@chromium.org750145a2013-03-07 15:14:13 +000013280int Dictionary<NameDictionaryShape, Name*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000013281
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013282template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013283int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000013284
13285
ager@chromium.org5ec48922009-05-05 07:25:34 +000013286// Collates undefined and unexisting elements below limit from position
13287// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013288MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013289 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000013290 // Must stay in dictionary mode, either because of requires_slow_elements,
13291 // or because we are not going to sort (and therefore compact) all of the
13292 // elements.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013293 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013294 HeapNumber* result_double = NULL;
13295 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
13296 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013297 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013298 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013299 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
13300 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013301 result_double = HeapNumber::cast(new_double);
13302 }
13303
lrn@chromium.org303ada72010-10-27 09:33:13 +000013304 Object* obj;
13305 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013306 SeededNumberDictionary::Allocate(GetHeap(), dict->NumberOfElements());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013307 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13308 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013309 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000013310
13311 AssertNoAllocation no_alloc;
13312
ager@chromium.org5ec48922009-05-05 07:25:34 +000013313 uint32_t pos = 0;
13314 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000013315 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013316 for (int i = 0; i < capacity; i++) {
13317 Object* k = dict->KeyAt(i);
13318 if (dict->IsKey(k)) {
13319 ASSERT(k->IsNumber());
13320 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
13321 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
13322 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
13323 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000013324 PropertyDetails details = dict->DetailsAt(i);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013325 if (details.type() == CALLBACKS || details.IsReadOnly()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000013326 // Bail out and do the sorting of undefineds and array holes in JS.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000013327 // Also bail out if the element is not supposed to be moved.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000013328 return Smi::FromInt(-1);
13329 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013330 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013331 // In the following we assert that adding the entry to the new dictionary
13332 // does not cause GC. This is the case because we made sure to allocate
13333 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000013334 if (key < limit) {
13335 if (value->IsUndefined()) {
13336 undefs++;
13337 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013338 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
13339 // Adding an entry with the key beyond smi-range requires
13340 // allocation. Bailout.
13341 return Smi::FromInt(-1);
13342 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000013343 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013344 pos++;
13345 }
13346 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013347 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
13348 // Adding an entry with the key beyond smi-range requires
13349 // allocation. Bailout.
13350 return Smi::FromInt(-1);
13351 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000013352 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013353 }
13354 }
13355 }
13356
13357 uint32_t result = pos;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000013358 PropertyDetails no_details = PropertyDetails(NONE, NORMAL, 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013359 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013360 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000013361 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
13362 // Adding an entry with the key beyond smi-range requires
13363 // allocation. Bailout.
13364 return Smi::FromInt(-1);
13365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013366 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000013367 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013368 pos++;
13369 undefs--;
13370 }
13371
13372 set_elements(new_dict);
13373
13374 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
13375 return Smi::FromInt(static_cast<int>(result));
13376 }
13377
13378 ASSERT_NE(NULL, result_double);
13379 result_double->set_value(static_cast<double>(result));
13380 return result_double;
13381}
13382
13383
13384// Collects all defined (non-hole) and non-undefined (array) elements at
13385// the start of the elements array.
13386// If the object is in dictionary mode, it is converted to fast elements
13387// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013388MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013389 Heap* heap = GetHeap();
13390
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013391 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000013392 // Convert to fast elements containing only the existing properties.
13393 // Ordering is irrelevant, since we are going to sort anyway.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013394 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000013395 if (IsJSArray() || dict->requires_slow_elements() ||
13396 dict->max_number_key() >= limit) {
13397 return PrepareSlowElementsForSort(limit);
13398 }
13399 // Convert to fast elements.
13400
lrn@chromium.org303ada72010-10-27 09:33:13 +000013401 Object* obj;
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013402 MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
13403 FAST_HOLEY_ELEMENTS);
13404 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000013405 Map* new_map = Map::cast(obj);
13406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013407 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000013408 Object* new_array;
13409 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013410 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013411 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
13412 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013413 FixedArray* fast_elements = FixedArray::cast(new_array);
13414 dict->CopyValuesTo(fast_elements);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013415 ValidateElements();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000013416
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013417 set_map_and_elements(new_map, fast_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013418 } else if (HasExternalArrayElements()) {
13419 // External arrays cannot have holes or undefined elements.
13420 return Smi::FromInt(ExternalArray::cast(elements())->length());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013421 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013422 Object* obj;
13423 { MaybeObject* maybe_obj = EnsureWritableFastElements();
13424 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13425 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013426 }
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +000013427 ASSERT(HasFastSmiOrObjectElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000013428
13429 // Collect holes at the end, undefined before that and the rest at the
13430 // start, and return the number of non-hole, non-undefined values.
13431
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013432 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
13433 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000013434 if (limit > elements_length) {
13435 limit = elements_length ;
13436 }
13437 if (limit == 0) {
13438 return Smi::FromInt(0);
13439 }
13440
13441 HeapNumber* result_double = NULL;
13442 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
13443 // Pessimistically allocate space for return value before
13444 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013445 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013446 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013447 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
13448 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013449 result_double = HeapNumber::cast(new_double);
13450 }
13451
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013452 uint32_t result = 0;
13453 if (elements_base->map() == heap->fixed_double_array_map()) {
13454 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
13455 // Split elements into defined and the_hole, in that order.
13456 unsigned int holes = limit;
13457 // Assume most arrays contain no holes and undefined values, so minimize the
13458 // number of stores of non-undefined, non-the-hole values.
13459 for (unsigned int i = 0; i < holes; i++) {
13460 if (elements->is_the_hole(i)) {
13461 holes--;
13462 } else {
13463 continue;
13464 }
13465 // Position i needs to be filled.
13466 while (holes > i) {
13467 if (elements->is_the_hole(holes)) {
13468 holes--;
13469 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013470 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013471 break;
13472 }
13473 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013474 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013475 result = holes;
13476 while (holes < limit) {
13477 elements->set_the_hole(holes);
13478 holes++;
13479 }
13480 } else {
13481 FixedArray* elements = FixedArray::cast(elements_base);
13482 AssertNoAllocation no_alloc;
13483
13484 // Split elements into defined, undefined and the_hole, in that order. Only
13485 // count locations for undefined and the hole, and fill them afterwards.
13486 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
13487 unsigned int undefs = limit;
13488 unsigned int holes = limit;
13489 // Assume most arrays contain no holes and undefined values, so minimize the
13490 // number of stores of non-undefined, non-the-hole values.
13491 for (unsigned int i = 0; i < undefs; i++) {
13492 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000013493 if (current->IsTheHole()) {
13494 holes--;
13495 undefs--;
13496 } else if (current->IsUndefined()) {
13497 undefs--;
13498 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013499 continue;
13500 }
13501 // Position i needs to be filled.
13502 while (undefs > i) {
13503 current = elements->get(undefs);
13504 if (current->IsTheHole()) {
13505 holes--;
13506 undefs--;
13507 } else if (current->IsUndefined()) {
13508 undefs--;
13509 } else {
13510 elements->set(i, current, write_barrier);
13511 break;
13512 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013513 }
13514 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000013515 result = undefs;
13516 while (undefs < holes) {
13517 elements->set_undefined(undefs);
13518 undefs++;
13519 }
13520 while (holes < limit) {
13521 elements->set_the_hole(holes);
13522 holes++;
13523 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000013524 }
13525
13526 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
13527 return Smi::FromInt(static_cast<int>(result));
13528 }
13529 ASSERT_NE(NULL, result_double);
13530 result_double->set_value(static_cast<double>(result));
13531 return result_double;
13532}
13533
danno@chromium.orgf005df62013-04-30 16:36:45 +000013534ExternalArrayType JSTypedArray::type() {
13535 switch (elements()->map()->instance_type()) {
13536 case EXTERNAL_BYTE_ARRAY_TYPE:
13537 return kExternalByteArray;
13538 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
13539 return kExternalUnsignedByteArray;
13540 case EXTERNAL_SHORT_ARRAY_TYPE:
13541 return kExternalShortArray;
13542 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
13543 return kExternalUnsignedShortArray;
13544 case EXTERNAL_INT_ARRAY_TYPE:
13545 return kExternalIntArray;
13546 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
13547 return kExternalUnsignedIntArray;
13548 case EXTERNAL_FLOAT_ARRAY_TYPE:
13549 return kExternalFloatArray;
13550 case EXTERNAL_DOUBLE_ARRAY_TYPE:
13551 return kExternalDoubleArray;
13552 case EXTERNAL_PIXEL_ARRAY_TYPE:
13553 return kExternalPixelArray;
13554 default:
13555 return static_cast<ExternalArrayType>(-1);
13556 }
13557}
13558
ager@chromium.org5ec48922009-05-05 07:25:34 +000013559
ulan@chromium.org57ff8812013-05-10 08:16:55 +000013560size_t JSTypedArray::element_size() {
13561 switch (elements()->map()->instance_type()) {
13562 case EXTERNAL_BYTE_ARRAY_TYPE:
13563 return 1;
13564 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
13565 return 1;
13566 case EXTERNAL_SHORT_ARRAY_TYPE:
13567 return 2;
13568 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
13569 return 2;
13570 case EXTERNAL_INT_ARRAY_TYPE:
13571 return 4;
13572 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
13573 return 4;
13574 case EXTERNAL_FLOAT_ARRAY_TYPE:
13575 return 4;
13576 case EXTERNAL_DOUBLE_ARRAY_TYPE:
13577 return 8;
13578 case EXTERNAL_PIXEL_ARRAY_TYPE:
13579 return 1;
13580 default:
13581 UNREACHABLE();
13582 return 0;
13583 }
13584}
13585
13586
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000013587Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013588 uint8_t clamped_value = 0;
13589 if (index < static_cast<uint32_t>(length())) {
13590 if (value->IsSmi()) {
13591 int int_value = Smi::cast(value)->value();
13592 if (int_value < 0) {
13593 clamped_value = 0;
13594 } else if (int_value > 255) {
13595 clamped_value = 255;
13596 } else {
13597 clamped_value = static_cast<uint8_t>(int_value);
13598 }
13599 } else if (value->IsHeapNumber()) {
13600 double double_value = HeapNumber::cast(value)->value();
13601 if (!(double_value > 0)) {
13602 // NaN and less than zero clamp to zero.
13603 clamped_value = 0;
13604 } else if (double_value > 255) {
13605 // Greater than 255 clamp to 255.
13606 clamped_value = 255;
13607 } else {
13608 // Other doubles are rounded to the nearest integer.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000013609 clamped_value = static_cast<uint8_t>(lrint(double_value));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013610 }
13611 } else {
13612 // Clamp undefined to zero (default). All other types have been
13613 // converted to a number type further up in the call chain.
13614 ASSERT(value->IsUndefined());
13615 }
13616 set(index, clamped_value);
13617 }
13618 return Smi::FromInt(clamped_value);
13619}
13620
13621
ager@chromium.org3811b432009-10-28 14:53:37 +000013622template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013623static MaybeObject* ExternalArrayIntSetter(Heap* heap,
13624 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000013625 uint32_t index,
13626 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013627 ValueType cast_value = 0;
13628 if (index < static_cast<uint32_t>(receiver->length())) {
13629 if (value->IsSmi()) {
13630 int int_value = Smi::cast(value)->value();
13631 cast_value = static_cast<ValueType>(int_value);
13632 } else if (value->IsHeapNumber()) {
13633 double double_value = HeapNumber::cast(value)->value();
13634 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
13635 } else {
13636 // Clamp undefined to zero (default). All other types have been
13637 // converted to a number type further up in the call chain.
13638 ASSERT(value->IsUndefined());
13639 }
13640 receiver->set(index, cast_value);
13641 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013642 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013643}
13644
13645
lrn@chromium.org303ada72010-10-27 09:33:13 +000013646MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013647 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013648 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013649}
13650
13651
lrn@chromium.org303ada72010-10-27 09:33:13 +000013652MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
13653 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013654 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013655 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013656}
13657
13658
lrn@chromium.org303ada72010-10-27 09:33:13 +000013659MaybeObject* ExternalShortArray::SetValue(uint32_t index,
13660 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013661 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013662 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013663}
13664
13665
lrn@chromium.org303ada72010-10-27 09:33:13 +000013666MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
13667 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013668 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013669 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013670}
13671
13672
lrn@chromium.org303ada72010-10-27 09:33:13 +000013673MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013674 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013675 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013676}
13677
13678
lrn@chromium.org303ada72010-10-27 09:33:13 +000013679MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013680 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013681 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000013682 if (index < static_cast<uint32_t>(length())) {
13683 if (value->IsSmi()) {
13684 int int_value = Smi::cast(value)->value();
13685 cast_value = static_cast<uint32_t>(int_value);
13686 } else if (value->IsHeapNumber()) {
13687 double double_value = HeapNumber::cast(value)->value();
13688 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
13689 } else {
13690 // Clamp undefined to zero (default). All other types have been
13691 // converted to a number type further up in the call chain.
13692 ASSERT(value->IsUndefined());
13693 }
13694 set(index, cast_value);
13695 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013696 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013697}
13698
13699
lrn@chromium.org303ada72010-10-27 09:33:13 +000013700MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000013701 float cast_value = static_cast<float>(OS::nan_value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013702 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000013703 if (index < static_cast<uint32_t>(length())) {
13704 if (value->IsSmi()) {
13705 int int_value = Smi::cast(value)->value();
13706 cast_value = static_cast<float>(int_value);
13707 } else if (value->IsHeapNumber()) {
13708 double double_value = HeapNumber::cast(value)->value();
13709 cast_value = static_cast<float>(double_value);
13710 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000013711 // Clamp undefined to NaN (default). All other types have been
ager@chromium.org3811b432009-10-28 14:53:37 +000013712 // converted to a number type further up in the call chain.
13713 ASSERT(value->IsUndefined());
13714 }
13715 set(index, cast_value);
13716 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013717 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000013718}
13719
13720
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013721MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
yangguo@chromium.org56454712012-02-16 15:33:53 +000013722 double double_value = OS::nan_value();
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013723 Heap* heap = GetHeap();
13724 if (index < static_cast<uint32_t>(length())) {
13725 if (value->IsSmi()) {
13726 int int_value = Smi::cast(value)->value();
13727 double_value = static_cast<double>(int_value);
13728 } else if (value->IsHeapNumber()) {
13729 double_value = HeapNumber::cast(value)->value();
13730 } else {
yangguo@chromium.org56454712012-02-16 15:33:53 +000013731 // Clamp undefined to NaN (default). All other types have been
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000013732 // converted to a number type further up in the call chain.
13733 ASSERT(value->IsUndefined());
13734 }
13735 set(index, double_value);
13736 }
13737 return heap->AllocateHeapNumber(double_value);
13738}
13739
13740
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013741JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013742 ASSERT(!HasFastProperties());
13743 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013744 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013745}
13746
13747
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013748Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
13749 Handle<GlobalObject> global,
ulan@chromium.org750145a2013-03-07 15:14:13 +000013750 Handle<Name> name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013751 Isolate* isolate = global->GetIsolate();
13752 CALL_HEAP_FUNCTION(isolate,
13753 global->EnsurePropertyCell(*name),
13754 JSGlobalPropertyCell);
13755}
13756
13757
ulan@chromium.org750145a2013-03-07 15:14:13 +000013758MaybeObject* GlobalObject::EnsurePropertyCell(Name* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000013759 ASSERT(!HasFastProperties());
13760 int entry = property_dictionary()->FindEntry(name);
ulan@chromium.org750145a2013-03-07 15:14:13 +000013761 if (entry == NameDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013762 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000013763 Object* cell;
13764 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013765 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000013766 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
13767 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +000013768 PropertyDetails details(NONE, NORMAL, 0);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000013769 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000013770 Object* dictionary;
13771 { MaybeObject* maybe_dictionary =
13772 property_dictionary()->Add(name, cell, details);
13773 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
13774 }
ulan@chromium.org750145a2013-03-07 15:14:13 +000013775 set_properties(NameDictionary::cast(dictionary));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000013776 return cell;
13777 } else {
13778 Object* value = property_dictionary()->ValueAt(entry);
13779 ASSERT(value->IsJSGlobalPropertyCell());
13780 return value;
13781 }
13782}
13783
13784
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013785MaybeObject* StringTable::LookupString(String* string, Object** s) {
13786 InternalizedStringKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013787 return LookupKey(&key, s);
13788}
13789
13790
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013791// This class is used for looking up two character strings in the string table.
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013792// If we don't have a hit we don't want to waste much time so we unroll the
13793// string hash calculation loop here for speed. Doesn't work if the two
13794// characters form a decimal integer, since such strings have a different hash
13795// algorithm.
13796class TwoCharHashTableKey : public HashTableKey {
13797 public:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013798 TwoCharHashTableKey(uint16_t c1, uint16_t c2, uint32_t seed)
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013799 : c1_(c1), c2_(c2) {
13800 // Char 1.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000013801 uint32_t hash = seed;
13802 hash += c1;
13803 hash += hash << 10;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013804 hash ^= hash >> 6;
13805 // Char 2.
13806 hash += c2;
13807 hash += hash << 10;
13808 hash ^= hash >> 6;
13809 // GetHash.
13810 hash += hash << 3;
13811 hash ^= hash >> 11;
13812 hash += hash << 15;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000013813 if ((hash & String::kHashBitMask) == 0) hash = StringHasher::kZeroHash;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013814 hash_ = hash;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013815#ifdef DEBUG
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013816 // If this assert fails then we failed to reproduce the two-character
13817 // version of the string hashing algorithm above. One reason could be
13818 // that we were passed two digits as characters, since the hash
13819 // algorithm is different in that case.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013820 uint16_t chars[2] = {c1, c2};
13821 uint32_t check_hash = StringHasher::HashSequentialString(chars, 2, seed);
13822 hash = (hash << String::kHashShift) | String::kIsNotArrayIndexMask;
13823 ASSERT_EQ(static_cast<int32_t>(hash), static_cast<int32_t>(check_hash));
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013824#endif
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013825 }
13826
13827 bool IsMatch(Object* o) {
13828 if (!o->IsString()) return false;
13829 String* other = String::cast(o);
13830 if (other->length() != 2) return false;
13831 if (other->Get(0) != c1_) return false;
13832 return other->Get(1) == c2_;
13833 }
13834
13835 uint32_t Hash() { return hash_; }
13836 uint32_t HashForObject(Object* key) {
13837 if (!key->IsString()) return 0;
13838 return String::cast(key)->Hash();
13839 }
13840
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013841 Object* AsObject(Heap* heap) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013842 // The TwoCharHashTableKey is only used for looking in the string
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013843 // table, not for adding to it.
13844 UNREACHABLE();
13845 return NULL;
13846 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000013847
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013848 private:
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013849 uint16_t c1_;
13850 uint16_t c2_;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013851 uint32_t hash_;
13852};
13853
13854
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013855bool StringTable::LookupStringIfExists(String* string, String** result) {
13856 InternalizedStringKey key(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +000013857 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013858 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000013859 return false;
13860 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013861 *result = String::cast(KeyAt(entry));
13862 ASSERT(StringShape(*result).IsInternalized());
ager@chromium.org7c537e22008-10-16 08:43:32 +000013863 return true;
13864 }
13865}
13866
13867
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013868bool StringTable::LookupTwoCharsStringIfExists(uint16_t c1,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013869 uint16_t c2,
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013870 String** result) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000013871 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013872 int entry = FindEntry(&key);
13873 if (entry == kNotFound) {
13874 return false;
13875 } else {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013876 *result = String::cast(KeyAt(entry));
13877 ASSERT(StringShape(*result).IsInternalized());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000013878 return true;
13879 }
13880}
13881
13882
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013883MaybeObject* StringTable::LookupUtf8String(Vector<const char> str,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013884 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013885 Utf8StringKey key(str, GetHeap()->HashSeed());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013886 return LookupKey(&key, s);
13887}
13888
13889
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013890MaybeObject* StringTable::LookupOneByteString(Vector<const uint8_t> str,
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +000013891 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013892 OneByteStringKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013893 return LookupKey(&key, s);
13894}
13895
13896
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013897MaybeObject* StringTable::LookupSubStringOneByteString(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +000013898 Handle<SeqOneByteString> str,
13899 int from,
13900 int length,
13901 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013902 SubStringOneByteStringKey key(str, from, length);
danno@chromium.org40cb8782011-05-25 07:58:50 +000013903 return LookupKey(&key, s);
13904}
13905
13906
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013907MaybeObject* StringTable::LookupTwoByteString(Vector<const uc16> str,
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013908 Object** s) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013909 TwoByteStringKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000013910 return LookupKey(&key, s);
13911}
13912
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013913MaybeObject* StringTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013914 int entry = FindEntry(key);
13915
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013916 // String already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013917 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013918 *s = KeyAt(entry);
13919 return this;
13920 }
13921
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013922 // Adding new string. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000013923 Object* obj;
13924 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
13925 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
13926 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013927
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013928 // Create string object.
13929 Object* string;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000013930 { MaybeObject* maybe_string = key->AsObject(GetHeap());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013931 if (!maybe_string->ToObject(&string)) return maybe_string;
lrn@chromium.org303ada72010-10-27 09:33:13 +000013932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013933
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013934 // If the string table grew as part of EnsureCapacity, obj is not
13935 // the current string table and therefore we cannot use
13936 // StringTable::cast here.
13937 StringTable* table = reinterpret_cast<StringTable*>(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013938
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013939 // Add the new string and return it along with the string table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013940 entry = table->FindInsertionEntry(key->Hash());
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013941 table->set(EntryToIndex(entry), string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013942 table->ElementAdded();
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000013943 *s = string;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013944 return table;
13945}
13946
13947
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000013948// The key for the script compilation cache is dependent on the mode flags,
13949// because they change the global language mode and thus binding behaviour.
13950// If flags change at some point, we must ensure that we do not hit the cache
13951// for code compiled with different settings.
13952static LanguageMode CurrentGlobalLanguageMode() {
13953 return FLAG_use_strict
13954 ? (FLAG_harmony_scoping ? EXTENDED_MODE : STRICT_MODE)
13955 : CLASSIC_MODE;
13956}
13957
13958
13959Object* CompilationCacheTable::Lookup(String* src, Context* context) {
13960 SharedFunctionInfo* shared = context->closure()->shared();
13961 StringSharedKey key(src,
13962 shared,
13963 CurrentGlobalLanguageMode(),
13964 RelocInfo::kNoPosition);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000013965 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013966 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000013967 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000013968}
13969
13970
ricow@chromium.org83aa5492011-02-07 12:42:56 +000013971Object* CompilationCacheTable::LookupEval(String* src,
13972 Context* context,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013973 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013974 int scope_position) {
13975 StringSharedKey key(src,
13976 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000013977 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000013978 scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013979 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013980 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000013981 return get(EntryToIndex(entry) + 1);
13982}
13983
13984
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013985Object* CompilationCacheTable::LookupRegExp(String* src,
13986 JSRegExp::Flags flags) {
13987 RegExpKey key(src, flags);
13988 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013989 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000013990 return get(EntryToIndex(entry) + 1);
13991}
13992
13993
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000013994MaybeObject* CompilationCacheTable::Put(String* src,
13995 Context* context,
13996 Object* value) {
13997 SharedFunctionInfo* shared = context->closure()->shared();
13998 StringSharedKey key(src,
13999 shared,
14000 CurrentGlobalLanguageMode(),
14001 RelocInfo::kNoPosition);
14002 CompilationCacheTable* cache;
14003 MaybeObject* maybe_cache = EnsureCapacity(1, &key);
14004 if (!maybe_cache->To(&cache)) return maybe_cache;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014005
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014006 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014007 MaybeObject* maybe_k = key.AsObject(GetHeap());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014008 if (!maybe_k->To(&k)) return maybe_k;
14009
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014010 int entry = cache->FindInsertionEntry(key.Hash());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +000014011 cache->set(EntryToIndex(entry), k);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000014012 cache->set(EntryToIndex(entry) + 1, value);
14013 cache->ElementAdded();
14014 return cache;
14015}
14016
14017
lrn@chromium.org303ada72010-10-27 09:33:13 +000014018MaybeObject* CompilationCacheTable::PutEval(String* src,
14019 Context* context,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000014020 SharedFunctionInfo* value,
14021 int scope_position) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +000014022 StringSharedKey key(src,
14023 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000014024 value->language_mode(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000014025 scope_position);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014026 Object* obj;
14027 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
14028 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14029 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000014030
14031 CompilationCacheTable* cache =
14032 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014033 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000014034
lrn@chromium.org303ada72010-10-27 09:33:13 +000014035 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014036 { MaybeObject* maybe_k = key.AsObject(GetHeap());
lrn@chromium.org303ada72010-10-27 09:33:13 +000014037 if (!maybe_k->ToObject(&k)) return maybe_k;
14038 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000014039
14040 cache->set(EntryToIndex(entry), k);
14041 cache->set(EntryToIndex(entry) + 1, value);
14042 cache->ElementAdded();
14043 return cache;
14044}
14045
14046
lrn@chromium.org303ada72010-10-27 09:33:13 +000014047MaybeObject* CompilationCacheTable::PutRegExp(String* src,
14048 JSRegExp::Flags flags,
14049 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014050 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014051 Object* obj;
14052 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
14053 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14054 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014055
14056 CompilationCacheTable* cache =
14057 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014058 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000014059 // We store the value in the key slot, and compare the search key
14060 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000014061 cache->set(EntryToIndex(entry), value);
14062 cache->set(EntryToIndex(entry) + 1, value);
14063 cache->ElementAdded();
14064 return cache;
14065}
14066
14067
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014068void CompilationCacheTable::Remove(Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014069 Object* the_hole_value = GetHeap()->the_hole_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014070 for (int entry = 0, size = Capacity(); entry < size; entry++) {
14071 int entry_index = EntryToIndex(entry);
14072 int value_index = entry_index + 1;
14073 if (get(value_index) == value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014074 NoWriteBarrierSet(this, entry_index, the_hole_value);
14075 NoWriteBarrierSet(this, value_index, the_hole_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000014076 ElementRemoved();
14077 }
14078 }
14079 return;
14080}
14081
14082
ulan@chromium.org750145a2013-03-07 15:14:13 +000014083// StringsKey used for HashTable where key is array of internalized strings.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014084class StringsKey : public HashTableKey {
ager@chromium.org236ad962008-09-25 09:45:57 +000014085 public:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014086 explicit StringsKey(FixedArray* strings) : strings_(strings) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000014087
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014088 bool IsMatch(Object* strings) {
14089 FixedArray* o = FixedArray::cast(strings);
14090 int len = strings_->length();
ager@chromium.org236ad962008-09-25 09:45:57 +000014091 if (o->length() != len) return false;
14092 for (int i = 0; i < len; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014093 if (o->get(i) != strings_->get(i)) return false;
ager@chromium.org236ad962008-09-25 09:45:57 +000014094 }
14095 return true;
14096 }
14097
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014098 uint32_t Hash() { return HashForObject(strings_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000014099
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014100 uint32_t HashForObject(Object* obj) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014101 FixedArray* strings = FixedArray::cast(obj);
14102 int len = strings->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014103 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000014104 for (int i = 0; i < len; i++) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014105 hash ^= String::cast(strings->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000014106 }
14107 return hash;
14108 }
14109
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014110 Object* AsObject(Heap* heap) { return strings_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000014111
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014112 private:
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014113 FixedArray* strings_;
ager@chromium.org236ad962008-09-25 09:45:57 +000014114};
14115
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014116
ager@chromium.org236ad962008-09-25 09:45:57 +000014117Object* MapCache::Lookup(FixedArray* array) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014118 StringsKey key(array);
ager@chromium.org236ad962008-09-25 09:45:57 +000014119 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014120 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014121 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000014122}
14123
14124
lrn@chromium.org303ada72010-10-27 09:33:13 +000014125MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000014126 StringsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014127 Object* obj;
14128 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
14129 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14130 }
ager@chromium.org236ad962008-09-25 09:45:57 +000014131
14132 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014133 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000014134 cache->set(EntryToIndex(entry), array);
14135 cache->set(EntryToIndex(entry) + 1, value);
14136 cache->ElementAdded();
14137 return cache;
14138}
14139
14140
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014141template<typename Shape, typename Key>
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014142MaybeObject* Dictionary<Shape, Key>::Allocate(Heap* heap,
14143 int at_least_space_for) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000014144 Object* obj;
14145 { MaybeObject* maybe_obj =
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014146 HashTable<Shape, Key>::Allocate(heap, at_least_space_for);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014147 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014148 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000014149 // Initialize the next enumeration index.
14150 Dictionary<Shape, Key>::cast(obj)->
14151 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014152 return obj;
14153}
14154
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014155
ulan@chromium.org750145a2013-03-07 15:14:13 +000014156void NameDictionary::DoGenerateNewEnumerationIndices(
14157 Handle<NameDictionary> dictionary) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014158 CALL_HEAP_FUNCTION_VOID(dictionary->GetIsolate(),
14159 dictionary->GenerateNewEnumerationIndices());
14160}
14161
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014162template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000014163MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014164 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014165 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014166
14167 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014168 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014169 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014170 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014172 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014173 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014174 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014175 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014176
14177 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014178 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014179 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14180 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014181 FixedArray* enumeration_order = FixedArray::cast(obj);
14182
14183 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014184 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014185 int pos = 0;
14186 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014187 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000014188 int index = DetailsAt(i).dictionary_index();
14189 enumeration_order->set(pos++, Smi::FromInt(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014190 }
14191 }
14192
14193 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000014194 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014195
14196 // Overwrite the enumeration_order with the enumeration indices.
14197 for (int i = 0; i < length; i++) {
14198 int index = Smi::cast(iteration_order->get(i))->value();
14199 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014200 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014201 }
14202
14203 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014204 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014205 pos = 0;
14206 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014207 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014208 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
14209 PropertyDetails details = DetailsAt(i);
danno@chromium.orgf005df62013-04-30 16:36:45 +000014210 PropertyDetails new_details = PropertyDetails(
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014211 details.attributes(), details.type(), enum_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014212 DetailsAtPut(i, new_details);
14213 }
14214 }
14215
14216 // Set the next enumeration index.
14217 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
14218 return this;
14219}
14220
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014221template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000014222MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000014223 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014224 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014225 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
14226 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014227 Object* result;
14228 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
14229 if (!maybe_result->ToObject(&result)) return maybe_result;
14230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014231 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014232 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014233}
14234
14235
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014236template<typename Shape, typename Key>
14237Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000014238 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014239 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014240 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000014241 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000014242 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014243 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000014244 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014245 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014246 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014247 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014248}
14249
14250
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014251template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000014252MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
14253 return HashTable<Shape, Key>::Shrink(key);
14254}
14255
14256
14257template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000014258MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014259 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014260
14261 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014262 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014263 ValueAtPut(entry, value);
14264 return this;
14265 }
14266
14267 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014268 Object* obj;
14269 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
14270 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14271 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014272
lrn@chromium.org303ada72010-10-27 09:33:13 +000014273 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014274 { MaybeObject* maybe_k = Shape::AsObject(this->GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014275 if (!maybe_k->ToObject(&k)) return maybe_k;
14276 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014277 PropertyDetails details = PropertyDetails(NONE, NORMAL, 0);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014278
14279 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
14280 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014281}
14282
14283
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014284template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000014285MaybeObject* Dictionary<Shape, Key>::Add(Key key,
14286 Object* value,
14287 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014288 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014289 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014290 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014291 Object* obj;
14292 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
14293 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14294 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014295
14296 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
14297 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014298}
14299
14300
14301// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014302template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000014303MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
14304 Object* value,
14305 PropertyDetails details,
14306 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014307 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000014308 Object* k;
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014309 { MaybeObject* maybe_k = Shape::AsObject(this->GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014310 if (!maybe_k->ToObject(&k)) return maybe_k;
14311 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014312
14313 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014314 // Insert element at empty or deleted entry
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014315 if (!details.IsDeleted() &&
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +000014316 details.dictionary_index() == 0 &&
14317 Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014318 // Assign an enumeration index to the property and update
14319 // SetNextEnumerationIndex.
14320 int index = NextEnumerationIndex();
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014321 details = PropertyDetails(details.attributes(), details.type(), index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014322 SetNextEnumerationIndex(index + 1);
14323 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014324 SetEntry(entry, k, value, details);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014325 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() ||
14326 Dictionary<Shape, Key>::KeyAt(entry)->IsName()));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014327 HashTable<Shape, Key>::ElementAdded();
14328 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014329}
14330
14331
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014332void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014333 // If the dictionary requires slow elements an element has already
14334 // been added at a high index.
14335 if (requires_slow_elements()) return;
14336 // Check if this index is high enough that we should require slow
14337 // elements.
14338 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000014339 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014340 return;
14341 }
14342 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000014343 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014344 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014345 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000014346 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014347 }
14348}
14349
14350
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014351MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
14352 Object* value,
14353 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014354 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000014355 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014356 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014357}
14358
14359
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014360MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
14361 Object* value) {
14362 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014363 return Add(key, value, PropertyDetails(NONE, NORMAL, 0));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014364}
14365
14366
14367MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014368 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014369 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014370}
14371
14372
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014373MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
14374 Object* value) {
14375 return AtPut(key, value);
14376}
14377
14378
14379Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
14380 Handle<SeededNumberDictionary> dictionary,
14381 uint32_t index,
14382 Handle<Object> value,
14383 PropertyDetails details) {
14384 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
14385 dictionary->Set(index, *value, details),
14386 SeededNumberDictionary);
14387}
14388
14389
14390Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
14391 Handle<UnseededNumberDictionary> dictionary,
14392 uint32_t index,
14393 Handle<Object> value) {
14394 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
14395 dictionary->Set(index, *value),
14396 UnseededNumberDictionary);
14397}
14398
14399
14400MaybeObject* SeededNumberDictionary::Set(uint32_t key,
14401 Object* value,
14402 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014403 int entry = FindEntry(key);
14404 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014405 // Preserve enumeration index.
14406 details = PropertyDetails(details.attributes(),
14407 details.type(),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014408 DetailsAt(entry).dictionary_index());
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014409 MaybeObject* maybe_object_key =
14410 SeededNumberDictionaryShape::AsObject(GetHeap(), key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000014411 Object* object_key;
14412 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000014413 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014414 return this;
14415}
14416
14417
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014418MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
14419 Object* value) {
14420 int entry = FindEntry(key);
14421 if (entry == kNotFound) return AddNumberEntry(key, value);
ulan@chromium.org6e196bf2013-03-13 09:38:22 +000014422 MaybeObject* maybe_object_key =
14423 UnseededNumberDictionaryShape::AsObject(GetHeap(), key);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000014424 Object* object_key;
14425 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
14426 SetEntry(entry, object_key, value);
14427 return this;
14428}
14429
14430
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000014431
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014432template<typename Shape, typename Key>
14433int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
14434 PropertyAttributes filter) {
14435 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014436 int result = 0;
14437 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014438 Object* k = HashTable<Shape, Key>::KeyAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014439 if (HashTable<Shape, Key>::IsKey(k) &&
14440 ((filter & SYMBOLIC) == 0 || !k->IsSymbol())) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014441 PropertyDetails details = DetailsAt(i);
14442 if (details.IsDeleted()) continue;
14443 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014444 if ((attr & filter) == 0) result++;
14445 }
14446 }
14447 return result;
14448}
14449
14450
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014451template<typename Shape, typename Key>
14452int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014453 return NumberOfElementsFilterAttributes(
14454 static_cast<PropertyAttributes>(DONT_ENUM));
14455}
14456
14457
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014458template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014459void Dictionary<Shape, Key>::CopyKeysTo(
14460 FixedArray* storage,
14461 PropertyAttributes filter,
14462 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014463 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014464 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014465 int index = 0;
14466 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014467 Object* k = HashTable<Shape, Key>::KeyAt(i);
14468 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014469 PropertyDetails details = DetailsAt(i);
14470 if (details.IsDeleted()) continue;
14471 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014472 if ((attr & filter) == 0) storage->set(index++, k);
14473 }
14474 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014475 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
14476 storage->SortPairs(storage, index);
14477 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014478 ASSERT(storage->length() >= index);
14479}
14480
14481
ulan@chromium.org750145a2013-03-07 15:14:13 +000014482FixedArray* NameDictionary::CopyEnumKeysTo(FixedArray* storage) {
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014483 int length = storage->length();
14484 ASSERT(length >= NumberOfEnumElements());
14485 Heap* heap = GetHeap();
14486 Object* undefined_value = heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014487 int capacity = Capacity();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014488 int properties = 0;
14489
14490 // Fill in the enumeration array by assigning enumerable keys at their
14491 // enumeration index. This will leave holes in the array if there are keys
14492 // that are deleted or not enumerable.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014493 for (int i = 0; i < capacity; i++) {
14494 Object* k = KeyAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014495 if (IsKey(k) && !k->IsSymbol()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014496 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014497 if (details.IsDeleted() || details.IsDontEnum()) continue;
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014498 properties++;
14499 storage->set(details.dictionary_index() - 1, k);
14500 if (properties == length) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014501 }
14502 }
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014503
14504 // There are holes in the enumeration array if less properties were assigned
14505 // than the length of the array. If so, crunch all the existing properties
14506 // together by shifting them to the left (maintaining the enumeration order),
14507 // and trimming of the right side of the array.
14508 if (properties < length) {
14509 if (properties == 0) return heap->empty_fixed_array();
14510 properties = 0;
14511 for (int i = 0; i < length; ++i) {
14512 Object* value = storage->get(i);
14513 if (value != undefined_value) {
14514 storage->set(properties, value);
14515 ++properties;
14516 }
14517 }
14518 RightTrimFixedArray<FROM_MUTATOR>(heap, storage, length - properties);
14519 }
14520 return storage;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014521}
14522
14523
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014524template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014525void Dictionary<Shape, Key>::CopyKeysTo(
14526 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000014527 int index,
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014528 PropertyAttributes filter,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014529 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014530 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
14531 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014532 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014533 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014534 Object* k = HashTable<Shape, Key>::KeyAt(i);
14535 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000014536 PropertyDetails details = DetailsAt(i);
14537 if (details.IsDeleted()) continue;
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000014538 PropertyAttributes attr = details.attributes();
14539 if ((attr & filter) == 0) storage->set(index++, k);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014540 }
14541 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000014542 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
14543 storage->SortPairs(storage, index);
14544 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014545 ASSERT(storage->length() >= index);
14546}
14547
14548
14549// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014550template<typename Shape, typename Key>
14551Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
14552 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014553 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014554 Object* k = HashTable<Shape, Key>::KeyAt(i);
14555 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000014556 Object* e = ValueAt(i);
14557 if (e->IsJSGlobalPropertyCell()) {
14558 e = JSGlobalPropertyCell::cast(e)->value();
14559 }
14560 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014561 }
14562 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014563 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014564 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014565}
14566
14567
ulan@chromium.org750145a2013-03-07 15:14:13 +000014568MaybeObject* NameDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000014569 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014570 // Make sure we preserve dictionary representation if there are too many
14571 // descriptors.
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014572 int number_of_elements = NumberOfElements();
14573 if (number_of_elements > DescriptorArray::kMaxNumberOfDescriptors) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014574
jkummerow@chromium.org78502a92012-09-06 13:50:42 +000014575 if (number_of_elements != NextEnumerationIndex()) {
14576 MaybeObject* maybe_result = GenerateNewEnumerationIndices();
14577 if (maybe_result->IsFailure()) return maybe_result;
14578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014579
14580 int instance_descriptor_length = 0;
14581 int number_of_fields = 0;
14582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014583 Heap* heap = GetHeap();
14584
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014585 // Compute the length of the instance descriptor.
14586 int capacity = Capacity();
14587 for (int i = 0; i < capacity; i++) {
14588 Object* k = KeyAt(i);
14589 if (IsKey(k)) {
14590 Object* value = ValueAt(i);
14591 PropertyType type = DetailsAt(i).type();
14592 ASSERT(type != FIELD);
14593 instance_descriptor_length++;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000014594 if (type == NORMAL && !value->IsJSFunction()) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000014595 number_of_fields += 1;
14596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014597 }
14598 }
14599
yangguo@chromium.org304cc332012-07-24 07:59:48 +000014600 int inobject_props = obj->map()->inobject_properties();
14601
14602 // Allocate new map.
14603 Map* new_map;
14604 MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
14605 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
erik.corry@gmail.com88767242012-08-08 14:43:45 +000014606 new_map->set_dictionary_map(false);
yangguo@chromium.org304cc332012-07-24 07:59:48 +000014607
14608 if (instance_descriptor_length == 0) {
14609 ASSERT_LE(unused_property_fields, inobject_props);
14610 // Transform the object.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +000014611 new_map->set_unused_property_fields(inobject_props);
yangguo@chromium.org304cc332012-07-24 07:59:48 +000014612 obj->set_map(new_map);
14613 obj->set_properties(heap->empty_fixed_array());
14614 // Check that it really works.
14615 ASSERT(obj->HasFastProperties());
14616 return obj;
14617 }
14618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014619 // Allocate the instance descriptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014620 DescriptorArray* descriptors;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014621 MaybeObject* maybe_descriptors =
verwaest@chromium.orgde64f722012-08-16 15:44:54 +000014622 DescriptorArray::Allocate(instance_descriptor_length);
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014623 if (!maybe_descriptors->To(&descriptors)) {
14624 return maybe_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +000014625 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014626
ulan@chromium.org56c14af2012-09-20 12:51:09 +000014627 DescriptorArray::WhitenessWitness witness(descriptors);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014628
ager@chromium.org32912102009-01-16 10:38:43 +000014629 int number_of_allocated_fields =
14630 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000014631 if (number_of_allocated_fields < 0) {
14632 // There is enough inobject space for all fields (including unused).
14633 number_of_allocated_fields = 0;
14634 unused_property_fields = inobject_props - number_of_fields;
14635 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014636
14637 // Allocate the fixed array for the fields.
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014638 FixedArray* fields;
14639 MaybeObject* maybe_fields =
14640 heap->AllocateFixedArray(number_of_allocated_fields);
14641 if (!maybe_fields->To(&fields)) return maybe_fields;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014642
14643 // Fill in the instance descriptor and the fields.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014644 int current_offset = 0;
14645 for (int i = 0; i < capacity; i++) {
14646 Object* k = KeyAt(i);
14647 if (IsKey(k)) {
14648 Object* value = ValueAt(i);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014649 Name* key;
14650 if (k->IsSymbol()) {
14651 key = Symbol::cast(k);
14652 } else {
14653 // Ensure the key is a unique name before writing into the
14654 // instance descriptor.
14655 MaybeObject* maybe_key = heap->InternalizeString(String::cast(k));
14656 if (!maybe_key->To(&key)) return maybe_key;
14657 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014658
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014659 PropertyDetails details = DetailsAt(i);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014660 int enumeration_index = details.dictionary_index();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014661 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000014662
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +000014663 if (value->IsJSFunction()) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014664 ConstantFunctionDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014665 JSFunction::cast(value),
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014666 details.attributes());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014667 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014668 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000014669 if (current_offset < inobject_props) {
14670 obj->InObjectPropertyAtPut(current_offset,
14671 value,
14672 UPDATE_WRITE_BARRIER);
14673 } else {
14674 int offset = current_offset - inobject_props;
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014675 fields->set(offset, value);
ager@chromium.org32912102009-01-16 10:38:43 +000014676 }
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014677 FieldDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014678 current_offset++,
14679 details.attributes(),
danno@chromium.orgf005df62013-04-30 16:36:45 +000014680 // TODO(verwaest): value->OptimalRepresentation();
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014681 Representation::Tagged());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014682 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014683 } else if (type == CALLBACKS) {
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014684 CallbacksDescriptor d(key,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014685 value,
ulan@chromium.org57ff8812013-05-10 08:16:55 +000014686 details.attributes());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014687 descriptors->Set(enumeration_index - 1, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014688 } else {
14689 UNREACHABLE();
14690 }
14691 }
14692 }
14693 ASSERT(current_offset == number_of_fields);
14694
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000014695 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014696
rossberg@chromium.org89e18f52012-10-22 13:09:53 +000014697 new_map->InitializeDescriptors(descriptors);
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000014698 new_map->set_unused_property_fields(unused_property_fields);
14699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014700 // Transform the object.
rossberg@chromium.org657d53b2012-07-12 11:06:03 +000014701 obj->set_map(new_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000014702
verwaest@chromium.org753aee42012-07-17 16:15:42 +000014703 obj->set_properties(fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014704 ASSERT(obj->IsJSObject());
14705
ager@chromium.org32912102009-01-16 10:38:43 +000014706 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014707 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000014708
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014709 return obj;
14710}
14711
14712
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014713bool ObjectHashSet::Contains(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014714 ASSERT(IsKey(key));
14715
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014716 // 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 +000014717 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
14718 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
14719 }
14720 return (FindEntry(key) != kNotFound);
14721}
14722
14723
14724MaybeObject* ObjectHashSet::Add(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014725 ASSERT(IsKey(key));
14726
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014727 // Make sure the key object has an identity hash code.
14728 int hash;
14729 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
14730 if (maybe_hash->IsFailure()) return maybe_hash;
14731 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
14732 }
14733 int entry = FindEntry(key);
14734
14735 // Check whether key is already present.
14736 if (entry != kNotFound) return this;
14737
14738 // Check whether the hash set should be extended and add entry.
14739 Object* obj;
14740 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
14741 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14742 }
14743 ObjectHashSet* table = ObjectHashSet::cast(obj);
14744 entry = table->FindInsertionEntry(hash);
14745 table->set(EntryToIndex(entry), key);
14746 table->ElementAdded();
14747 return table;
14748}
14749
14750
14751MaybeObject* ObjectHashSet::Remove(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014752 ASSERT(IsKey(key));
14753
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014754 // If the object does not have an identity hash, it was never used as a key.
14755 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
14756 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
14757 }
14758 int entry = FindEntry(key);
14759
14760 // Check whether key is actually present.
14761 if (entry == kNotFound) return this;
14762
14763 // Remove entry and try to shrink this hash set.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014764 set_the_hole(EntryToIndex(entry));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014765 ElementRemoved();
14766 return Shrink(key);
14767}
14768
14769
14770Object* ObjectHashTable::Lookup(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014771 ASSERT(IsKey(key));
14772
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014773 // If the object does not have an identity hash, it was never used as a key.
14774 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
14775 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000014776 return GetHeap()->the_hole_value();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014777 }
14778 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014779 int entry = FindEntry(key);
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000014780 if (entry == kNotFound) return GetHeap()->the_hole_value();
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014781 return get(EntryToIndex(entry) + 1);
14782}
14783
14784
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014785MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014786 ASSERT(IsKey(key));
14787
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014788 // Make sure the key object has an identity hash code.
14789 int hash;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014790 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014791 if (maybe_hash->IsFailure()) return maybe_hash;
14792 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
14793 }
14794 int entry = FindEntry(key);
14795
14796 // Check whether to perform removal operation.
jkummerow@chromium.org7a6fc812012-06-27 11:12:38 +000014797 if (value->IsTheHole()) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014798 if (entry == kNotFound) return this;
14799 RemoveEntry(entry);
14800 return Shrink(key);
14801 }
14802
14803 // Key is already in table, just overwrite value.
14804 if (entry != kNotFound) {
14805 set(EntryToIndex(entry) + 1, value);
14806 return this;
14807 }
14808
14809 // Check whether the hash table should be extended.
14810 Object* obj;
14811 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
14812 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
14813 }
14814 ObjectHashTable* table = ObjectHashTable::cast(obj);
14815 table->AddEntry(table->FindInsertionEntry(hash), key, value);
14816 return table;
14817}
14818
14819
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000014820void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014821 set(EntryToIndex(entry), key);
14822 set(EntryToIndex(entry) + 1, value);
14823 ElementAdded();
14824}
14825
14826
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000014827void ObjectHashTable::RemoveEntry(int entry) {
14828 set_the_hole(EntryToIndex(entry));
14829 set_the_hole(EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000014830 ElementRemoved();
14831}
14832
14833
ulan@chromium.org750145a2013-03-07 15:14:13 +000014834DeclaredAccessorDescriptorIterator::DeclaredAccessorDescriptorIterator(
14835 DeclaredAccessorDescriptor* descriptor)
14836 : array_(descriptor->serialized_data()->GetDataStartAddress()),
14837 length_(descriptor->serialized_data()->length()),
14838 offset_(0) {
14839}
14840
14841
14842const DeclaredAccessorDescriptorData*
14843 DeclaredAccessorDescriptorIterator::Next() {
14844 ASSERT(offset_ < length_);
14845 uint8_t* ptr = &array_[offset_];
14846 ASSERT(reinterpret_cast<uintptr_t>(ptr) % sizeof(uintptr_t) == 0);
14847 const DeclaredAccessorDescriptorData* data =
14848 reinterpret_cast<const DeclaredAccessorDescriptorData*>(ptr);
14849 offset_ += sizeof(*data);
14850 ASSERT(offset_ <= length_);
14851 return data;
14852}
14853
14854
14855Handle<DeclaredAccessorDescriptor> DeclaredAccessorDescriptor::Create(
14856 Isolate* isolate,
14857 const DeclaredAccessorDescriptorData& descriptor,
14858 Handle<DeclaredAccessorDescriptor> previous) {
14859 int previous_length =
14860 previous.is_null() ? 0 : previous->serialized_data()->length();
14861 int length = sizeof(descriptor) + previous_length;
14862 Handle<ByteArray> serialized_descriptor =
14863 isolate->factory()->NewByteArray(length);
14864 Handle<DeclaredAccessorDescriptor> value =
14865 isolate->factory()->NewDeclaredAccessorDescriptor();
14866 value->set_serialized_data(*serialized_descriptor);
14867 // Copy in the data.
14868 {
14869 AssertNoAllocation no_allocation;
14870 uint8_t* array = serialized_descriptor->GetDataStartAddress();
14871 if (previous_length != 0) {
14872 uint8_t* previous_array =
14873 previous->serialized_data()->GetDataStartAddress();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000014874 OS::MemCopy(array, previous_array, previous_length);
ulan@chromium.org750145a2013-03-07 15:14:13 +000014875 array += previous_length;
14876 }
14877 ASSERT(reinterpret_cast<uintptr_t>(array) % sizeof(uintptr_t) == 0);
14878 DeclaredAccessorDescriptorData* data =
14879 reinterpret_cast<DeclaredAccessorDescriptorData*>(array);
14880 *data = descriptor;
14881 }
14882 return value;
14883}
14884
14885
ager@chromium.org65dad4b2009-04-23 08:48:43 +000014886#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014887// Check if there is a break point at this code position.
14888bool DebugInfo::HasBreakPoint(int code_position) {
14889 // Get the break point info object for this code position.
14890 Object* break_point_info = GetBreakPointInfo(code_position);
14891
14892 // If there is no break point info object or no break points in the break
14893 // point info object there is no break point at this code position.
14894 if (break_point_info->IsUndefined()) return false;
14895 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
14896}
14897
14898
14899// Get the break point info object for this code position.
14900Object* DebugInfo::GetBreakPointInfo(int code_position) {
14901 // Find the index of the break point info object for this code position.
14902 int index = GetBreakPointInfoIndex(code_position);
14903
14904 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014905 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014906 return BreakPointInfo::cast(break_points()->get(index));
14907}
14908
14909
14910// Clear a break point at the specified code position.
14911void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
14912 int code_position,
14913 Handle<Object> break_point_object) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014914 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
14915 Isolate::Current());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014916 if (break_point_info->IsUndefined()) return;
14917 BreakPointInfo::ClearBreakPoint(
14918 Handle<BreakPointInfo>::cast(break_point_info),
14919 break_point_object);
14920}
14921
14922
14923void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
14924 int code_position,
14925 int source_position,
14926 int statement_position,
14927 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014928 Isolate* isolate = Isolate::Current();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +000014929 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position),
14930 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014931 if (!break_point_info->IsUndefined()) {
14932 BreakPointInfo::SetBreakPoint(
14933 Handle<BreakPointInfo>::cast(break_point_info),
14934 break_point_object);
14935 return;
14936 }
14937
14938 // Adding a new break point for a code position which did not have any
14939 // break points before. Try to find a free slot.
14940 int index = kNoBreakPointInfo;
14941 for (int i = 0; i < debug_info->break_points()->length(); i++) {
14942 if (debug_info->break_points()->get(i)->IsUndefined()) {
14943 index = i;
14944 break;
14945 }
14946 }
14947 if (index == kNoBreakPointInfo) {
14948 // No free slot - extend break point info array.
14949 Handle<FixedArray> old_break_points =
14950 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014951 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014952 isolate->factory()->NewFixedArray(
14953 old_break_points->length() +
14954 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000014955
14956 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014957 for (int i = 0; i < old_break_points->length(); i++) {
14958 new_break_points->set(i, old_break_points->get(i));
14959 }
14960 index = old_break_points->length();
14961 }
14962 ASSERT(index != kNoBreakPointInfo);
14963
14964 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014965 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
14966 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014967 new_break_point_info->set_code_position(Smi::FromInt(code_position));
14968 new_break_point_info->set_source_position(Smi::FromInt(source_position));
14969 new_break_point_info->
14970 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000014971 new_break_point_info->set_break_point_objects(
14972 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014973 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
14974 debug_info->break_points()->set(index, *new_break_point_info);
14975}
14976
14977
14978// Get the break point objects for a code position.
14979Object* DebugInfo::GetBreakPointObjects(int code_position) {
14980 Object* break_point_info = GetBreakPointInfo(code_position);
14981 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000014982 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000014983 }
14984 return BreakPointInfo::cast(break_point_info)->break_point_objects();
14985}
14986
14987
14988// Get the total number of break points.
14989int DebugInfo::GetBreakPointCount() {
14990 if (break_points()->IsUndefined()) return 0;
14991 int count = 0;
14992 for (int i = 0; i < break_points()->length(); i++) {
14993 if (!break_points()->get(i)->IsUndefined()) {
14994 BreakPointInfo* break_point_info =
14995 BreakPointInfo::cast(break_points()->get(i));
14996 count += break_point_info->GetBreakPointCount();
14997 }
14998 }
14999 return count;
15000}
15001
15002
15003Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
15004 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000015005 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015006 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015007 for (int i = 0; i < debug_info->break_points()->length(); i++) {
15008 if (!debug_info->break_points()->get(i)->IsUndefined()) {
15009 Handle<BreakPointInfo> break_point_info =
15010 Handle<BreakPointInfo>(BreakPointInfo::cast(
15011 debug_info->break_points()->get(i)));
15012 if (BreakPointInfo::HasBreakPointObject(break_point_info,
15013 break_point_object)) {
15014 return *break_point_info;
15015 }
15016 }
15017 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015018 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015019}
15020
15021
15022// Find the index of the break point info object for the specified code
15023// position.
15024int DebugInfo::GetBreakPointInfoIndex(int code_position) {
15025 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
15026 for (int i = 0; i < break_points()->length(); i++) {
15027 if (!break_points()->get(i)->IsUndefined()) {
15028 BreakPointInfo* break_point_info =
15029 BreakPointInfo::cast(break_points()->get(i));
15030 if (break_point_info->code_position()->value() == code_position) {
15031 return i;
15032 }
15033 }
15034 }
15035 return kNoBreakPointInfo;
15036}
15037
15038
15039// Remove the specified break point object.
15040void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
15041 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015042 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015043 // If there are no break points just ignore.
15044 if (break_point_info->break_point_objects()->IsUndefined()) return;
15045 // If there is a single break point clear it if it is the same.
15046 if (!break_point_info->break_point_objects()->IsFixedArray()) {
15047 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015048 break_point_info->set_break_point_objects(
15049 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015050 }
15051 return;
15052 }
15053 // If there are multiple break points shrink the array
15054 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
15055 Handle<FixedArray> old_array =
15056 Handle<FixedArray>(
15057 FixedArray::cast(break_point_info->break_point_objects()));
15058 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015059 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015060 int found_count = 0;
15061 for (int i = 0; i < old_array->length(); i++) {
15062 if (old_array->get(i) == *break_point_object) {
15063 ASSERT(found_count == 0);
15064 found_count++;
15065 } else {
15066 new_array->set(i - found_count, old_array->get(i));
15067 }
15068 }
15069 // If the break point was found in the list change it.
15070 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
15071}
15072
15073
15074// Add the specified break point object.
15075void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
15076 Handle<Object> break_point_object) {
15077 // If there was no break point objects before just set it.
15078 if (break_point_info->break_point_objects()->IsUndefined()) {
15079 break_point_info->set_break_point_objects(*break_point_object);
15080 return;
15081 }
15082 // If the break point object is the same as before just ignore.
15083 if (break_point_info->break_point_objects() == *break_point_object) return;
15084 // If there was one break point object before replace with array.
15085 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015086 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015087 array->set(0, break_point_info->break_point_objects());
15088 array->set(1, *break_point_object);
15089 break_point_info->set_break_point_objects(*array);
15090 return;
15091 }
15092 // If there was more than one break point before extend array.
15093 Handle<FixedArray> old_array =
15094 Handle<FixedArray>(
15095 FixedArray::cast(break_point_info->break_point_objects()));
15096 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000015097 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015098 for (int i = 0; i < old_array->length(); i++) {
15099 // If the break point was there before just ignore.
15100 if (old_array->get(i) == *break_point_object) return;
15101 new_array->set(i, old_array->get(i));
15102 }
15103 // Add the new break point.
15104 new_array->set(old_array->length(), *break_point_object);
15105 break_point_info->set_break_point_objects(*new_array);
15106}
15107
15108
15109bool BreakPointInfo::HasBreakPointObject(
15110 Handle<BreakPointInfo> break_point_info,
15111 Handle<Object> break_point_object) {
15112 // No break point.
15113 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000015114 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015115 if (!break_point_info->break_point_objects()->IsFixedArray()) {
15116 return break_point_info->break_point_objects() == *break_point_object;
15117 }
15118 // Multiple break points.
15119 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
15120 for (int i = 0; i < array->length(); i++) {
15121 if (array->get(i) == *break_point_object) {
15122 return true;
15123 }
15124 }
15125 return false;
15126}
15127
15128
15129// Get the number of break points.
15130int BreakPointInfo::GetBreakPointCount() {
15131 // No break point.
15132 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000015133 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015134 if (!break_point_objects()->IsFixedArray()) return 1;
15135 // Multiple break points.
15136 return FixedArray::cast(break_point_objects())->length();
15137}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000015138#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015139
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000015140
jkummerow@chromium.org212d9642012-05-11 15:02:09 +000015141Object* JSDate::GetField(Object* object, Smi* index) {
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000015142 return JSDate::cast(object)->DoGetField(
15143 static_cast<FieldIndex>(index->value()));
15144}
15145
15146
15147Object* JSDate::DoGetField(FieldIndex index) {
15148 ASSERT(index != kDateValue);
15149
15150 DateCache* date_cache = GetIsolate()->date_cache();
15151
15152 if (index < kFirstUncachedField) {
15153 Object* stamp = cache_stamp();
15154 if (stamp != date_cache->stamp() && stamp->IsSmi()) {
15155 // Since the stamp is not NaN, the value is also not NaN.
15156 int64_t local_time_ms =
15157 date_cache->ToLocal(static_cast<int64_t>(value()->Number()));
15158 SetLocalFields(local_time_ms, date_cache);
15159 }
15160 switch (index) {
15161 case kYear: return year();
15162 case kMonth: return month();
15163 case kDay: return day();
15164 case kWeekday: return weekday();
15165 case kHour: return hour();
15166 case kMinute: return min();
15167 case kSecond: return sec();
15168 default: UNREACHABLE();
15169 }
15170 }
15171
15172 if (index >= kFirstUTCField) {
15173 return GetUTCField(index, value()->Number(), date_cache);
15174 }
15175
15176 double time = value()->Number();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000015177 if (std::isnan(time)) return GetIsolate()->heap()->nan_value();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000015178
15179 int64_t local_time_ms = date_cache->ToLocal(static_cast<int64_t>(time));
15180 int days = DateCache::DaysFromTime(local_time_ms);
15181
15182 if (index == kDays) return Smi::FromInt(days);
15183
15184 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
15185 if (index == kMillisecond) return Smi::FromInt(time_in_day_ms % 1000);
15186 ASSERT(index == kTimeInDay);
15187 return Smi::FromInt(time_in_day_ms);
15188}
15189
15190
15191Object* JSDate::GetUTCField(FieldIndex index,
15192 double value,
15193 DateCache* date_cache) {
15194 ASSERT(index >= kFirstUTCField);
15195
ulan@chromium.org77ca49a2013-04-22 09:43:56 +000015196 if (std::isnan(value)) return GetIsolate()->heap()->nan_value();
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +000015197
15198 int64_t time_ms = static_cast<int64_t>(value);
15199
15200 if (index == kTimezoneOffset) {
15201 return Smi::FromInt(date_cache->TimezoneOffset(time_ms));
15202 }
15203
15204 int days = DateCache::DaysFromTime(time_ms);
15205
15206 if (index == kWeekdayUTC) return Smi::FromInt(date_cache->Weekday(days));
15207
15208 if (index <= kDayUTC) {
15209 int year, month, day;
15210 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
15211 if (index == kYearUTC) return Smi::FromInt(year);
15212 if (index == kMonthUTC) return Smi::FromInt(month);
15213 ASSERT(index == kDayUTC);
15214 return Smi::FromInt(day);
15215 }
15216
15217 int time_in_day_ms = DateCache::TimeInDay(time_ms, days);
15218 switch (index) {
15219 case kHourUTC: return Smi::FromInt(time_in_day_ms / (60 * 60 * 1000));
15220 case kMinuteUTC: return Smi::FromInt((time_in_day_ms / (60 * 1000)) % 60);
15221 case kSecondUTC: return Smi::FromInt((time_in_day_ms / 1000) % 60);
15222 case kMillisecondUTC: return Smi::FromInt(time_in_day_ms % 1000);
15223 case kDaysUTC: return Smi::FromInt(days);
15224 case kTimeInDayUTC: return Smi::FromInt(time_in_day_ms);
15225 default: UNREACHABLE();
15226 }
15227
15228 UNREACHABLE();
15229 return NULL;
15230}
15231
15232
15233void JSDate::SetValue(Object* value, bool is_value_nan) {
15234 set_value(value);
15235 if (is_value_nan) {
15236 HeapNumber* nan = GetIsolate()->heap()->nan_value();
15237 set_cache_stamp(nan, SKIP_WRITE_BARRIER);
15238 set_year(nan, SKIP_WRITE_BARRIER);
15239 set_month(nan, SKIP_WRITE_BARRIER);
15240 set_day(nan, SKIP_WRITE_BARRIER);
15241 set_hour(nan, SKIP_WRITE_BARRIER);
15242 set_min(nan, SKIP_WRITE_BARRIER);
15243 set_sec(nan, SKIP_WRITE_BARRIER);
15244 set_weekday(nan, SKIP_WRITE_BARRIER);
15245 } else {
15246 set_cache_stamp(Smi::FromInt(DateCache::kInvalidStamp), SKIP_WRITE_BARRIER);
15247 }
15248}
15249
15250
15251void JSDate::SetLocalFields(int64_t local_time_ms, DateCache* date_cache) {
15252 int days = DateCache::DaysFromTime(local_time_ms);
15253 int time_in_day_ms = DateCache::TimeInDay(local_time_ms, days);
15254 int year, month, day;
15255 date_cache->YearMonthDayFromDays(days, &year, &month, &day);
15256 int weekday = date_cache->Weekday(days);
15257 int hour = time_in_day_ms / (60 * 60 * 1000);
15258 int min = (time_in_day_ms / (60 * 1000)) % 60;
15259 int sec = (time_in_day_ms / 1000) % 60;
15260 set_cache_stamp(date_cache->stamp());
15261 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER);
15262 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER);
15263 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER);
15264 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER);
15265 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER);
15266 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER);
15267 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER);
15268}
15269
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000015270} } // namespace v8::internal