blob: 5e472ba44a9551cdbe9f0c56ba7453333afadcea [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 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
30#include "api.h"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000031#include "arguments.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032#include "bootstrapper.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000033#include "codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000034#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "deoptimizer.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000036#include "elements.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "full-codegen.h"
39#include "hydrogen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000041#include "objects-visiting.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000042#include "objects-visiting-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "macro-assembler.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000044#include "mark-compact.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000045#include "safepoint-table.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000047#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000048#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049
mads.s.ager31e71382008-08-13 09:32:07 +000050#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000052#include "disassembler.h"
53#endif
54
kasperl@chromium.org71affb52009-05-26 05:44:31 +000055namespace v8 {
56namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000058void PrintElementsKind(FILE* out, ElementsKind kind) {
59 switch (kind) {
60 case FAST_SMI_ONLY_ELEMENTS:
61 PrintF(out, "FAST_SMI_ONLY_ELEMENTS");
62 break;
63 case FAST_ELEMENTS:
64 PrintF(out, "FAST_ELEMENTS");
65 break;
66 case FAST_DOUBLE_ELEMENTS:
67 PrintF(out, "FAST_DOUBLE_ELEMENTS");
68 break;
69 case DICTIONARY_ELEMENTS:
70 PrintF(out, "DICTIONARY_ELEMENTS");
71 break;
72 case NON_STRICT_ARGUMENTS_ELEMENTS:
73 PrintF(out, "NON_STRICT_ARGUMENTS_ELEMENTS");
74 break;
75 case EXTERNAL_BYTE_ELEMENTS:
76 PrintF(out, "EXTERNAL_BYTE_ELEMENTS");
77 break;
78 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
79 PrintF(out, "EXTERNAL_UNSIGNED_BYTE_ELEMENTS");
80 break;
81 case EXTERNAL_SHORT_ELEMENTS:
82 PrintF(out, "EXTERNAL_SHORT_ELEMENTS");
83 break;
84 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
85 PrintF(out, "EXTERNAL_UNSIGNED_SHORT_ELEMENTS");
86 break;
87 case EXTERNAL_INT_ELEMENTS:
88 PrintF(out, "EXTERNAL_INT_ELEMENTS");
89 break;
90 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
91 PrintF(out, "EXTERNAL_UNSIGNED_INT_ELEMENTS");
92 break;
93 case EXTERNAL_FLOAT_ELEMENTS:
94 PrintF(out, "EXTERNAL_FLOAT_ELEMENTS");
95 break;
96 case EXTERNAL_DOUBLE_ELEMENTS:
97 PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
98 break;
99 case EXTERNAL_PIXEL_ELEMENTS:
100 PrintF(out, "EXTERNAL_DOUBLE_ELEMENTS");
101 break;
102 }
103}
104
105
lrn@chromium.org303ada72010-10-27 09:33:13 +0000106MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
107 Object* value) {
108 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 { MaybeObject* maybe_result =
110 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 if (!maybe_result->ToObject(&result)) return maybe_result;
112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113 JSValue::cast(result)->set_value(value);
114 return result;
115}
116
117
lrn@chromium.org303ada72010-10-27 09:33:13 +0000118MaybeObject* Object::ToObject(Context* global_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119 if (IsNumber()) {
120 return CreateJSValue(global_context->number_function(), this);
121 } else if (IsBoolean()) {
122 return CreateJSValue(global_context->boolean_function(), this);
123 } else if (IsString()) {
124 return CreateJSValue(global_context->string_function(), this);
125 }
126 ASSERT(IsJSObject());
127 return this;
128}
129
130
lrn@chromium.org303ada72010-10-27 09:33:13 +0000131MaybeObject* Object::ToObject() {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000132 if (IsJSReceiver()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000133 return this;
134 } else if (IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Isolate* isolate = Isolate::Current();
136 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000137 return CreateJSValue(global_context->number_function(), this);
138 } else if (IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
140 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 return CreateJSValue(global_context->boolean_function(), this);
142 } else if (IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
144 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145 return CreateJSValue(global_context->string_function(), this);
146 }
147
148 // Throw a type error.
149 return Failure::InternalError();
150}
151
152
153Object* Object::ToBoolean() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000154 if (IsTrue()) return this;
155 if (IsFalse()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 if (IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000159 HeapObject* heap_object = HeapObject::cast(this);
160 if (heap_object->IsUndefined() || heap_object->IsNull()) {
161 return heap_object->GetHeap()->false_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000163 // Undetectable object is false
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000164 if (heap_object->IsUndetectableObject()) {
165 return heap_object->GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000167 if (heap_object->IsString()) {
168 return heap_object->GetHeap()->ToBoolean(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 String::cast(this)->length() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000170 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000171 if (heap_object->IsHeapNumber()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172 return HeapNumber::cast(this)->HeapNumberToBoolean();
173 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000174 return heap_object->GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000175}
176
177
178void Object::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179 Object* holder = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000180 if (IsJSReceiver()) {
181 holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000182 } else {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000183 Context* global_context = Isolate::Current()->context()->global_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000184 if (IsNumber()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000185 holder = global_context->number_function()->instance_prototype();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000186 } else if (IsString()) {
187 holder = global_context->string_function()->instance_prototype();
188 } else if (IsBoolean()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000189 holder = global_context->boolean_function()->instance_prototype();
190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000191 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000192 ASSERT(holder != NULL); // Cannot handle null or undefined.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000193 JSReceiver::cast(holder)->Lookup(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000194}
195
196
lrn@chromium.org303ada72010-10-27 09:33:13 +0000197MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
198 String* name,
199 PropertyAttributes* attributes) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000200 LookupResult result(name->GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000202 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000203 ASSERT(*attributes <= ABSENT);
204 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000205}
206
207
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000208MaybeObject* JSObject::GetPropertyWithCallback(Object* receiver,
209 Object* structure,
210 String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000211 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000213 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000215 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000217 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000218 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000219 MaybeObject* value = (callback->getter)(receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000221 return value;
222 }
223
224 // api style callbacks.
225 if (structure->IsAccessorInfo()) {
226 AccessorInfo* data = AccessorInfo::cast(structure);
227 Object* fun_obj = data->getter();
228 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000229 HandleScope scope(isolate);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000230 JSObject* self = JSObject::cast(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000231 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000233 CustomArguments args(isolate, data->data(), self, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000234 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000235 v8::Handle<v8::Value> result;
236 {
237 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000238 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239 result = call_fun(v8::Utils::ToLocal(key), info);
240 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000241 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
242 if (result.IsEmpty()) {
243 return isolate->heap()->undefined_value();
244 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000245 return *v8::Utils::OpenHandle(*result);
246 }
247
248 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000249 if (structure->IsAccessorPair()) {
250 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000251 if (getter->IsSpecFunction()) {
252 // TODO(rossberg): nicer would be to cast to some JSCallable here...
253 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254 }
255 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000256 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257 }
258
259 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000260 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261}
262
263
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000264MaybeObject* JSProxy::GetPropertyWithHandler(Object* receiver_raw,
265 String* name_raw) {
266 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000267 HandleScope scope(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000268 Handle<Object> receiver(receiver_raw);
269 Handle<Object> name(name_raw);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000270
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000271 Handle<Object> args[] = { receiver, name };
272 Handle<Object> result = CallTrap(
273 "get", isolate->derived_get_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000274 if (isolate->has_pending_exception()) return Failure::Exception();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000275
276 return *result;
277}
278
279
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000280Handle<Object> Object::GetElement(Handle<Object> object, uint32_t index) {
281 Isolate* isolate = object->IsHeapObject()
282 ? Handle<HeapObject>::cast(object)->GetIsolate()
283 : Isolate::Current();
284 CALL_HEAP_FUNCTION(isolate, object->GetElement(index), Object);
285}
286
287
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000288MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
289 uint32_t index) {
290 String* name;
291 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
292 if (!maybe->To<String>(&name)) return maybe;
293 return GetPropertyWithHandler(receiver, name);
294}
295
296
297MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
298 Object* value,
299 StrictModeFlag strict_mode) {
300 String* name;
301 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
302 if (!maybe->To<String>(&name)) return maybe;
303 return SetPropertyWithHandler(name, value, NONE, strict_mode);
304}
305
306
307bool JSProxy::HasElementWithHandler(uint32_t index) {
308 String* name;
309 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
310 if (!maybe->To<String>(&name)) return maybe;
311 return HasPropertyWithHandler(name);
312}
313
314
lrn@chromium.org303ada72010-10-27 09:33:13 +0000315MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000316 JSReceiver* getter) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000317 HandleScope scope;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000318 Handle<JSReceiver> fun(getter);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000319 Handle<Object> self(receiver);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000320#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 Debug* debug = fun->GetHeap()->isolate()->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000322 // Handle stepping into a getter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000323 // TODO(rossberg): should this apply to getters that are function proxies?
324 if (debug->StepInActive() && fun->IsJSFunction()) {
325 debug->HandleStepIn(
326 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000327 }
328#endif
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000329
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000330 bool has_pending_exception;
331 Handle<Object> result =
332 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
333 // Check for pending exception and return the result.
334 if (has_pending_exception) return Failure::Exception();
335 return *result;
336}
337
338
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339// Only deal with CALLBACKS and INTERCEPTOR
lrn@chromium.org303ada72010-10-27 09:33:13 +0000340MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000341 Object* receiver,
342 LookupResult* result,
343 String* name,
344 PropertyAttributes* attributes) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000345 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346 switch (result->type()) {
347 case CALLBACKS: {
348 // Only allow API accessors.
349 Object* obj = result->GetCallbackObject();
350 if (obj->IsAccessorInfo()) {
351 AccessorInfo* info = AccessorInfo::cast(obj);
352 if (info->all_can_read()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000353 *attributes = result->GetAttributes();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000354 return result->holder()->GetPropertyWithCallback(
355 receiver, result->GetCallbackObject(), name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356 }
357 }
358 break;
359 }
360 case NORMAL:
361 case FIELD:
362 case CONSTANT_FUNCTION: {
363 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000364 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000366 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000367 return GetPropertyWithFailedAccessCheck(receiver,
368 &r,
369 name,
370 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371 }
372 break;
373 }
374 case INTERCEPTOR: {
375 // If the object has an interceptor, try real named properties.
376 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000377 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000378 result->holder()->LookupRealNamedProperty(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000379 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000380 return GetPropertyWithFailedAccessCheck(receiver,
381 &r,
382 name,
383 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000384 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000385 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000387 default:
388 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 }
390 }
391
ager@chromium.org8bb60582008-12-11 12:02:20 +0000392 // No accessible property found.
393 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000394 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000395 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
396 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000397}
398
399
ager@chromium.org870a0b62008-11-04 11:43:05 +0000400PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
401 Object* receiver,
402 LookupResult* result,
403 String* name,
404 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000405 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000406 switch (result->type()) {
407 case CALLBACKS: {
408 // Only allow API accessors.
409 Object* obj = result->GetCallbackObject();
410 if (obj->IsAccessorInfo()) {
411 AccessorInfo* info = AccessorInfo::cast(obj);
412 if (info->all_can_read()) {
413 return result->GetAttributes();
414 }
415 }
416 break;
417 }
418
419 case NORMAL:
420 case FIELD:
421 case CONSTANT_FUNCTION: {
422 if (!continue_search) break;
423 // Search ALL_CAN_READ accessors in prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000424 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000425 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000426 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000427 return GetPropertyAttributeWithFailedAccessCheck(receiver,
428 &r,
429 name,
430 continue_search);
431 }
432 break;
433 }
434
435 case INTERCEPTOR: {
436 // If the object has an interceptor, try real named properties.
437 // No access check in GetPropertyAttributeWithInterceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000438 LookupResult r(GetIsolate());
ager@chromium.org870a0b62008-11-04 11:43:05 +0000439 if (continue_search) {
440 result->holder()->LookupRealNamedProperty(name, &r);
441 } else {
442 result->holder()->LocalLookupRealNamedProperty(name, &r);
443 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000444 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000445 return GetPropertyAttributeWithFailedAccessCheck(receiver,
446 &r,
447 name,
448 continue_search);
449 }
450 break;
451 }
452
ager@chromium.org5c838252010-02-19 08:53:10 +0000453 default:
454 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000455 }
456 }
457
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000458 GetIsolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000459 return ABSENT;
460}
461
462
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000463Object* JSObject::GetNormalizedProperty(LookupResult* result) {
464 ASSERT(!HasFastProperties());
465 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
466 if (IsGlobalObject()) {
467 value = JSGlobalPropertyCell::cast(value)->value();
468 }
469 ASSERT(!value->IsJSGlobalPropertyCell());
470 return value;
471}
472
473
474Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
475 ASSERT(!HasFastProperties());
476 if (IsGlobalObject()) {
477 JSGlobalPropertyCell* cell =
478 JSGlobalPropertyCell::cast(
479 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
480 cell->set_value(value);
481 } else {
482 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
483 }
484 return value;
485}
486
487
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000488Handle<Object> JSObject::SetNormalizedProperty(Handle<JSObject> object,
489 Handle<String> key,
490 Handle<Object> value,
491 PropertyDetails details) {
492 CALL_HEAP_FUNCTION(object->GetIsolate(),
493 object->SetNormalizedProperty(*key, *value, details),
494 Object);
495}
496
497
lrn@chromium.org303ada72010-10-27 09:33:13 +0000498MaybeObject* JSObject::SetNormalizedProperty(String* name,
499 Object* value,
500 PropertyDetails details) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000501 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000502 int entry = property_dictionary()->FindEntry(name);
503 if (entry == StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000504 Object* store_value = value;
505 if (IsGlobalObject()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000506 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000507 MaybeObject* maybe_store_value =
508 heap->AllocateJSGlobalPropertyCell(value);
509 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000510 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000511 Object* dict;
512 { MaybeObject* maybe_dict =
513 property_dictionary()->Add(name, store_value, details);
514 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
515 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000516 set_properties(StringDictionary::cast(dict));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000517 return value;
518 }
519 // Preserve enumeration index.
520 details = PropertyDetails(details.attributes(),
521 details.type(),
522 property_dictionary()->DetailsAt(entry).index());
523 if (IsGlobalObject()) {
524 JSGlobalPropertyCell* cell =
525 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
526 cell->set_value(value);
527 // Please note we have to update the property details.
528 property_dictionary()->DetailsAtPut(entry, details);
529 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000530 property_dictionary()->SetEntry(entry, name, value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000531 }
532 return value;
533}
534
535
lrn@chromium.org303ada72010-10-27 09:33:13 +0000536MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000537 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000538 StringDictionary* dictionary = property_dictionary();
539 int entry = dictionary->FindEntry(name);
540 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000541 // If we have a global object set the cell to the hole.
542 if (IsGlobalObject()) {
543 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000544 if (details.IsDontDelete()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545 if (mode != FORCE_DELETION) return GetHeap()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000546 // When forced to delete global properties, we have to make a
547 // map change to invalidate any ICs that think they can load
548 // from the DontDelete cell without checking if it contains
549 // the hole value.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000550 Object* new_map;
551 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
552 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
553 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000554 set_map(Map::cast(new_map));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000555 }
556 JSGlobalPropertyCell* cell =
557 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000558 cell->set_value(cell->GetHeap()->the_hole_value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000559 dictionary->DetailsAtPut(entry, details.AsDeleted());
560 } else {
ager@chromium.org04921a82011-06-27 13:21:41 +0000561 Object* deleted = dictionary->DeleteProperty(entry, mode);
562 if (deleted == GetHeap()->true_value()) {
563 FixedArray* new_properties = NULL;
564 MaybeObject* maybe_properties = dictionary->Shrink(name);
565 if (!maybe_properties->To(&new_properties)) {
566 return maybe_properties;
567 }
568 set_properties(new_properties);
569 }
570 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000571 }
572 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000573 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000574}
575
576
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000577bool JSObject::IsDirty() {
578 Object* cons_obj = map()->constructor();
579 if (!cons_obj->IsJSFunction())
580 return true;
581 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000582 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000583 return true;
584 // If the object is fully fast case and has the same map it was
585 // created with then no changes can have been made to it.
586 return map() != fun->initial_map()
587 || !HasFastElements()
588 || !HasFastProperties();
589}
590
591
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000592Handle<Object> Object::GetProperty(Handle<Object> object,
593 Handle<Object> receiver,
594 LookupResult* result,
595 Handle<String> key,
596 PropertyAttributes* attributes) {
597 Isolate* isolate = object->IsHeapObject()
598 ? Handle<HeapObject>::cast(object)->GetIsolate()
599 : Isolate::Current();
600 CALL_HEAP_FUNCTION(
601 isolate,
602 object->GetProperty(*receiver, result, *key, attributes),
603 Object);
604}
605
606
lrn@chromium.org303ada72010-10-27 09:33:13 +0000607MaybeObject* Object::GetProperty(Object* receiver,
608 LookupResult* result,
609 String* name,
610 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000611 // Make sure that the top context does not change when doing
612 // callbacks or interceptor calls.
613 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 Heap* heap = name->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000615
616 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000617 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000618 // objects more than once in case of interceptors, because the
619 // holder will always be the interceptor holder and the search may
620 // only continue with a current object just after the interceptor
621 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000622 // Proxy handlers do not use the proxy's prototype, so we can skip this.
623 if (!result->IsHandler()) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000624 Object* last = result->IsProperty()
625 ? result->holder()
626 : Object::cast(heap->null_value());
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000627 ASSERT(this != this->GetPrototype());
628 for (Object* current = this; true; current = current->GetPrototype()) {
629 if (current->IsAccessCheckNeeded()) {
630 // Check if we're allowed to read from the current object. Note
631 // that even though we may not actually end up loading the named
632 // property from the current object, we still check that we have
633 // access to it.
634 JSObject* checked = JSObject::cast(current);
635 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
636 return checked->GetPropertyWithFailedAccessCheck(receiver,
637 result,
638 name,
639 attributes);
640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000642 // Stop traversing the chain once we reach the last object in the
643 // chain; either the holder of the result or null in case of an
644 // absent property.
645 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000647 }
648
kasper.lund44510672008-07-25 07:37:58 +0000649 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000652 }
653 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655 switch (result->type()) {
656 case NORMAL:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000657 value = result->holder()->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000658 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000660 case FIELD:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000661 value = result->holder()->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000663 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664 case CONSTANT_FUNCTION:
665 return result->GetConstantFunction();
666 case CALLBACKS:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000667 return result->holder()->GetPropertyWithCallback(
668 receiver, result->GetCallbackObject(), name);
669 case HANDLER:
670 return result->proxy()->GetPropertyWithHandler(receiver, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000671 case INTERCEPTOR: {
672 JSObject* recvr = JSObject::cast(receiver);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000673 return result->holder()->GetPropertyWithInterceptor(
674 recvr, name, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000676 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000677 case ELEMENTS_TRANSITION:
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000678 case CONSTANT_TRANSITION:
679 case NULL_DESCRIPTOR:
680 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000682 UNREACHABLE();
683 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684}
685
686
lrn@chromium.org303ada72010-10-27 09:33:13 +0000687MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000688 Heap* heap = IsSmi()
689 ? Isolate::Current()->heap()
690 : HeapObject::cast(this)->GetHeap();
691 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000692
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000693 // Iterate up the prototype chain until an element is found or the null
694 // prototype is encountered.
695 for (holder = this;
696 holder != heap->null_value();
697 holder = holder->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000698 if (!holder->IsJSObject()) {
699 Isolate* isolate = heap->isolate();
700 Context* global_context = isolate->context()->global_context();
701 if (holder->IsNumber()) {
702 holder = global_context->number_function()->instance_prototype();
703 } else if (holder->IsString()) {
704 holder = global_context->string_function()->instance_prototype();
705 } else if (holder->IsBoolean()) {
706 holder = global_context->boolean_function()->instance_prototype();
707 } else if (holder->IsJSProxy()) {
708 return JSProxy::cast(holder)->GetElementWithHandler(receiver, index);
709 } else {
710 // Undefined and null have no indexed properties.
711 ASSERT(holder->IsUndefined() || holder->IsNull());
712 return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000713 }
714 }
715
716 // Inline the case for JSObjects. Doing so significantly improves the
717 // performance of fetching elements where checking the prototype chain is
718 // necessary.
719 JSObject* js_object = JSObject::cast(holder);
720
721 // Check access rights if needed.
722 if (js_object->IsAccessCheckNeeded()) {
723 Isolate* isolate = heap->isolate();
724 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
725 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
726 return heap->undefined_value();
727 }
728 }
729
730 if (js_object->HasIndexedInterceptor()) {
731 return js_object->GetElementWithInterceptor(receiver, index);
732 }
733
734 if (js_object->elements() != heap->empty_fixed_array()) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000735 MaybeObject* result = js_object->GetElementsAccessor()->Get(
736 js_object->elements(),
737 index,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000738 js_object,
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000739 receiver);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000740 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000741 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000742 }
743
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000744 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745}
746
747
748Object* Object::GetPrototype() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000749 if (IsSmi()) {
750 Heap* heap = Isolate::Current()->heap();
751 Context* context = heap->isolate()->context()->global_context();
752 return context->number_function()->instance_prototype();
753 }
754
755 HeapObject* heap_object = HeapObject::cast(this);
756
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000757 // The object is either a number, a string, a boolean,
758 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000759 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000760 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000761 }
762 Heap* heap = heap_object->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000763 Context* context = heap->isolate()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000765 if (heap_object->IsHeapNumber()) {
766 return context->number_function()->instance_prototype();
767 }
768 if (heap_object->IsString()) {
769 return context->string_function()->instance_prototype();
770 }
771 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772 return context->boolean_function()->instance_prototype();
773 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000774 return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775 }
776}
777
778
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000779MaybeObject* Object::GetHash(CreationFlag flag) {
780 // The object is either a number, a string, an odd-ball,
781 // a real JS object, or a Harmony proxy.
782 if (IsNumber()) {
783 uint32_t hash = ComputeLongHash(double_to_uint64(Number()));
784 return Smi::FromInt(hash & Smi::kMaxValue);
785 }
786 if (IsString()) {
787 uint32_t hash = String::cast(this)->Hash();
788 return Smi::FromInt(hash);
789 }
790 if (IsOddball()) {
791 uint32_t hash = Oddball::cast(this)->to_string()->Hash();
792 return Smi::FromInt(hash);
793 }
794 if (IsJSReceiver()) {
795 return JSReceiver::cast(this)->GetIdentityHash(flag);
796 }
797
798 UNREACHABLE();
799 return Smi::FromInt(0);
800}
801
802
803bool Object::SameValue(Object* other) {
804 if (other == this) return true;
805 if (!IsHeapObject() || !other->IsHeapObject()) return false;
806
807 // The object is either a number, a string, an odd-ball,
808 // a real JS object, or a Harmony proxy.
809 if (IsNumber() && other->IsNumber()) {
810 double this_value = Number();
811 double other_value = other->Number();
812 return (this_value == other_value) ||
813 (isnan(this_value) && isnan(other_value));
814 }
815 if (IsString() && other->IsString()) {
816 return String::cast(this)->Equals(String::cast(other));
817 }
818 return false;
819}
820
821
whesse@chromium.org023421e2010-12-21 12:19:12 +0000822void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 HeapStringAllocator allocator;
824 StringStream accumulator(&allocator);
825 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000826 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827}
828
829
830void Object::ShortPrint(StringStream* accumulator) {
831 if (IsSmi()) {
832 Smi::cast(this)->SmiPrint(accumulator);
833 } else if (IsFailure()) {
834 Failure::cast(this)->FailurePrint(accumulator);
835 } else {
836 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
837 }
838}
839
840
whesse@chromium.org023421e2010-12-21 12:19:12 +0000841void Smi::SmiPrint(FILE* out) {
842 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843}
844
845
846void Smi::SmiPrint(StringStream* accumulator) {
847 accumulator->Add("%d", value());
848}
849
850
851void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000852 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000853}
854
855
whesse@chromium.org023421e2010-12-21 12:19:12 +0000856void Failure::FailurePrint(FILE* out) {
857 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858}
859
860
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000861// Should a word be prefixed by 'a' or 'an' in order to read naturally in
862// English? Returns false for non-ASCII or words that don't start with
863// a capital letter. The a/an rule follows pronunciation in English.
864// We don't use the BBC's overcorrect "an historic occasion" though if
865// you speak a dialect you may well say "an 'istoric occasion".
866static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000867 if (str->length() == 0) return false; // A nothing.
868 int c0 = str->Get(0);
869 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 if (c0 == 'U') {
871 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000872 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000873 }
874 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000875 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000876 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
877 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
878 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000879 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 }
881 return false;
882}
883
884
lrn@chromium.org303ada72010-10-27 09:33:13 +0000885MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000886#ifdef DEBUG
887 // Do not attempt to flatten in debug mode when allocation is not
888 // allowed. This is to avoid an assertion failure when allocating.
889 // Flattening strings is the only case where we always allow
890 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000891 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000892#endif
893
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000895 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000896 case kConsStringTag: {
897 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000898 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000899 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000900 }
901 // There's little point in putting the flat string in new space if the
902 // cons string is in old space. It can never get GCed until there is
903 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000904 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000905 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000906 Object* object;
907 String* result;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000908 if (IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000910 if (!maybe_object->ToObject(&object)) return maybe_object;
911 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000912 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000913 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000914 int first_length = first->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000915 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000916 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000917 String* second = cs->second();
918 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000919 dest + first_length,
920 0,
921 len - first_length);
922 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000923 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000925 if (!maybe_object->ToObject(&object)) return maybe_object;
926 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000927 result = String::cast(object);
928 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000929 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000930 int first_length = first->length();
931 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000932 String* second = cs->second();
933 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000934 dest + first_length,
935 0,
936 len - first_length);
937 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 cs->set_first(result);
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +0000939 cs->set_second(heap->empty_string(), SKIP_WRITE_BARRIER);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000940 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000941 }
942 default:
943 return this;
944 }
945}
946
947
ager@chromium.org6f10e412009-02-13 10:11:16 +0000948bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000949 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000950 // prohibited by the API.
951 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000952#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000953 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000954 // Assert that the resource and the string are equivalent.
955 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000956 ScopedVector<uc16> smart_chars(this->length());
957 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
958 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000959 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000960 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000961 }
962#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000964 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000965 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000966 return false;
967 }
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000968 bool is_ascii = this->IsAsciiRepresentation();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000969 bool is_symbol = this->IsSymbol();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000970
971 // Morph the object to an external string by adjusting the map and
972 // reinitializing the fields.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000973 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000974 this->set_map_no_write_barrier(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000975 is_symbol
976 ? (is_ascii ? heap->external_symbol_with_ascii_data_map()
977 : heap->external_symbol_map())
978 : (is_ascii ? heap->external_string_with_ascii_data_map()
979 : heap->external_string_map()));
980 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000981 this->set_map_no_write_barrier(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000982 is_symbol
983 ? (is_ascii ? heap->short_external_symbol_with_ascii_data_map()
984 : heap->short_external_symbol_map())
985 : (is_ascii ? heap->short_external_string_with_ascii_data_map()
986 : heap->short_external_string_map()));
ager@chromium.org6f10e412009-02-13 10:11:16 +0000987 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000988 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
989 self->set_resource(resource);
990 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +0000991
992 // Fill the remainder of the string with dead wood.
993 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000995 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000996 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
997 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000998 }
ager@chromium.org6f10e412009-02-13 10:11:16 +0000999 return true;
1000}
1001
1002
1003bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
1004#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +00001005 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001006 // Assert that the resource and the string are equivalent.
1007 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001008 ScopedVector<char> smart_chars(this->length());
1009 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
1010 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +00001011 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001012 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +00001013 }
1014#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001016 int size = this->Size(); // Byte size of the original string.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001017 if (size < ExternalString::kShortSize) {
ager@chromium.org6f10e412009-02-13 10:11:16 +00001018 return false;
1019 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001020 bool is_symbol = this->IsSymbol();
ager@chromium.org6f10e412009-02-13 10:11:16 +00001021
1022 // Morph the object to an external string by adjusting the map and
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001023 // reinitializing the fields. Use short version if space is limited.
1024 if (size >= ExternalString::kSize) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001025 this->set_map_no_write_barrier(
1026 is_symbol ? heap->external_ascii_symbol_map()
1027 : heap->external_ascii_string_map());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001028 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001029 this->set_map_no_write_barrier(
1030 is_symbol ? heap->short_external_ascii_symbol_map()
1031 : heap->short_external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +00001032 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001033 ExternalAsciiString* self = ExternalAsciiString::cast(this);
1034 self->set_resource(resource);
1035 if (is_symbol) self->Hash(); // Force regeneration of the hash value.
ager@chromium.org6f10e412009-02-13 10:11:16 +00001036
1037 // Fill the remainder of the string with dead wood.
1038 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001039 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001040 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001041 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
1042 new_size - size);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001043 }
ager@chromium.org6f10e412009-02-13 10:11:16 +00001044 return true;
1045}
1046
1047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001049 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001050 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001051 accumulator->Add("<Very long string[%u]>", len);
1052 return;
1053 }
1054
1055 if (!LooksValid()) {
1056 accumulator->Add("<Invalid String>");
1057 return;
1058 }
1059
1060 StringInputBuffer buf(this);
1061
1062 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +00001063 if (len > kMaxShortPrintLength) {
1064 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001065 truncated = true;
1066 }
1067 bool ascii = true;
1068 for (int i = 0; i < len; i++) {
1069 int c = buf.GetNext();
1070
1071 if (c < 32 || c >= 127) {
1072 ascii = false;
1073 }
1074 }
1075 buf.Reset(this);
1076 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001077 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 for (int i = 0; i < len; i++) {
1079 accumulator->Put(buf.GetNext());
1080 }
1081 accumulator->Put('>');
1082 } else {
1083 // Backslash indicates that the string contains control
1084 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001085 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001086 for (int i = 0; i < len; i++) {
1087 int c = buf.GetNext();
1088 if (c == '\n') {
1089 accumulator->Add("\\n");
1090 } else if (c == '\r') {
1091 accumulator->Add("\\r");
1092 } else if (c == '\\') {
1093 accumulator->Add("\\\\");
1094 } else if (c < 32 || c > 126) {
1095 accumulator->Add("\\x%02x", c);
1096 } else {
1097 accumulator->Put(c);
1098 }
1099 }
1100 if (truncated) {
1101 accumulator->Put('.');
1102 accumulator->Put('.');
1103 accumulator->Put('.');
1104 }
1105 accumulator->Put('>');
1106 }
1107 return;
1108}
1109
1110
1111void JSObject::JSObjectShortPrint(StringStream* accumulator) {
1112 switch (map()->instance_type()) {
1113 case JS_ARRAY_TYPE: {
1114 double length = JSArray::cast(this)->length()->Number();
1115 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
1116 break;
1117 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001118 case JS_WEAK_MAP_TYPE: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001119 accumulator->Add("<JS WeakMap>");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001120 break;
1121 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001122 case JS_REGEXP_TYPE: {
1123 accumulator->Add("<JS RegExp>");
1124 break;
1125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001126 case JS_FUNCTION_TYPE: {
1127 Object* fun_name = JSFunction::cast(this)->shared()->name();
1128 bool printed = false;
1129 if (fun_name->IsString()) {
1130 String* str = String::cast(fun_name);
1131 if (str->length() > 0) {
1132 accumulator->Add("<JS Function ");
1133 accumulator->Put(str);
1134 accumulator->Put('>');
1135 printed = true;
1136 }
1137 }
1138 if (!printed) {
1139 accumulator->Add("<JS Function>");
1140 }
1141 break;
1142 }
1143 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001144 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001146 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001147 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001148 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001149 bool printed = false;
1150 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001151 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1153 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001154 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1158 } else {
1159 Object* constructor_name =
1160 JSFunction::cast(constructor)->shared()->name();
1161 if (constructor_name->IsString()) {
1162 String* str = String::cast(constructor_name);
1163 if (str->length() > 0) {
1164 bool vowel = AnWord(str);
1165 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001166 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001167 vowel ? "n" : "");
1168 accumulator->Put(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 printed = true;
1170 }
1171 }
1172 }
1173 }
1174 if (!printed) {
1175 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1176 }
1177 }
1178 if (IsJSValue()) {
1179 accumulator->Add(" value = ");
1180 JSValue::cast(this)->value()->ShortPrint(accumulator);
1181 }
1182 accumulator->Put('>');
1183 break;
1184 }
1185 }
1186}
1187
1188
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001189void JSObject::PrintElementsTransition(
1190 FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
1191 ElementsKind to_kind, FixedArrayBase* to_elements) {
1192 if (from_kind != to_kind) {
1193 PrintF(file, "elements transition [");
1194 PrintElementsKind(file, from_kind);
1195 PrintF(file, " -> ");
1196 PrintElementsKind(file, to_kind);
1197 PrintF(file, "] in ");
1198 JavaScriptFrame::PrintTop(file, false, true);
1199 PrintF(file, " for ");
1200 ShortPrint(file);
1201 PrintF(file, " from ");
1202 from_elements->ShortPrint(file);
1203 PrintF(file, " to ");
1204 to_elements->ShortPrint(file);
1205 PrintF(file, "\n");
1206 }
1207}
1208
1209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001210void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001211 Heap* heap = GetHeap();
1212 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 accumulator->Add("!!!INVALID POINTER!!!");
1214 return;
1215 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217 accumulator->Add("!!!INVALID MAP!!!");
1218 return;
1219 }
1220
1221 accumulator->Add("%p ", this);
1222
1223 if (IsString()) {
1224 String::cast(this)->StringShortPrint(accumulator);
1225 return;
1226 }
1227 if (IsJSObject()) {
1228 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1229 return;
1230 }
1231 switch (map()->instance_type()) {
1232 case MAP_TYPE:
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001233 accumulator->Add("<Map(elements=%u)>", Map::cast(this)->elements_kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234 break;
1235 case FIXED_ARRAY_TYPE:
1236 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1237 break;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001238 case FIXED_DOUBLE_ARRAY_TYPE:
1239 accumulator->Add("<FixedDoubleArray[%u]>",
1240 FixedDoubleArray::cast(this)->length());
1241 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242 case BYTE_ARRAY_TYPE:
1243 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1244 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001245 case FREE_SPACE_TYPE:
1246 accumulator->Add("<FreeSpace[%u]>", FreeSpace::cast(this)->Size());
1247 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001248 case EXTERNAL_PIXEL_ARRAY_TYPE:
1249 accumulator->Add("<ExternalPixelArray[%u]>",
1250 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001251 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001252 case EXTERNAL_BYTE_ARRAY_TYPE:
1253 accumulator->Add("<ExternalByteArray[%u]>",
1254 ExternalByteArray::cast(this)->length());
1255 break;
1256 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1257 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1258 ExternalUnsignedByteArray::cast(this)->length());
1259 break;
1260 case EXTERNAL_SHORT_ARRAY_TYPE:
1261 accumulator->Add("<ExternalShortArray[%u]>",
1262 ExternalShortArray::cast(this)->length());
1263 break;
1264 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1265 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1266 ExternalUnsignedShortArray::cast(this)->length());
1267 break;
1268 case EXTERNAL_INT_ARRAY_TYPE:
1269 accumulator->Add("<ExternalIntArray[%u]>",
1270 ExternalIntArray::cast(this)->length());
1271 break;
1272 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1273 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1274 ExternalUnsignedIntArray::cast(this)->length());
1275 break;
1276 case EXTERNAL_FLOAT_ARRAY_TYPE:
1277 accumulator->Add("<ExternalFloatArray[%u]>",
1278 ExternalFloatArray::cast(this)->length());
1279 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001280 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1281 accumulator->Add("<ExternalDoubleArray[%u]>",
1282 ExternalDoubleArray::cast(this)->length());
1283 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 case SHARED_FUNCTION_INFO_TYPE:
1285 accumulator->Add("<SharedFunctionInfo>");
1286 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001287 case JS_MESSAGE_OBJECT_TYPE:
1288 accumulator->Add("<JSMessageObject>");
1289 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290#define MAKE_STRUCT_CASE(NAME, Name, name) \
1291 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001292 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001294 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001295 break;
1296 STRUCT_LIST(MAKE_STRUCT_CASE)
1297#undef MAKE_STRUCT_CASE
1298 case CODE_TYPE:
1299 accumulator->Add("<Code>");
1300 break;
1301 case ODDBALL_TYPE: {
1302 if (IsUndefined())
1303 accumulator->Add("<undefined>");
1304 else if (IsTheHole())
1305 accumulator->Add("<the hole>");
1306 else if (IsNull())
1307 accumulator->Add("<null>");
1308 else if (IsTrue())
1309 accumulator->Add("<true>");
1310 else if (IsFalse())
1311 accumulator->Add("<false>");
1312 else
1313 accumulator->Add("<Odd Oddball>");
1314 break;
1315 }
1316 case HEAP_NUMBER_TYPE:
1317 accumulator->Add("<Number: ");
1318 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1319 accumulator->Put('>');
1320 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001321 case JS_PROXY_TYPE:
1322 accumulator->Add("<JSProxy>");
1323 break;
1324 case JS_FUNCTION_PROXY_TYPE:
1325 accumulator->Add("<JSFunctionProxy>");
1326 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001327 case FOREIGN_TYPE:
1328 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001330 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1331 accumulator->Add("Cell for ");
1332 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1333 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001334 default:
1335 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1336 break;
1337 }
1338}
1339
1340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341void HeapObject::Iterate(ObjectVisitor* v) {
1342 // Handle header
1343 IteratePointer(v, kMapOffset);
1344 // Handle object body
1345 Map* m = map();
1346 IterateBody(m->instance_type(), SizeFromMap(m), v);
1347}
1348
1349
1350void HeapObject::IterateBody(InstanceType type, int object_size,
1351 ObjectVisitor* v) {
1352 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1353 // During GC, the map pointer field is encoded.
1354 if (type < FIRST_NONSTRING_TYPE) {
1355 switch (type & kStringRepresentationMask) {
1356 case kSeqStringTag:
1357 break;
1358 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001359 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 break;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001361 case kSlicedStringTag:
1362 SlicedString::BodyDescriptor::IterateBody(this, v);
1363 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001364 case kExternalStringTag:
1365 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1366 reinterpret_cast<ExternalAsciiString*>(this)->
1367 ExternalAsciiStringIterateBody(v);
1368 } else {
1369 reinterpret_cast<ExternalTwoByteString*>(this)->
1370 ExternalTwoByteStringIterateBody(v);
1371 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 break;
1373 }
1374 return;
1375 }
1376
1377 switch (type) {
1378 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001379 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001381 case FIXED_DOUBLE_ARRAY_TYPE:
1382 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001384 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385 case JS_VALUE_TYPE:
1386 case JS_ARRAY_TYPE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001387 case JS_SET_TYPE:
1388 case JS_MAP_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001389 case JS_WEAK_MAP_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001390 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001391 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001394 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001395 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001397 case JS_FUNCTION_TYPE:
1398 reinterpret_cast<JSFunction*>(this)
1399 ->JSFunctionIterateBody(object_size, v);
1400 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001401 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001402 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001403 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001404 case JS_PROXY_TYPE:
1405 JSProxy::BodyDescriptor::IterateBody(this, v);
1406 break;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001407 case JS_FUNCTION_PROXY_TYPE:
1408 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1409 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001410 case FOREIGN_TYPE:
1411 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412 break;
1413 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001414 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 break;
1416 case CODE_TYPE:
1417 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1418 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001419 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001420 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001421 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422 case HEAP_NUMBER_TYPE:
1423 case FILLER_TYPE:
1424 case BYTE_ARRAY_TYPE:
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001425 case FREE_SPACE_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001426 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001427 case EXTERNAL_BYTE_ARRAY_TYPE:
1428 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1429 case EXTERNAL_SHORT_ARRAY_TYPE:
1430 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1431 case EXTERNAL_INT_ARRAY_TYPE:
1432 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1433 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001434 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001436 case SHARED_FUNCTION_INFO_TYPE:
1437 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001439
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001440#define MAKE_STRUCT_CASE(NAME, Name, name) \
1441 case NAME##_TYPE:
1442 STRUCT_LIST(MAKE_STRUCT_CASE)
1443#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001444 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445 break;
1446 default:
1447 PrintF("Unknown type: %d\n", type);
1448 UNREACHABLE();
1449 }
1450}
1451
1452
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001453Object* HeapNumber::HeapNumberToBoolean() {
1454 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001455#if __BYTE_ORDER == __LITTLE_ENDIAN
1456 union IeeeDoubleLittleEndianArchType u;
1457#elif __BYTE_ORDER == __BIG_ENDIAN
1458 union IeeeDoubleBigEndianArchType u;
1459#endif
1460 u.d = value();
1461 if (u.bits.exp == 2047) {
1462 // Detect NaN for IEEE double precision floating point.
1463 if ((u.bits.man_low | u.bits.man_high) != 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 return GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001466 if (u.bits.exp == 0) {
1467 // Detect +0, and -0 for IEEE double precision floating point.
1468 if ((u.bits.man_low | u.bits.man_high) == 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001469 return GetHeap()->false_value();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001470 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472}
1473
1474
whesse@chromium.org023421e2010-12-21 12:19:12 +00001475void HeapNumber::HeapNumberPrint(FILE* out) {
1476 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001477}
1478
1479
1480void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1481 // The Windows version of vsnprintf can allocate when printing a %g string
1482 // into a buffer that may not be big enough. We don't want random memory
1483 // allocation when producing post-crash stack traces, so we print into a
1484 // buffer that is plenty big enough for any floating point number, then
1485 // print that using vsnprintf (which may truncate but never allocate if
1486 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001487 EmbeddedVector<char, 100> buffer;
1488 OS::SNPrintF(buffer, "%.16g", Number());
1489 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490}
1491
1492
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001493String* JSReceiver::class_name() {
1494 if (IsJSFunction() && IsJSFunctionProxy()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001495 return GetHeap()->function_class_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001496 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 if (map()->constructor()->IsJSFunction()) {
1498 JSFunction* constructor = JSFunction::cast(map()->constructor());
1499 return String::cast(constructor->shared()->instance_class_name());
1500 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001501 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502 return GetHeap()->Object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503}
1504
1505
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001506String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001507 if (map()->constructor()->IsJSFunction()) {
1508 JSFunction* constructor = JSFunction::cast(map()->constructor());
1509 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001510 if (name->length() > 0) return name;
1511 String* inferred_name = constructor->shared()->inferred_name();
1512 if (inferred_name->length() > 0) return inferred_name;
1513 Object* proto = GetPrototype();
1514 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001515 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001516 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001517 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001518 return GetHeap()->Object_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001519}
1520
1521
lrn@chromium.org303ada72010-10-27 09:33:13 +00001522MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1523 String* name,
1524 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001525 int index = new_map->PropertyIndexFor(name);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001526 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 ASSERT(map()->unused_property_fields() == 0);
1528 int new_unused = new_map->unused_property_fields();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001529 Object* values;
1530 { MaybeObject* maybe_values =
1531 properties()->CopySize(properties()->length() + new_unused + 1);
1532 if (!maybe_values->ToObject(&values)) return maybe_values;
1533 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 set_properties(FixedArray::cast(values));
1535 }
1536 set_map(new_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001537 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001538}
1539
1540
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001541static bool IsIdentifier(UnicodeCache* cache,
1542 unibrow::CharacterStream* buffer) {
1543 // Checks whether the buffer contains an identifier (no escape).
1544 if (!buffer->has_more()) return false;
1545 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1546 return false;
1547 }
1548 while (buffer->has_more()) {
1549 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1550 return false;
1551 }
1552 }
1553 return true;
1554}
1555
1556
lrn@chromium.org303ada72010-10-27 09:33:13 +00001557MaybeObject* JSObject::AddFastProperty(String* name,
1558 Object* value,
1559 PropertyAttributes attributes) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001560 ASSERT(!IsJSGlobalProxy());
1561
ager@chromium.org8c51fc92009-04-22 11:54:55 +00001562 // Normalize the object if the name is an actual string (not the
1563 // hidden symbols) and is not a real identifier.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001564 Isolate* isolate = GetHeap()->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001565 StringInputBuffer buffer(name);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001566 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001567 && name != isolate->heap()->hidden_symbol()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001568 Object* obj;
1569 { MaybeObject* maybe_obj =
1570 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1571 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573 return AddSlowProperty(name, value, attributes);
1574 }
1575
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001576 DescriptorArray* old_descriptors = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577 // Compute the new index for new field.
1578 int index = map()->NextFreePropertyIndex();
1579
1580 // Allocate new instance descriptors with (name, index) added
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001581 FieldDescriptor new_field(name, index, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001582 Object* new_descriptors;
1583 { MaybeObject* maybe_new_descriptors =
1584 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1585 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1586 return maybe_new_descriptors;
1587 }
1588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001590 // Only allow map transition if the object isn't the global object and there
1591 // is not a transition for the name, or there's a transition for the name but
1592 // it's unrelated to properties.
1593 int descriptor_index = old_descriptors->Search(name);
1594
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001595 // Element transitions are stored in the descriptor for property "", which is
1596 // not a identifier and should have forced a switch to slow properties above.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001597 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001598 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001599 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001600 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 bool allow_map_transition =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001602 can_insert_transition &&
1603 (isolate->context()->global_context()->object_function()->map() != map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604
ager@chromium.org7c537e22008-10-16 08:43:32 +00001605 ASSERT(index < map()->inobject_properties() ||
1606 (index - map()->inobject_properties()) < properties()->length() ||
1607 map()->unused_property_fields() == 0);
1608 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001609 Object* r;
1610 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1611 if (!maybe_r->ToObject(&r)) return maybe_r;
1612 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001613 Map* new_map = Map::cast(r);
1614 if (allow_map_transition) {
1615 // Allocate new instance descriptors for the old map with map transition.
1616 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001617 Object* r;
1618 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1619 if (!maybe_r->ToObject(&r)) return maybe_r;
1620 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001621 old_descriptors = DescriptorArray::cast(r);
1622 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623
ager@chromium.org7c537e22008-10-16 08:43:32 +00001624 if (map()->unused_property_fields() == 0) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001625 if (properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001626 Object* obj;
1627 { MaybeObject* maybe_obj =
1628 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1629 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001631 return AddSlowProperty(name, value, attributes);
1632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633 // Make room for the new value
lrn@chromium.org303ada72010-10-27 09:33:13 +00001634 Object* values;
1635 { MaybeObject* maybe_values =
1636 properties()->CopySize(properties()->length() + kFieldsAdded);
1637 if (!maybe_values->ToObject(&values)) return maybe_values;
1638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 set_properties(FixedArray::cast(values));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001640 new_map->set_unused_property_fields(kFieldsAdded - 1);
1641 } else {
1642 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001644 // We have now allocated all the necessary objects.
1645 // All the changes can be applied at once, so they are atomic.
1646 map()->set_instance_descriptors(old_descriptors);
1647 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1648 set_map(new_map);
1649 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650}
1651
1652
lrn@chromium.org303ada72010-10-27 09:33:13 +00001653MaybeObject* JSObject::AddConstantFunctionProperty(
1654 String* name,
1655 JSFunction* function,
1656 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657 // Allocate new instance descriptors with (name, function) added
1658 ConstantFunctionDescriptor d(name, function, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001659 Object* new_descriptors;
1660 { MaybeObject* maybe_new_descriptors =
1661 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1662 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1663 return maybe_new_descriptors;
1664 }
1665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666
1667 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668 Object* new_map;
1669 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1670 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1671 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001672
1673 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1674 Map::cast(new_map)->set_instance_descriptors(descriptors);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001675 Map* old_map = map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 set_map(Map::cast(new_map));
1677
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001678 // If the old map is the global object map (from new Object()),
1679 // then transitions are not added to it, so we are done.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001680 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 if (old_map == heap->isolate()->context()->global_context()->
1682 object_function()->map()) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001683 return function;
1684 }
1685
1686 // Do not add CONSTANT_TRANSITIONS to global objects
1687 if (IsGlobalObject()) {
1688 return function;
1689 }
1690
1691 // Add a CONSTANT_TRANSITION descriptor to the old map,
1692 // so future assignments to this property on other objects
1693 // of the same type will create a normal field, not a constant function.
1694 // Don't do this for special properties, with non-trival attributes.
1695 if (attributes != NONE) {
1696 return function;
1697 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001698 ConstTransitionDescriptor mark(name, Map::cast(new_map));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001699 { MaybeObject* maybe_new_descriptors =
1700 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1701 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1702 // We have accomplished the main goal, so return success.
1703 return function;
1704 }
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001705 }
1706 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001708 return function;
1709}
1710
1711
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001712// Add property in slow mode
lrn@chromium.org303ada72010-10-27 09:33:13 +00001713MaybeObject* JSObject::AddSlowProperty(String* name,
1714 Object* value,
1715 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001716 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001717 StringDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001718 Object* store_value = value;
1719 if (IsGlobalObject()) {
1720 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001721 int entry = dict->FindEntry(name);
1722 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001723 store_value = dict->ValueAt(entry);
1724 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001725 // Assign an enumeration index to the property and update
1726 // SetNextEnumerationIndex.
1727 int index = dict->NextEnumerationIndex();
1728 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1729 dict->SetNextEnumerationIndex(index + 1);
1730 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001731 return value;
1732 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001733 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001736 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1737 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001738 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001740 PropertyDetails details = PropertyDetails(attributes, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001741 Object* result;
1742 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1743 if (!maybe_result->ToObject(&result)) return maybe_result;
1744 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001745 if (dict != result) set_properties(StringDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001746 return value;
1747}
1748
1749
lrn@chromium.org303ada72010-10-27 09:33:13 +00001750MaybeObject* JSObject::AddProperty(String* name,
1751 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001752 PropertyAttributes attributes,
1753 StrictModeFlag strict_mode) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001754 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001755 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001756 Heap* heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001757 if (!map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001758 if (strict_mode == kNonStrictMode) {
1759 return heap->undefined_value();
1760 } else {
1761 Handle<Object> args[1] = {Handle<String>(name)};
1762 return heap->isolate()->Throw(
1763 *FACTORY->NewTypeError("object_not_extensible",
1764 HandleVector(args, 1)));
1765 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001767 if (HasFastProperties()) {
1768 // Ensure the descriptor array does not get too big.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769 if (map_of_this->instance_descriptors()->number_of_descriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001770 DescriptorArray::kMaxNumberOfDescriptors) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00001771 if (value->IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 return AddConstantFunctionProperty(name,
1773 JSFunction::cast(value),
1774 attributes);
1775 } else {
1776 return AddFastProperty(name, value, attributes);
1777 }
1778 } else {
1779 // Normalize the object to prevent very large instance descriptors.
1780 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001781 Object* obj;
1782 { MaybeObject* maybe_obj =
1783 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1785 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786 }
1787 }
1788 return AddSlowProperty(name, value, attributes);
1789}
1790
1791
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792MaybeObject* JSObject::SetPropertyPostInterceptor(
1793 String* name,
1794 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001795 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001796 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001797 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001798 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001799 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001800 if (result.IsFound()) {
1801 // An existing property, a map transition or a null descriptor was
1802 // found. Use set property to handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001803 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001804 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001805 bool found = false;
1806 MaybeObject* result_object;
1807 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
1808 value,
1809 attributes,
1810 &found,
1811 strict_mode);
1812 if (found) return result_object;
ager@chromium.org5c838252010-02-19 08:53:10 +00001813 // Add a new real property.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001814 return AddProperty(name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815}
1816
1817
lrn@chromium.org303ada72010-10-27 09:33:13 +00001818MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1819 Object* value,
1820 PropertyAttributes attributes) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001821 StringDictionary* dictionary = property_dictionary();
1822 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001823 int new_enumeration_index = 0; // 0 means "Use the next available index."
1824 if (old_index != -1) {
1825 // All calls to ReplaceSlowProperty have had all transitions removed.
rossberg@chromium.org994edf62012-02-06 10:12:55 +00001826 ASSERT(!dictionary->ContainsTransition(old_index));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001827 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1828 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001829
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001830 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001831 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001832}
1833
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001834
lrn@chromium.org303ada72010-10-27 09:33:13 +00001835MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
ager@chromium.org7c537e22008-10-16 08:43:32 +00001836 String* name,
1837 Object* new_value,
1838 PropertyAttributes attributes) {
1839 Map* old_map = map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001840 Object* result;
1841 { MaybeObject* maybe_result =
1842 ConvertDescriptorToField(name, new_value, attributes);
1843 if (!maybe_result->ToObject(&result)) return maybe_result;
1844 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001845 // If we get to this point we have succeeded - do not return failure
1846 // after this point. Later stuff is optional.
1847 if (!HasFastProperties()) {
1848 return result;
1849 }
1850 // Do not add transitions to the map of "new Object()".
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001851 if (map() == GetIsolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001852 object_function()->map()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001853 return result;
1854 }
1855
1856 MapTransitionDescriptor transition(name,
1857 map(),
1858 attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001859 Object* new_descriptors;
1860 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1861 CopyInsert(&transition, KEEP_TRANSITIONS);
1862 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1863 return result; // Yes, return _result_.
1864 }
1865 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001866 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1867 return result;
1868}
1869
1870
lrn@chromium.org303ada72010-10-27 09:33:13 +00001871MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1872 Object* new_value,
1873 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001874 if (map()->unused_property_fields() == 0 &&
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001875 properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001876 Object* obj;
1877 { MaybeObject* maybe_obj =
1878 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1879 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1880 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001881 return ReplaceSlowProperty(name, new_value, attributes);
1882 }
1883
1884 int index = map()->NextFreePropertyIndex();
1885 FieldDescriptor new_field(name, index, attributes);
1886 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001887 Object* descriptors_unchecked;
1888 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1889 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1890 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1891 return maybe_descriptors_unchecked;
1892 }
1893 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001894 DescriptorArray* new_descriptors =
1895 DescriptorArray::cast(descriptors_unchecked);
1896
1897 // Make a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001898 Object* new_map_unchecked;
1899 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1900 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1901 return maybe_new_map_unchecked;
1902 }
1903 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001904 Map* new_map = Map::cast(new_map_unchecked);
1905 new_map->set_instance_descriptors(new_descriptors);
1906
1907 // Make new properties array if necessary.
1908 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1909 int new_unused_property_fields = map()->unused_property_fields() - 1;
1910 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001911 new_unused_property_fields = kFieldsAdded - 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001912 Object* new_properties_object;
1913 { MaybeObject* maybe_new_properties_object =
1914 properties()->CopySize(properties()->length() + kFieldsAdded);
1915 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1916 return maybe_new_properties_object;
1917 }
1918 }
1919 new_properties = FixedArray::cast(new_properties_object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001920 }
1921
1922 // Update pointers to commit changes.
1923 // Object points to the new map.
1924 new_map->set_unused_property_fields(new_unused_property_fields);
1925 set_map(new_map);
1926 if (new_properties) {
1927 set_properties(FixedArray::cast(new_properties));
1928 }
1929 return FastPropertyAtPut(index, new_value);
1930}
1931
1932
1933
lrn@chromium.org303ada72010-10-27 09:33:13 +00001934MaybeObject* JSObject::SetPropertyWithInterceptor(
1935 String* name,
1936 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001937 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001938 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001939 Isolate* isolate = GetIsolate();
1940 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001941 Handle<JSObject> this_handle(this);
1942 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001943 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001944 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1945 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001946 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1947 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001948 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 v8::NamedPropertySetter setter =
1950 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1951 v8::Handle<v8::Value> result;
1952 {
1953 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001954 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001955 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 isolate->heap()->undefined_value() :
1957 value,
1958 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 result = setter(v8::Utils::ToLocal(name_handle),
1960 v8::Utils::ToLocal(value_unhole),
1961 info);
1962 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001963 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001964 if (!result.IsEmpty()) return *value_handle;
1965 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001966 MaybeObject* raw_result =
1967 this_handle->SetPropertyPostInterceptor(*name_handle,
1968 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001969 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001970 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001971 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001972 return raw_result;
1973}
1974
1975
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001976Handle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
1977 Handle<String> key,
1978 Handle<Object> value,
1979 PropertyAttributes attributes,
1980 StrictModeFlag strict_mode) {
1981 CALL_HEAP_FUNCTION(object->GetIsolate(),
1982 object->SetProperty(*key, *value, attributes, strict_mode),
1983 Object);
1984}
1985
1986
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001987MaybeObject* JSReceiver::SetProperty(String* name,
1988 Object* value,
1989 PropertyAttributes attributes,
1990 StrictModeFlag strict_mode) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001991 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992 LocalLookup(name, &result);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001993 return SetProperty(&result, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001994}
1995
1996
lrn@chromium.org303ada72010-10-27 09:33:13 +00001997MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1998 String* name,
1999 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002000 JSObject* holder,
2001 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 Isolate* isolate = GetIsolate();
2003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002004
2005 // We should never get here to initialize a const with the hole
2006 // value since a const declaration would conflict with the setter.
2007 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002008 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009
2010 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002011 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002013 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002015 reinterpret_cast<AccessorDescriptor*>(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002016 Foreign::cast(structure)->foreign_address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002017 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002018 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002019 if (obj->IsFailure()) return obj;
2020 return *value_handle;
2021 }
2022
2023 if (structure->IsAccessorInfo()) {
2024 // api style callbacks
2025 AccessorInfo* data = AccessorInfo::cast(structure);
2026 Object* call_obj = data->setter();
2027 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
2028 if (call_fun == NULL) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002030 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
2031 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002032 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033 {
2034 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002035 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 call_fun(v8::Utils::ToLocal(key),
2037 v8::Utils::ToLocal(value_handle),
2038 info);
2039 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002040 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002041 return *value_handle;
2042 }
2043
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002044 if (structure->IsAccessorPair()) {
2045 Object* setter = AccessorPair::cast(structure)->setter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002046 if (setter->IsSpecFunction()) {
2047 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2048 return SetPropertyWithDefinedSetter(JSReceiver::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002050 if (strict_mode == kNonStrictMode) {
2051 return value;
2052 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002055 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002056 return isolate->Throw(
2057 *isolate->factory()->NewTypeError("no_setter_in_callback",
2058 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 }
2061
2062 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002063 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064}
2065
2066
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002067MaybeObject* JSReceiver::SetPropertyWithDefinedSetter(JSReceiver* setter,
2068 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002069 Isolate* isolate = GetIsolate();
2070 Handle<Object> value_handle(value, isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002071 Handle<JSReceiver> fun(setter, isolate);
2072 Handle<JSReceiver> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002073#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002074 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002075 // Handle stepping into a setter if step into is active.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002076 // TODO(rossberg): should this apply to getters that are function proxies?
2077 if (debug->StepInActive() && fun->IsJSFunction()) {
2078 debug->HandleStepIn(
2079 Handle<JSFunction>::cast(fun), Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00002080 }
2081#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002082 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002083 Handle<Object> argv[] = { value_handle };
2084 Execution::Call(fun, self, ARRAY_SIZE(argv), argv, &has_pending_exception);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002085 // Check for pending exception and return the result.
2086 if (has_pending_exception) return Failure::Exception();
2087 return *value_handle;
2088}
2089
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002090
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002091void JSObject::LookupCallbackSetterInPrototypes(String* name,
2092 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002093 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002094 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002095 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002096 pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002097 if (pt->IsJSProxy()) {
2098 return result->HandlerResult(JSProxy::cast(pt));
2099 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002100 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002101 if (result->IsProperty()) {
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002102 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
2103 // Found non-callback or read-only callback, stop looking.
2104 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105 }
2106 }
2107 result->NotFound();
2108}
2109
2110
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002111MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
2112 uint32_t index,
2113 Object* value,
2114 bool* found,
2115 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002116 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002117 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002118 pt != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002119 pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002120 if (pt->IsJSProxy()) {
2121 String* name;
2122 MaybeObject* maybe = GetHeap()->Uint32ToString(index);
2123 if (!maybe->To<String>(&name)) {
2124 *found = true; // Force abort
2125 return maybe;
2126 }
2127 return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
2128 name, value, NONE, strict_mode, found);
2129 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002130 if (!JSObject::cast(pt)->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00002131 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002132 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002133 SeededNumberDictionary* dictionary =
2134 JSObject::cast(pt)->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002135 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002136 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002137 PropertyDetails details = dictionary->DetailsAt(entry);
2138 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002139 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002140 return SetElementWithCallback(dictionary->ValueAt(entry),
2141 index,
2142 value,
2143 JSObject::cast(pt),
2144 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002145 }
2146 }
2147 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00002148 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002149 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002150}
2151
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002152MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
2153 String* name,
2154 Object* value,
2155 PropertyAttributes attributes,
2156 bool* found,
2157 StrictModeFlag strict_mode) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002158 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002159 // We could not find a local property so let's check whether there is an
2160 // accessor that wants to handle the property.
2161 LookupResult accessor_result(heap->isolate());
2162 LookupCallbackSetterInPrototypes(name, &accessor_result);
2163 if (accessor_result.IsFound()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002164 *found = true;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002165 if (accessor_result.type() == CALLBACKS) {
2166 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002167 name,
2168 value,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002169 accessor_result.holder(),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002170 strict_mode);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002171 } else if (accessor_result.type() == HANDLER) {
2172 // There is a proxy in the prototype chain. Invoke its
2173 // getPropertyDescriptor trap.
2174 bool found = false;
2175 // SetPropertyWithHandlerIfDefiningSetter can cause GC,
2176 // make sure to use the handlified references after calling
2177 // the function.
2178 Handle<JSObject> self(this);
2179 Handle<String> hname(name);
2180 Handle<Object> hvalue(value);
2181 MaybeObject* result =
2182 accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
2183 name, value, attributes, strict_mode, &found);
2184 if (found) return result;
2185 // The proxy does not define the property as an accessor.
2186 // Consequently, it has no effect on setting the receiver.
2187 return self->AddProperty(*hname, *hvalue, attributes, strict_mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002188 }
2189 }
2190 *found = false;
2191 return heap->the_hole_value();
2192}
2193
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002194
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
2196 DescriptorArray* descriptors = map()->instance_descriptors();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002197 int number = descriptors->SearchWithCache(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198 if (number != DescriptorArray::kNotFound) {
2199 result->DescriptorResult(this, descriptors->GetDetails(number), number);
2200 } else {
2201 result->NotFound();
2202 }
2203}
2204
2205
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002206void Map::LookupInDescriptors(JSObject* holder,
2207 String* name,
2208 LookupResult* result) {
2209 DescriptorArray* descriptors = instance_descriptors();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002210 DescriptorLookupCache* cache =
2211 GetHeap()->isolate()->descriptor_lookup_cache();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 int number = cache->Lookup(descriptors, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002213 if (number == DescriptorLookupCache::kAbsent) {
2214 number = descriptors->Search(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002215 cache->Update(descriptors, name, number);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002216 }
2217 if (number != DescriptorArray::kNotFound) {
2218 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
2219 } else {
2220 result->NotFound();
2221 }
2222}
2223
2224
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002225static bool ContainsMap(MapHandleList* maps, Handle<Map> map) {
2226 ASSERT(!map.is_null());
2227 for (int i = 0; i < maps->length(); ++i) {
2228 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true;
2229 }
2230 return false;
2231}
2232
2233
2234template <class T>
2235static Handle<T> MaybeNull(T* p) {
2236 if (p == NULL) return Handle<T>::null();
2237 return Handle<T>(p);
2238}
2239
2240
2241Handle<Map> Map::FindTransitionedMap(MapHandleList* candidates) {
2242 ElementsKind elms_kind = elements_kind();
2243 if (elms_kind == FAST_DOUBLE_ELEMENTS) {
2244 bool dummy = true;
2245 Handle<Map> fast_map =
2246 MaybeNull(LookupElementsTransitionMap(FAST_ELEMENTS, &dummy));
2247 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2248 return fast_map;
2249 }
2250 return Handle<Map>::null();
2251 }
2252 if (elms_kind == FAST_SMI_ONLY_ELEMENTS) {
2253 bool dummy = true;
2254 Handle<Map> double_map =
2255 MaybeNull(LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, &dummy));
2256 // In the current implementation, if the DOUBLE map doesn't exist, the
2257 // FAST map can't exist either.
2258 if (double_map.is_null()) return Handle<Map>::null();
2259 Handle<Map> fast_map =
2260 MaybeNull(double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2261 &dummy));
2262 if (!fast_map.is_null() && ContainsMap(candidates, fast_map)) {
2263 return fast_map;
2264 }
2265 if (ContainsMap(candidates, double_map)) return double_map;
2266 }
2267 return Handle<Map>::null();
2268}
2269
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002270static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents,
2271 ElementsKind elements_kind) {
2272 if (descriptor_contents->IsMap()) {
2273 Map* map = Map::cast(descriptor_contents);
2274 if (map->elements_kind() == elements_kind) {
2275 return map;
2276 }
2277 return NULL;
2278 }
2279
2280 FixedArray* map_array = FixedArray::cast(descriptor_contents);
2281 for (int i = 0; i < map_array->length(); ++i) {
2282 Object* current = map_array->get(i);
2283 // Skip undefined slots, they are sentinels for reclaimed maps.
2284 if (!current->IsUndefined()) {
2285 Map* current_map = Map::cast(map_array->get(i));
2286 if (current_map->elements_kind() == elements_kind) {
2287 return current_map;
2288 }
2289 }
2290 }
2291
2292 return NULL;
2293}
2294
2295
2296static MaybeObject* AddElementsTransitionMapToDescriptor(
2297 Object* descriptor_contents,
2298 Map* new_map) {
2299 // Nothing was in the descriptor for an ELEMENTS_TRANSITION,
2300 // simply add the map.
2301 if (descriptor_contents == NULL) {
2302 return new_map;
2303 }
2304
2305 // There was already a map in the descriptor, create a 2-element FixedArray
2306 // to contain the existing map plus the new one.
2307 FixedArray* new_array;
2308 Heap* heap = new_map->GetHeap();
2309 if (descriptor_contents->IsMap()) {
2310 // Must tenure, DescriptorArray expects no new-space objects.
2311 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED);
2312 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2313 return maybe_new_array;
2314 }
2315 new_array->set(0, descriptor_contents);
2316 new_array->set(1, new_map);
2317 return new_array;
2318 }
2319
2320 // The descriptor already contained a list of maps for different ElementKinds
2321 // of ELEMENTS_TRANSITION, first check the existing array for an undefined
2322 // slot, and if that's not available, create a FixedArray to hold the existing
2323 // maps plus the new one and fill it in.
2324 FixedArray* array = FixedArray::cast(descriptor_contents);
2325 for (int i = 0; i < array->length(); ++i) {
2326 if (array->get(i)->IsUndefined()) {
2327 array->set(i, new_map);
2328 return array;
2329 }
2330 }
2331
2332 // Must tenure, DescriptorArray expects no new-space objects.
2333 MaybeObject* maybe_new_array =
2334 heap->AllocateFixedArray(array->length() + 1, TENURED);
2335 if (!maybe_new_array->To<FixedArray>(&new_array)) {
2336 return maybe_new_array;
2337 }
2338 int i = 0;
2339 while (i < array->length()) {
2340 new_array->set(i, array->get(i));
2341 ++i;
2342 }
2343 new_array->set(i, new_map);
2344 return new_array;
2345}
2346
2347
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002348String* Map::elements_transition_sentinel_name() {
2349 return GetHeap()->empty_symbol();
2350}
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002351
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002352
2353Object* Map::GetDescriptorContents(String* sentinel_name,
2354 bool* safe_to_add_transition) {
2355 // Get the cached index for the descriptors lookup, or find and cache it.
2356 DescriptorArray* descriptors = instance_descriptors();
2357 DescriptorLookupCache* cache = GetIsolate()->descriptor_lookup_cache();
2358 int index = cache->Lookup(descriptors, sentinel_name);
2359 if (index == DescriptorLookupCache::kAbsent) {
2360 index = descriptors->Search(sentinel_name);
2361 cache->Update(descriptors, sentinel_name, index);
2362 }
2363 // If the transition already exists, return its descriptor.
2364 if (index != DescriptorArray::kNotFound) {
2365 PropertyDetails details(descriptors->GetDetails(index));
2366 if (details.type() == ELEMENTS_TRANSITION) {
2367 return descriptors->GetValue(index);
2368 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00002369 if (safe_to_add_transition != NULL) {
2370 *safe_to_add_transition = false;
2371 }
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002372 }
2373 }
2374 return NULL;
2375}
2376
2377
2378Map* Map::LookupElementsTransitionMap(ElementsKind elements_kind,
2379 bool* safe_to_add_transition) {
2380 // Special case: indirect SMI->FAST transition (cf. comment in
2381 // AddElementsTransition()).
2382 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2383 elements_kind == FAST_ELEMENTS) {
2384 Map* double_map = this->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS,
2385 safe_to_add_transition);
2386 if (double_map == NULL) return double_map;
2387 return double_map->LookupElementsTransitionMap(FAST_ELEMENTS,
2388 safe_to_add_transition);
2389 }
2390 Object* descriptor_contents = GetDescriptorContents(
2391 elements_transition_sentinel_name(), safe_to_add_transition);
2392 if (descriptor_contents != NULL) {
2393 Map* maybe_transition_map =
2394 GetElementsTransitionMapFromDescriptor(descriptor_contents,
2395 elements_kind);
2396 ASSERT(maybe_transition_map == NULL || maybe_transition_map->IsMap());
2397 return maybe_transition_map;
2398 }
2399 return NULL;
2400}
2401
2402
2403MaybeObject* Map::AddElementsTransition(ElementsKind elements_kind,
2404 Map* transitioned_map) {
2405 // The map transition graph should be a tree, therefore the transition
2406 // from SMI to FAST elements is not done directly, but by going through
2407 // DOUBLE elements first.
2408 if (this->elements_kind() == FAST_SMI_ONLY_ELEMENTS &&
2409 elements_kind == FAST_ELEMENTS) {
2410 bool safe_to_add = true;
2411 Map* double_map = this->LookupElementsTransitionMap(
2412 FAST_DOUBLE_ELEMENTS, &safe_to_add);
2413 // This method is only called when safe_to_add_transition has been found
2414 // to be true earlier.
2415 ASSERT(safe_to_add);
2416
2417 if (double_map == NULL) {
2418 MaybeObject* maybe_map = this->CopyDropTransitions();
2419 if (!maybe_map->To(&double_map)) return maybe_map;
2420 double_map->set_elements_kind(FAST_DOUBLE_ELEMENTS);
2421 MaybeObject* maybe_double_transition = this->AddElementsTransition(
2422 FAST_DOUBLE_ELEMENTS, double_map);
2423 if (maybe_double_transition->IsFailure()) return maybe_double_transition;
2424 }
2425 return double_map->AddElementsTransition(FAST_ELEMENTS, transitioned_map);
2426 }
2427
2428 bool safe_to_add_transition = true;
2429 Object* descriptor_contents = GetDescriptorContents(
2430 elements_transition_sentinel_name(), &safe_to_add_transition);
2431 // This method is only called when safe_to_add_transition has been found
2432 // to be true earlier.
2433 ASSERT(safe_to_add_transition);
2434 MaybeObject* maybe_new_contents =
2435 AddElementsTransitionMapToDescriptor(descriptor_contents,
2436 transitioned_map);
2437 Object* new_contents;
2438 if (!maybe_new_contents->ToObject(&new_contents)) {
2439 return maybe_new_contents;
2440 }
2441
2442 ElementsTransitionDescriptor desc(elements_transition_sentinel_name(),
2443 new_contents);
2444 Object* new_descriptors;
2445 MaybeObject* maybe_new_descriptors =
2446 instance_descriptors()->CopyInsert(&desc, KEEP_TRANSITIONS);
2447 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2448 return maybe_new_descriptors;
2449 }
2450 set_instance_descriptors(DescriptorArray::cast(new_descriptors));
2451 return this;
2452}
2453
2454
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002455Handle<Map> JSObject::GetElementsTransitionMap(Handle<JSObject> object,
2456 ElementsKind to_kind) {
2457 Isolate* isolate = object->GetIsolate();
2458 CALL_HEAP_FUNCTION(isolate,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002459 object->GetElementsTransitionMap(isolate, to_kind),
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002460 Map);
2461}
2462
2463
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002464MaybeObject* JSObject::GetElementsTransitionMapSlow(ElementsKind to_kind) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002465 Map* current_map = map();
2466 ElementsKind from_kind = current_map->elements_kind();
2467
2468 if (from_kind == to_kind) return current_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002469
2470 // Only objects with FastProperties can have DescriptorArrays and can track
2471 // element-related maps. Also don't add descriptors to maps that are shared.
2472 bool safe_to_add_transition = HasFastProperties() &&
2473 !current_map->IsUndefined() &&
2474 !current_map->is_shared();
2475
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002476 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps caused by objects
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002477 // with elements that switch back and forth between dictionary and fast
2478 // element mode.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002479 if (from_kind == DICTIONARY_ELEMENTS && to_kind == FAST_ELEMENTS) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002480 safe_to_add_transition = false;
2481 }
2482
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002483 if (safe_to_add_transition) {
2484 // It's only safe to manipulate the descriptor array if it would be
2485 // safe to add a transition.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002486 Map* maybe_transition_map = current_map->LookupElementsTransitionMap(
2487 to_kind, &safe_to_add_transition);
2488 if (maybe_transition_map != NULL) {
2489 return maybe_transition_map;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002490 }
2491 }
2492
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002493 Map* new_map = NULL;
2494
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002495 // No transition to an existing map for the given ElementsKind. Make a new
2496 // one.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002497 { MaybeObject* maybe_map = current_map->CopyDropTransitions();
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002498 if (!maybe_map->To(&new_map)) return maybe_map;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002499 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002500
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002501 new_map->set_elements_kind(to_kind);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002502
2503 // Only remember the map transition if the object's map is NOT equal to the
2504 // global object_function's map and there is not an already existing
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00002505 // non-matching element transition.
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002506 Context* global_context = GetIsolate()->context()->global_context();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002507 bool allow_map_transition = safe_to_add_transition &&
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002508 (global_context->object_function()->map() != map());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002509 if (allow_map_transition) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002510 MaybeObject* maybe_transition =
2511 current_map->AddElementsTransition(to_kind, new_map);
2512 if (maybe_transition->IsFailure()) return maybe_transition;
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002513 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002514 return new_map;
2515}
2516
2517
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002518void JSObject::LocalLookupRealNamedProperty(String* name,
2519 LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002520 if (IsJSGlobalProxy()) {
2521 Object* proto = GetPrototype();
2522 if (proto->IsNull()) return result->NotFound();
2523 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002524 // A GlobalProxy's prototype should always be a proper JSObject.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002525 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2526 }
2527
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002528 if (HasFastProperties()) {
2529 LookupInDescriptor(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002530 if (result->IsFound()) {
2531 // A property, a map transition or a null descriptor was found.
2532 // We return all of these result types because
2533 // LocalLookupRealNamedProperty is used when setting properties
2534 // where map transitions and null descriptors are handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002535 ASSERT(result->holder() == this && result->type() != NORMAL);
2536 // Disallow caching for uninitialized constants. These can only
2537 // occur as fields.
2538 if (result->IsReadOnly() && result->type() == FIELD &&
ager@chromium.org7c537e22008-10-16 08:43:32 +00002539 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002540 result->DisallowCaching();
2541 }
2542 return;
2543 }
2544 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002545 int entry = property_dictionary()->FindEntry(name);
2546 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002547 Object* value = property_dictionary()->ValueAt(entry);
2548 if (IsGlobalObject()) {
2549 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2550 if (d.IsDeleted()) {
2551 result->NotFound();
2552 return;
2553 }
2554 value = JSGlobalPropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002555 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002556 // Make sure to disallow caching for uninitialized constants
2557 // found in the dictionary-mode objects.
2558 if (value->IsTheHole()) result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002559 result->DictionaryResult(this, entry);
2560 return;
2561 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002562 }
2563 result->NotFound();
2564}
2565
2566
2567void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2568 LocalLookupRealNamedProperty(name, result);
2569 if (result->IsProperty()) return;
2570
2571 LookupRealNamedPropertyInPrototypes(name, result);
2572}
2573
2574
2575void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2576 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002577 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002578 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002579 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002580 pt = JSObject::cast(pt)->GetPrototype()) {
2581 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002582 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002583 }
2584 result->NotFound();
2585}
2586
2587
2588// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002589MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2590 LookupResult* result,
2591 String* name,
2592 Object* value,
2593 bool check_prototype,
2594 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002595 if (check_prototype && !result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002596 LookupCallbackSetterInPrototypes(name, result);
2597 }
2598
2599 if (result->IsProperty()) {
2600 if (!result->IsReadOnly()) {
2601 switch (result->type()) {
2602 case CALLBACKS: {
2603 Object* obj = result->GetCallbackObject();
2604 if (obj->IsAccessorInfo()) {
2605 AccessorInfo* info = AccessorInfo::cast(obj);
2606 if (info->all_can_write()) {
2607 return SetPropertyWithCallback(result->GetCallbackObject(),
2608 name,
2609 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002610 result->holder(),
2611 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002612 }
2613 }
2614 break;
2615 }
2616 case INTERCEPTOR: {
2617 // Try lookup real named properties. Note that only property can be
2618 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002619 LookupResult r(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002620 LookupRealNamedProperty(name, &r);
2621 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002622 return SetPropertyWithFailedAccessCheck(&r,
2623 name,
2624 value,
2625 check_prototype,
2626 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002627 }
2628 break;
2629 }
2630 default: {
2631 break;
2632 }
2633 }
2634 }
2635 }
2636
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002637 Isolate* isolate = GetIsolate();
2638 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002639 Handle<Object> value_handle(value);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002640 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002641 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002642}
2643
2644
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002645MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2646 String* key,
2647 Object* value,
2648 PropertyAttributes attributes,
2649 StrictModeFlag strict_mode) {
2650 if (result->IsFound() && result->type() == HANDLER) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002651 return result->proxy()->SetPropertyWithHandler(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002652 key, value, attributes, strict_mode);
2653 } else {
2654 return JSObject::cast(this)->SetPropertyForResult(
2655 result, key, value, attributes, strict_mode);
2656 }
2657}
2658
2659
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002660bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2661 Isolate* isolate = GetIsolate();
2662 HandleScope scope(isolate);
2663 Handle<Object> receiver(this);
2664 Handle<Object> name(name_raw);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002665
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002666 Handle<Object> args[] = { name };
2667 Handle<Object> result = CallTrap(
2668 "has", isolate->derived_has_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002669 if (isolate->has_pending_exception()) return Failure::Exception();
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002670
2671 return result->ToBoolean()->IsTrue();
2672}
2673
2674
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002675MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2676 String* name_raw,
2677 Object* value_raw,
2678 PropertyAttributes attributes,
2679 StrictModeFlag strict_mode) {
2680 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002681 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002682 Handle<Object> receiver(this);
2683 Handle<Object> name(name_raw);
2684 Handle<Object> value(value_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002685
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002686 Handle<Object> args[] = { receiver, name, value };
2687 CallTrap("set", isolate->derived_set_trap(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002688 if (isolate->has_pending_exception()) return Failure::Exception();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002689
2690 return *value;
2691}
2692
2693
2694MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
2695 String* name_raw,
2696 Object* value_raw,
2697 PropertyAttributes attributes,
2698 StrictModeFlag strict_mode,
2699 bool* found) {
2700 *found = true; // except where defined otherwise...
2701 Isolate* isolate = GetHeap()->isolate();
2702 Handle<JSProxy> proxy(this);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002703 Handle<Object> handler(this->handler()); // Trap might morph proxy.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002704 Handle<String> name(name_raw);
2705 Handle<Object> value(value_raw);
2706 Handle<Object> args[] = { name };
2707 Handle<Object> result = proxy->CallTrap(
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002708 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002709 if (isolate->has_pending_exception()) return Failure::Exception();
2710
2711 if (!result->IsUndefined()) {
2712 // The proxy handler cares about this property.
2713 // Check whether it is virtualized as an accessor.
2714 // Emulate [[GetProperty]] semantics for proxies.
2715 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002716 Handle<Object> argv[] = { result };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002717 Handle<Object> desc =
2718 Execution::Call(isolate->to_complete_property_descriptor(), result,
2719 ARRAY_SIZE(argv), argv, &has_pending_exception);
2720 if (has_pending_exception) return Failure::Exception();
2721
2722 Handle<String> conf_name =
2723 isolate->factory()->LookupAsciiSymbol("configurable_");
2724 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_name));
2725 ASSERT(!isolate->has_pending_exception());
2726 if (configurable->IsFalse()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002727 Handle<String> trap =
2728 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2729 Handle<Object> args[] = { handler, trap, name };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002730 Handle<Object> error = isolate->factory()->NewTypeError(
2731 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
2732 return isolate->Throw(*error);
2733 }
2734 ASSERT(configurable->IsTrue());
2735
2736 // Check for AccessorDescriptor.
2737 Handle<String> set_name = isolate->factory()->LookupAsciiSymbol("set_");
2738 Handle<Object> setter(v8::internal::GetProperty(desc, set_name));
2739 ASSERT(!isolate->has_pending_exception());
2740 if (!setter->IsUndefined()) {
2741 // We have a setter -- invoke it.
2742 // TODO(rossberg): nicer would be to cast to some JSCallable here...
2743 return proxy->SetPropertyWithDefinedSetter(
2744 JSReceiver::cast(*setter), *value);
2745 } else {
2746 Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
2747 Handle<Object> getter(v8::internal::GetProperty(desc, get_name));
2748 ASSERT(!isolate->has_pending_exception());
2749 if (!getter->IsUndefined()) {
2750 // We have a getter but no setter -- the property may not be
2751 // written. In strict mode, throw an error.
2752 if (strict_mode == kNonStrictMode) return *value;
2753 Handle<Object> args[] = { name, proxy };
2754 Handle<Object> error = isolate->factory()->NewTypeError(
2755 "no_setter_in_callback", HandleVector(args, ARRAY_SIZE(args)));
2756 return isolate->Throw(*error);
2757 }
2758 }
2759 // Fall-through.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002760 }
2761
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002762 // The proxy does not define the property as an accessor.
2763 *found = false;
ager@chromium.org04921a82011-06-27 13:21:41 +00002764 return *value;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002765}
2766
2767
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002768MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2769 String* name_raw, DeleteMode mode) {
2770 Isolate* isolate = GetIsolate();
2771 HandleScope scope(isolate);
2772 Handle<Object> receiver(this);
2773 Handle<Object> name(name_raw);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002774
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002775 Handle<Object> args[] = { name };
2776 Handle<Object> result = CallTrap(
2777 "delete", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002778 if (isolate->has_pending_exception()) return Failure::Exception();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002779
2780 Object* bool_result = result->ToBoolean();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002781 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2782 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2783 Handle<Object> args[] = { Handle<Object>(handler()), trap_name };
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002784 Handle<Object> error = isolate->factory()->NewTypeError(
2785 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2786 isolate->Throw(*error);
2787 return Failure::Exception();
2788 }
2789 return bool_result;
2790}
2791
2792
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002793MUST_USE_RESULT MaybeObject* JSProxy::DeleteElementWithHandler(
2794 uint32_t index,
2795 DeleteMode mode) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002796 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002797 HandleScope scope(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002798 Handle<String> name = isolate->factory()->Uint32ToString(index);
2799 return JSProxy::DeletePropertyWithHandler(*name, mode);
2800}
2801
2802
2803MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2804 JSReceiver* receiver_raw,
2805 String* name_raw) {
2806 Isolate* isolate = GetIsolate();
2807 HandleScope scope(isolate);
2808 Handle<JSProxy> proxy(this);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002809 Handle<Object> handler(this->handler()); // Trap might morph proxy.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002810 Handle<JSReceiver> receiver(receiver_raw);
2811 Handle<Object> name(name_raw);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002812
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002813 Handle<Object> args[] = { name };
2814 Handle<Object> result = CallTrap(
2815 "getPropertyDescriptor", Handle<Object>(), ARRAY_SIZE(args), args);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002816 if (isolate->has_pending_exception()) return NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002817
2818 if (result->IsUndefined()) return ABSENT;
2819
2820 bool has_pending_exception;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002821 Handle<Object> argv[] = { result };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002822 Handle<Object> desc =
2823 Execution::Call(isolate->to_complete_property_descriptor(), result,
2824 ARRAY_SIZE(argv), argv, &has_pending_exception);
2825 if (has_pending_exception) return NONE;
2826
2827 // Convert result to PropertyAttributes.
2828 Handle<String> enum_n = isolate->factory()->LookupAsciiSymbol("enumerable");
2829 Handle<Object> enumerable(v8::internal::GetProperty(desc, enum_n));
2830 if (isolate->has_pending_exception()) return NONE;
2831 Handle<String> conf_n = isolate->factory()->LookupAsciiSymbol("configurable");
2832 Handle<Object> configurable(v8::internal::GetProperty(desc, conf_n));
2833 if (isolate->has_pending_exception()) return NONE;
2834 Handle<String> writ_n = isolate->factory()->LookupAsciiSymbol("writable");
2835 Handle<Object> writable(v8::internal::GetProperty(desc, writ_n));
2836 if (isolate->has_pending_exception()) return NONE;
2837
2838 if (configurable->IsFalse()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002839 Handle<String> trap =
2840 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2841 Handle<Object> args[] = { handler, trap, name };
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002842 Handle<Object> error = isolate->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002843 "proxy_prop_not_configurable", HandleVector(args, ARRAY_SIZE(args)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002844 isolate->Throw(*error);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002845 return NONE;
2846 }
2847
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002848 int attributes = NONE;
2849 if (enumerable->ToBoolean()->IsFalse()) attributes |= DONT_ENUM;
2850 if (configurable->ToBoolean()->IsFalse()) attributes |= DONT_DELETE;
2851 if (writable->ToBoolean()->IsFalse()) attributes |= READ_ONLY;
2852 return static_cast<PropertyAttributes>(attributes);
2853}
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002854
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002855
2856MUST_USE_RESULT PropertyAttributes JSProxy::GetElementAttributeWithHandler(
2857 JSReceiver* receiver,
2858 uint32_t index) {
2859 Isolate* isolate = GetIsolate();
2860 HandleScope scope(isolate);
2861 Handle<String> name = isolate->factory()->Uint32ToString(index);
2862 return GetPropertyAttributeWithHandler(receiver, *name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002863}
2864
2865
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002866void JSProxy::Fix() {
2867 Isolate* isolate = GetIsolate();
2868 HandleScope scope(isolate);
2869 Handle<JSProxy> self(this);
2870
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002871 // Save identity hash.
2872 MaybeObject* maybe_hash = GetIdentityHash(OMIT_CREATION);
2873
lrn@chromium.org34e60782011-09-15 07:25:40 +00002874 if (IsJSFunctionProxy()) {
2875 isolate->factory()->BecomeJSFunction(self);
2876 // Code will be set on the JavaScript side.
2877 } else {
2878 isolate->factory()->BecomeJSObject(self);
2879 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002880 ASSERT(self->IsJSObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002881
2882 // Inherit identity, if it was present.
2883 Object* hash;
2884 if (maybe_hash->To<Object>(&hash) && hash->IsSmi()) {
2885 Handle<JSObject> new_self(JSObject::cast(*self));
2886 isolate->factory()->SetIdentityHash(new_self, hash);
2887 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002888}
2889
2890
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002891MUST_USE_RESULT Handle<Object> JSProxy::CallTrap(const char* name,
2892 Handle<Object> derived,
2893 int argc,
2894 Handle<Object> argv[]) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002895 Isolate* isolate = GetIsolate();
2896 Handle<Object> handler(this->handler());
2897
2898 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol(name);
2899 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2900 if (isolate->has_pending_exception()) return trap;
2901
2902 if (trap->IsUndefined()) {
2903 if (derived.is_null()) {
2904 Handle<Object> args[] = { handler, trap_name };
2905 Handle<Object> error = isolate->factory()->NewTypeError(
2906 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2907 isolate->Throw(*error);
2908 return Handle<Object>();
2909 }
2910 trap = Handle<Object>(derived);
2911 }
2912
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002913 bool threw;
2914 return Execution::Call(trap, handler, argc, argv, &threw);
2915}
2916
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002917
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002918MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002919 String* name,
2920 Object* value,
2921 PropertyAttributes attributes,
2922 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002924 // Make sure that the top context does not change when doing callbacks or
2925 // interceptor calls.
2926 AssertNoContextChange ncc;
2927
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002928 // Optimization for 2-byte strings often used as keys in a decompression
2929 // dictionary. We make these short keys into symbols to avoid constantly
2930 // reallocating them.
2931 if (!name->IsSymbol() && name->length() <= 2) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002932 Object* symbol_version;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002934 if (maybe_symbol_version->ToObject(&symbol_version)) {
2935 name = String::cast(symbol_version);
2936 }
2937 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002938 }
2939
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002940 // Check access rights if needed.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002941 if (IsAccessCheckNeeded()) {
2942 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2943 return SetPropertyWithFailedAccessCheck(
2944 result, name, value, true, strict_mode);
2945 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002946 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002947
2948 if (IsJSGlobalProxy()) {
2949 Object* proto = GetPrototype();
2950 if (proto->IsNull()) return value;
2951 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002952 return JSObject::cast(proto)->SetPropertyForResult(
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002953 result, name, value, attributes, strict_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002954 }
2955
ager@chromium.org32912102009-01-16 10:38:43 +00002956 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002957 bool found = false;
2958 MaybeObject* result_object;
2959 result_object = SetPropertyWithCallbackSetterInPrototypes(name,
2960 value,
2961 attributes,
2962 &found,
2963 strict_mode);
2964 if (found) return result_object;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002965 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002966
2967 // At this point, no GC should have happened, as this would invalidate
2968 // 'result', which we cannot handlify!
2969
ager@chromium.org5c838252010-02-19 08:53:10 +00002970 if (!result->IsFound()) {
2971 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002972 return AddProperty(name, value, attributes, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002973 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002974 if (result->IsReadOnly() && result->IsProperty()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002975 if (strict_mode == kStrictMode) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002976 Handle<JSObject> self(this);
2977 Handle<String> hname(name);
2978 Handle<Object> args[] = { hname, self };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002979 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002980 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args))));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002981 } else {
2982 return value;
2983 }
2984 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002985 // This is a real property that is not read-only, or it is a
2986 // transition or null descriptor and there are no setters in the prototypes.
2987 switch (result->type()) {
2988 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002989 return SetNormalizedProperty(result, value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002990 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002991 return FastPropertyAtPut(result->GetFieldIndex(), value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002992 case MAP_TRANSITION:
2993 if (attributes == result->GetAttributes()) {
2994 // Only use map transition if the attributes match.
2995 return AddFastPropertyUsingMap(result->GetTransitionMap(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996 name,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002997 value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002998 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002999 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003000 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003001 // Only replace the function if necessary.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003002 if (value == result->GetConstantFunction()) return value;
3003 // Preserve the attributes of this existing property.
3004 attributes = result->GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003005 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003006 case CALLBACKS:
3007 return SetPropertyWithCallback(result->GetCallbackObject(),
3008 name,
3009 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003010 result->holder(),
3011 strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003012 case INTERCEPTOR:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003013 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003014 case CONSTANT_TRANSITION: {
3015 // If the same constant function is being added we can simply
3016 // transition to the target map.
3017 Map* target_map = result->GetTransitionMap();
3018 DescriptorArray* target_descriptors = target_map->instance_descriptors();
3019 int number = target_descriptors->SearchWithCache(name);
3020 ASSERT(number != DescriptorArray::kNotFound);
3021 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
3022 JSFunction* function =
3023 JSFunction::cast(target_descriptors->GetValue(number));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003024 if (value == function) {
3025 set_map(target_map);
3026 return value;
3027 }
3028 // Otherwise, replace with a MAP_TRANSITION to a new map with a
3029 // FIELD, even if the value is a constant function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003030 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003031 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003032 case NULL_DESCRIPTOR:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003033 case ELEMENTS_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00003034 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003035 case HANDLER:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003036 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00003037 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003038 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003039 UNREACHABLE(); // keep the compiler happy
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003040 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003041}
3042
3043
3044// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003045// present, add it with attributes NONE. This code is an exact clone of
3046// SetProperty, with the check for IsReadOnly and the check for a
3047// callback setter removed. The two lines looking up the LookupResult
3048// result are also added. If one of the functions is changed, the other
3049// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00003050// Note that this method cannot be used to set the prototype of a function
3051// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
3052// doesn't handle function prototypes correctly.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003053Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
3054 Handle<JSObject> object,
3055 Handle<String> key,
3056 Handle<Object> value,
3057 PropertyAttributes attributes) {
3058 CALL_HEAP_FUNCTION(
3059 object->GetIsolate(),
3060 object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
3061 Object);
3062}
3063
3064
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003065MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003066 String* name,
3067 Object* value,
3068 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003069
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003070 // Make sure that the top context does not change when doing callbacks or
3071 // interceptor calls.
3072 AssertNoContextChange ncc;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003073 Isolate* isolate = GetIsolate();
3074 LookupResult result(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003075 LocalLookup(name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003077 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003078 if (!isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003079 return SetPropertyWithFailedAccessCheck(&result,
3080 name,
3081 value,
3082 false,
3083 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003085 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003086
3087 if (IsJSGlobalProxy()) {
3088 Object* proto = GetPrototype();
3089 if (proto->IsNull()) return value;
3090 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003091 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003092 name,
3093 value,
3094 attributes);
3095 }
3096
ager@chromium.org7c537e22008-10-16 08:43:32 +00003097 // Check for accessor in prototype chain removed here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00003098 if (!result.IsFound()) {
3099 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003100 return AddProperty(name, value, attributes, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003101 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003102
ager@chromium.org5c838252010-02-19 08:53:10 +00003103 PropertyDetails details = PropertyDetails(attributes, NORMAL);
3104
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003105 // Check of IsReadOnly removed from here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00003106 switch (result.type()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003107 case NORMAL:
ager@chromium.org5c838252010-02-19 08:53:10 +00003108 return SetNormalizedProperty(name, value, details);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003109 case FIELD:
ager@chromium.org5c838252010-02-19 08:53:10 +00003110 return FastPropertyAtPut(result.GetFieldIndex(), value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003111 case MAP_TRANSITION:
ager@chromium.org5c838252010-02-19 08:53:10 +00003112 if (attributes == result.GetAttributes()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003113 // Only use map transition if the attributes match.
ager@chromium.org5c838252010-02-19 08:53:10 +00003114 return AddFastPropertyUsingMap(result.GetTransitionMap(),
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003115 name,
3116 value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003117 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003118 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003119 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003120 // Only replace the function if necessary.
ager@chromium.org5c838252010-02-19 08:53:10 +00003121 if (value == result.GetConstantFunction()) return value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00003122 // Preserve the attributes of this existing property.
ager@chromium.org5c838252010-02-19 08:53:10 +00003123 attributes = result.GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003124 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003125 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003126 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003127 // Override callback in clone
3128 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003129 case CONSTANT_TRANSITION:
3130 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
3131 // if the value is a function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003132 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003133 case NULL_DESCRIPTOR:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003134 case ELEMENTS_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00003135 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003136 case HANDLER:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003137 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00003138 return value;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003139 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00003140 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003141 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003142}
3143
3144
3145PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
3146 JSObject* receiver,
3147 String* name,
3148 bool continue_search) {
3149 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003150 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003151 LocalLookupRealNamedProperty(name, &result);
kasper.lund44510672008-07-25 07:37:58 +00003152 if (result.IsProperty()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003153
3154 if (continue_search) {
3155 // Continue searching via the prototype chain.
3156 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003157 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003158 return JSObject::cast(pt)->
3159 GetPropertyAttributeWithReceiver(receiver, name);
3160 }
3161 }
3162 return ABSENT;
3163}
3164
3165
3166PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
3167 JSObject* receiver,
3168 String* name,
3169 bool continue_search) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003170 Isolate* isolate = GetIsolate();
3171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172 // Make sure that the top context does not change when doing
3173 // callbacks or interceptor calls.
3174 AssertNoContextChange ncc;
3175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003176 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003177 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3178 Handle<JSObject> receiver_handle(receiver);
3179 Handle<JSObject> holder_handle(this);
3180 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003181 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003182 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003183 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003184 v8::NamedPropertyQuery query =
3185 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003186 LOG(isolate,
3187 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003188 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003189 {
3190 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003191 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003192 result = query(v8::Utils::ToLocal(name_handle), info);
3193 }
3194 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003195 ASSERT(result->IsInt32());
3196 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003197 }
3198 } else if (!interceptor->getter()->IsUndefined()) {
3199 v8::NamedPropertyGetter getter =
3200 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003201 LOG(isolate,
3202 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003203 v8::Handle<v8::Value> result;
3204 {
3205 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003206 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003207 result = getter(v8::Utils::ToLocal(name_handle), info);
3208 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003209 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003210 }
3211 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
3212 *name_handle,
3213 continue_search);
3214}
3215
3216
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003217PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
3218 JSReceiver* receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003219 String* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003220 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003221 if (IsJSObject() && key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003222 return JSObject::cast(this)->HasElementWithReceiver(receiver, index)
3223 ? NONE : ABSENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003224 }
3225 // Named property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003226 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003227 Lookup(key, &result);
3228 return GetPropertyAttribute(receiver, &result, key, true);
3229}
3230
3231
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003232PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
3233 LookupResult* result,
3234 String* name,
3235 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003236 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003237 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003238 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003239 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003240 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
3241 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
3242 receiver, result, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003243 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003244 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003245 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003246 switch (result->type()) {
3247 case NORMAL: // fall through
3248 case FIELD:
3249 case CONSTANT_FUNCTION:
3250 case CALLBACKS:
3251 return result->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003252 case HANDLER: {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003253 return JSProxy::cast(result->proxy())->GetPropertyAttributeWithHandler(
3254 receiver, name);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003255 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003256 case INTERCEPTOR:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003257 return result->holder()->GetPropertyAttributeWithInterceptor(
3258 JSObject::cast(receiver), name, continue_search);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003259 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003260 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003261 }
3262 }
3263 return ABSENT;
3264}
3265
3266
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003267PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003269 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003270 if (IsJSObject() && name->AsArrayIndex(&index)) {
3271 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003272 return ABSENT;
3273 }
3274 // Named property.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003275 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003276 LocalLookup(name, &result);
3277 return GetPropertyAttribute(this, &result, name, false);
3278}
3279
3280
lrn@chromium.org303ada72010-10-27 09:33:13 +00003281MaybeObject* NormalizedMapCache::Get(JSObject* obj,
3282 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003283 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003284 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003285 int index = fast->Hash() % kEntries;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003286 Object* result = get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003287 if (result->IsMap() &&
3288 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003289#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003290 if (FLAG_verify_heap) {
3291 Map::cast(result)->SharedMapVerify();
3292 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003293 if (FLAG_enable_slow_asserts) {
3294 // The cached map should match newly created normalized map bit-by-bit.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003295 Object* fresh;
3296 { MaybeObject* maybe_fresh =
3297 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3298 if (maybe_fresh->ToObject(&fresh)) {
3299 ASSERT(memcmp(Map::cast(fresh)->address(),
3300 Map::cast(result)->address(),
3301 Map::kSize) == 0);
3302 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003303 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003304 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003305#endif
3306 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003307 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003308
lrn@chromium.org303ada72010-10-27 09:33:13 +00003309 { MaybeObject* maybe_result =
3310 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
3311 if (!maybe_result->ToObject(&result)) return maybe_result;
3312 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003313 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003314 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003315
3316 return result;
3317}
3318
3319
ricow@chromium.org65fae842010-08-25 15:26:24 +00003320void NormalizedMapCache::Clear() {
3321 int entries = length();
3322 for (int i = 0; i != entries; i++) {
3323 set_undefined(i);
3324 }
3325}
3326
3327
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003328void JSObject::UpdateMapCodeCache(Handle<JSObject> object,
3329 Handle<String> name,
3330 Handle<Code> code) {
3331 Isolate* isolate = object->GetIsolate();
3332 CALL_HEAP_FUNCTION_VOID(isolate,
3333 object->UpdateMapCodeCache(*name, *code));
3334}
3335
3336
lrn@chromium.org303ada72010-10-27 09:33:13 +00003337MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003338 if (map()->is_shared()) {
3339 // Fast case maps are never marked as shared.
3340 ASSERT(!HasFastProperties());
3341 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003342 Object* obj;
3343 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
3344 UNIQUE_NORMALIZED_MAP);
3345 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3346 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003347 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003348
3349 set_map(Map::cast(obj));
3350 }
3351 return map()->UpdateCodeCache(name, code);
3352}
3353
3354
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003355void JSObject::NormalizeProperties(Handle<JSObject> object,
3356 PropertyNormalizationMode mode,
3357 int expected_additional_properties) {
3358 CALL_HEAP_FUNCTION_VOID(object->GetIsolate(),
3359 object->NormalizeProperties(
3360 mode, expected_additional_properties));
3361}
3362
3363
lrn@chromium.org303ada72010-10-27 09:33:13 +00003364MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
3365 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003366 if (!HasFastProperties()) return this;
3367
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003368 // The global object is always normalized.
3369 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003370 // JSGlobalProxy must never be normalized
3371 ASSERT(!IsJSGlobalProxy());
3372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003373 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003374
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003375 // Allocate new content.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003376 int property_count = map_of_this->NumberOfDescribedProperties();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003377 if (expected_additional_properties > 0) {
3378 property_count += expected_additional_properties;
3379 } else {
3380 property_count += 2; // Make space for two more properties.
3381 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003382 Object* obj;
3383 { MaybeObject* maybe_obj =
3384 StringDictionary::Allocate(property_count);
3385 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3386 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003387 StringDictionary* dictionary = StringDictionary::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003389 DescriptorArray* descs = map_of_this->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003390 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003391 PropertyDetails details(descs->GetDetails(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003392 switch (details.type()) {
3393 case CONSTANT_FUNCTION: {
3394 PropertyDetails d =
3395 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003396 Object* value = descs->GetConstantFunction(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003397 Object* result;
3398 { MaybeObject* maybe_result =
3399 dictionary->Add(descs->GetKey(i), value, d);
3400 if (!maybe_result->ToObject(&result)) return maybe_result;
3401 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003402 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003403 break;
3404 }
3405 case FIELD: {
3406 PropertyDetails d =
3407 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003408 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003409 Object* result;
3410 { MaybeObject* maybe_result =
3411 dictionary->Add(descs->GetKey(i), value, d);
3412 if (!maybe_result->ToObject(&result)) return maybe_result;
3413 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003414 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 break;
3416 }
3417 case CALLBACKS: {
3418 PropertyDetails d =
3419 PropertyDetails(details.attributes(), CALLBACKS, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003420 Object* value = descs->GetCallbacksObject(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003421 Object* result;
3422 { MaybeObject* maybe_result =
3423 dictionary->Add(descs->GetKey(i), value, d);
3424 if (!maybe_result->ToObject(&result)) return maybe_result;
3425 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003426 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427 break;
3428 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003429 case MAP_TRANSITION:
3430 case CONSTANT_TRANSITION:
3431 case NULL_DESCRIPTOR:
3432 case INTERCEPTOR:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00003433 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003434 break;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003435 case HANDLER:
3436 case NORMAL:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003437 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +00003438 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439 }
3440 }
3441
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003442 Heap* current_heap = GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 // Copy the next enumeration index from instance descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003445 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003446 dictionary->SetNextEnumerationIndex(index);
3447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003448 { MaybeObject* maybe_obj =
3449 current_heap->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003450 normalized_map_cache()->Get(this, mode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003451 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3452 }
ager@chromium.org32912102009-01-16 10:38:43 +00003453 Map* new_map = Map::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
ager@chromium.org32912102009-01-16 10:38:43 +00003455 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003456 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00003457
3458 // Resize the object in the heap if necessary.
3459 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003460 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003461 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003462 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
3463 instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003464 if (Marking::IsBlack(Marking::MarkBitFrom(this))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003465 MemoryChunk::IncrementLiveBytesFromMutator(this->address(),
3466 -instance_size_delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003467 }
3468
ricow@chromium.org65fae842010-08-25 15:26:24 +00003469
ager@chromium.org32912102009-01-16 10:38:43 +00003470 set_map(new_map);
danno@chromium.org40cb8782011-05-25 07:58:50 +00003471 new_map->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003473 set_properties(dictionary);
3474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003475 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476
3477#ifdef DEBUG
3478 if (FLAG_trace_normalization) {
3479 PrintF("Object properties have been normalized:\n");
3480 Print();
3481 }
3482#endif
3483 return this;
3484}
3485
3486
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003487void JSObject::TransformToFastProperties(Handle<JSObject> object,
3488 int unused_property_fields) {
3489 CALL_HEAP_FUNCTION_VOID(
3490 object->GetIsolate(),
3491 object->TransformToFastProperties(unused_property_fields));
3492}
3493
3494
lrn@chromium.org303ada72010-10-27 09:33:13 +00003495MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003497 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003498 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003499 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500}
3501
3502
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003503Handle<SeededNumberDictionary> JSObject::NormalizeElements(
3504 Handle<JSObject> object) {
3505 CALL_HEAP_FUNCTION(object->GetIsolate(),
3506 object->NormalizeElements(),
3507 SeededNumberDictionary);
3508}
3509
3510
lrn@chromium.org303ada72010-10-27 09:33:13 +00003511MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003512 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00003513
whesse@chromium.org7b260152011-06-20 15:33:18 +00003514 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003515 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003516 Map* old_map = array->map();
3517 bool is_arguments =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003518 (old_map == old_map->GetHeap()->non_strict_arguments_elements_map());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003519 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003520 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00003521 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003522 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003524 ASSERT(HasFastElements() ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003525 HasFastSmiOnlyElements() ||
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003526 HasFastDoubleElements() ||
3527 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00003528 // Compute the effective length and allocate a new backing store.
3529 int length = IsJSArray()
3530 ? Smi::cast(JSArray::cast(this)->length())->value()
3531 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00003532 int old_capacity = 0;
3533 int used_elements = 0;
3534 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003535 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003536 { Object* object;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003537 MaybeObject* maybe = SeededNumberDictionary::Allocate(used_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003538 if (!maybe->ToObject(&object)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003539 dictionary = SeededNumberDictionary::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003540 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003541
3542 // Copy the elements to the new backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003543 bool has_double_elements = array->IsFixedDoubleArray();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544 for (int i = 0; i < length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003545 Object* value = NULL;
3546 if (has_double_elements) {
3547 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
3548 if (double_array->is_the_hole(i)) {
3549 value = GetIsolate()->heap()->the_hole_value();
3550 } else {
3551 // Objects must be allocated in the old object space, since the
3552 // overall number of HeapNumbers needed for the conversion might
3553 // exceed the capacity of new space, and we would fail repeatedly
3554 // trying to convert the FixedDoubleArray.
3555 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003556 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003557 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003558 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003559 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003560 ASSERT(old_map->has_fast_elements() ||
3561 old_map->has_fast_smi_only_elements());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003562 value = FixedArray::cast(array)->get(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003563 }
3564 PropertyDetails details = PropertyDetails(NONE, NORMAL);
3565 if (!value->IsTheHole()) {
3566 Object* result;
3567 MaybeObject* maybe_result =
3568 dictionary->AddNumberEntry(i, value, details);
3569 if (!maybe_result->ToObject(&result)) return maybe_result;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003570 dictionary = SeededNumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 }
3572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003573
whesse@chromium.org7b260152011-06-20 15:33:18 +00003574 // Switch to using the dictionary as the backing storage for elements.
3575 if (is_arguments) {
3576 FixedArray::cast(elements())->set(1, dictionary);
3577 } else {
3578 // Set the new map first to satify the elements type assert in
3579 // set_elements().
3580 Object* new_map;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00003581 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(),
3582 DICTIONARY_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00003583 if (!maybe->ToObject(&new_map)) return maybe;
3584 set_map(Map::cast(new_map));
3585 set_elements(dictionary);
3586 }
3587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003588 old_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
3589 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590
3591#ifdef DEBUG
3592 if (FLAG_trace_normalization) {
3593 PrintF("Object elements have been normalized:\n");
3594 Print();
3595 }
3596#endif
3597
whesse@chromium.org7b260152011-06-20 15:33:18 +00003598 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3599 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600}
3601
3602
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003603Smi* JSReceiver::GenerateIdentityHash() {
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003604 Isolate* isolate = GetIsolate();
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003605
3606 int hash_value;
3607 int attempts = 0;
3608 do {
3609 // Generate a random 32-bit hash value but limit range to fit
3610 // within a smi.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003611 hash_value = V8::RandomPrivate(isolate) & Smi::kMaxValue;
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003612 attempts++;
3613 } while (hash_value == 0 && attempts < 30);
3614 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3615
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003616 return Smi::FromInt(hash_value);
3617}
3618
3619
3620MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) {
3621 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3622 hash);
3623 if (maybe->IsFailure()) return maybe;
3624 return this;
3625}
3626
3627
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003628int JSObject::GetIdentityHash(Handle<JSObject> obj) {
3629 CALL_AND_RETRY(obj->GetIsolate(),
3630 obj->GetIdentityHash(ALLOW_CREATION),
3631 return Smi::cast(__object__)->value(),
3632 return 0);
3633}
3634
3635
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003636MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) {
3637 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol());
3638 if (stored_value->IsSmi()) return stored_value;
3639
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003640 // Do not generate permanent identity hash code if not requested.
3641 if (flag == OMIT_CREATION) return GetHeap()->undefined_value();
3642
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003643 Smi* hash = GenerateIdentityHash();
3644 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(),
3645 hash);
3646 if (result->IsFailure()) return result;
3647 if (result->ToObjectUnchecked()->IsUndefined()) {
3648 // Trying to get hash of detached proxy.
3649 return Smi::FromInt(0);
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003650 }
3651 return hash;
3652}
3653
3654
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003655MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) {
3656 Object* hash = this->hash();
3657 if (!hash->IsSmi() && flag == ALLOW_CREATION) {
3658 hash = GenerateIdentityHash();
3659 set_hash(hash);
3660 }
3661 return hash;
3662}
3663
3664
3665Object* JSObject::GetHiddenProperty(String* key) {
3666 if (IsJSGlobalProxy()) {
3667 // For a proxy, use the prototype as target object.
3668 Object* proxy_parent = GetPrototype();
3669 // If the proxy is detached, return undefined.
3670 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3671 ASSERT(proxy_parent->IsJSGlobalObject());
3672 return JSObject::cast(proxy_parent)->GetHiddenProperty(key);
3673 }
3674 ASSERT(!IsJSGlobalProxy());
3675 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3676 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3677 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) {
3678 return GetHeap()->undefined_value();
3679 }
3680 StringDictionary* dictionary =
3681 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3682 int entry = dictionary->FindEntry(key);
3683 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value();
3684 return dictionary->ValueAt(entry);
3685}
3686
3687
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003688Handle<Object> JSObject::SetHiddenProperty(Handle<JSObject> obj,
3689 Handle<String> key,
3690 Handle<Object> value) {
3691 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3692 obj->SetHiddenProperty(*key, *value),
3693 Object);
3694}
3695
3696
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003697MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) {
3698 if (IsJSGlobalProxy()) {
3699 // For a proxy, use the prototype as target object.
3700 Object* proxy_parent = GetPrototype();
3701 // If the proxy is detached, return undefined.
3702 if (proxy_parent->IsNull()) return GetHeap()->undefined_value();
3703 ASSERT(proxy_parent->IsJSGlobalObject());
3704 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value);
3705 }
3706 ASSERT(!IsJSGlobalProxy());
3707 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true);
3708 StringDictionary* dictionary;
3709 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup;
3710
3711 // If it was found, check if the key is already in the dictionary.
3712 int entry = dictionary->FindEntry(key);
3713 if (entry != StringDictionary::kNotFound) {
3714 // If key was found, just update the value.
3715 dictionary->ValueAtPut(entry, value);
3716 return this;
3717 }
3718 // Key was not already in the dictionary, so add the entry.
3719 MaybeObject* insert_result = dictionary->Add(key,
3720 value,
3721 PropertyDetails(NONE, NORMAL));
3722 StringDictionary* new_dict;
3723 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result;
3724 if (new_dict != dictionary) {
3725 // If adding the key expanded the dictionary (i.e., Add returned a new
3726 // dictionary), store it back to the object.
3727 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict);
3728 if (store_result->IsFailure()) return store_result;
3729 }
3730 // Return this to mark success.
3731 return this;
3732}
3733
3734
3735void JSObject::DeleteHiddenProperty(String* key) {
3736 if (IsJSGlobalProxy()) {
3737 // For a proxy, use the prototype as target object.
3738 Object* proxy_parent = GetPrototype();
3739 // If the proxy is detached, return immediately.
3740 if (proxy_parent->IsNull()) return;
3741 ASSERT(proxy_parent->IsJSGlobalObject());
3742 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key);
3743 return;
3744 }
3745 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false);
3746 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg.
3747 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return;
3748 StringDictionary* dictionary =
3749 StringDictionary::cast(hidden_lookup->ToObjectUnchecked());
3750 int entry = dictionary->FindEntry(key);
3751 if (entry == StringDictionary::kNotFound) {
3752 // Key wasn't in dictionary. Deletion is a success.
3753 return;
3754 }
3755 // Key was in the dictionary. Remove it.
3756 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION);
3757}
3758
3759
3760bool JSObject::HasHiddenProperties() {
erik.corry@gmail.comb99cabf2011-10-07 09:45:13 +00003761 return GetPropertyAttributePostInterceptor(this,
3762 GetHeap()->hidden_symbol(),
3763 false) != ABSENT;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003764}
3765
3766
3767MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) {
3768 ASSERT(!IsJSGlobalProxy());
3769 if (HasFastProperties()) {
3770 // If the object has fast properties, check whether the first slot
3771 // in the descriptor array matches the hidden symbol. Since the
3772 // hidden symbols hash code is zero (and no other string has hash
3773 // code zero) it will always occupy the first entry if present.
3774 DescriptorArray* descriptors = this->map()->instance_descriptors();
3775 if ((descriptors->number_of_descriptors() > 0) &&
3776 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
3777 descriptors->IsProperty(0)) {
3778 ASSERT(descriptors->GetType(0) == FIELD);
3779 Object* hidden_store =
3780 this->FastPropertyAt(descriptors->GetFieldIndex(0));
3781 return StringDictionary::cast(hidden_store);
3782 }
3783 } else {
3784 PropertyAttributes attributes;
3785 // You can't install a getter on a property indexed by the hidden symbol,
3786 // so we can be sure that GetLocalPropertyPostInterceptor returns a real
3787 // object.
3788 Object* lookup =
3789 GetLocalPropertyPostInterceptor(this,
3790 GetHeap()->hidden_symbol(),
3791 &attributes)->ToObjectUnchecked();
3792 if (!lookup->IsUndefined()) {
3793 return StringDictionary::cast(lookup);
3794 }
3795 }
3796 if (!create_if_absent) return GetHeap()->undefined_value();
3797 const int kInitialSize = 5;
3798 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize);
3799 StringDictionary* dictionary;
3800 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc;
3801 MaybeObject* store_result =
3802 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3803 dictionary,
3804 DONT_ENUM,
3805 kNonStrictMode);
3806 if (store_result->IsFailure()) return store_result;
3807 return dictionary;
3808}
3809
3810
3811MaybeObject* JSObject::SetHiddenPropertiesDictionary(
3812 StringDictionary* dictionary) {
3813 ASSERT(!IsJSGlobalProxy());
3814 ASSERT(HasHiddenProperties());
3815 if (HasFastProperties()) {
3816 // If the object has fast properties, check whether the first slot
3817 // in the descriptor array matches the hidden symbol. Since the
3818 // hidden symbols hash code is zero (and no other string has hash
3819 // code zero) it will always occupy the first entry if present.
3820 DescriptorArray* descriptors = this->map()->instance_descriptors();
3821 if ((descriptors->number_of_descriptors() > 0) &&
3822 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) &&
3823 descriptors->IsProperty(0)) {
3824 ASSERT(descriptors->GetType(0) == FIELD);
3825 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary);
3826 return this;
3827 }
3828 }
3829 MaybeObject* store_result =
3830 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(),
3831 dictionary,
3832 DONT_ENUM,
3833 kNonStrictMode);
3834 if (store_result->IsFailure()) return store_result;
3835 return this;
3836}
3837
3838
lrn@chromium.org303ada72010-10-27 09:33:13 +00003839MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3840 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841 // Check local property, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003842 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003843 LocalLookupRealNamedProperty(name, &result);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003844 if (!result.IsProperty()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845
3846 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003847 Object* obj;
3848 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3849 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3850 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003852 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853}
3854
3855
lrn@chromium.org303ada72010-10-27 09:33:13 +00003856MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003857 Isolate* isolate = GetIsolate();
3858 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003859 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3860 Handle<String> name_handle(name);
3861 Handle<JSObject> this_handle(this);
3862 if (!interceptor->deleter()->IsUndefined()) {
3863 v8::NamedPropertyDeleter deleter =
3864 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003865 LOG(isolate,
3866 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3867 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003868 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003869 v8::Handle<v8::Boolean> result;
3870 {
3871 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003872 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003873 result = deleter(v8::Utils::ToLocal(name_handle), info);
3874 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003875 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003876 if (!result.IsEmpty()) {
3877 ASSERT(result->IsBoolean());
3878 return *v8::Utils::OpenHandle(*result);
3879 }
3880 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003881 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00003882 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003883 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003884 return raw_result;
3885}
3886
3887
lrn@chromium.org303ada72010-10-27 09:33:13 +00003888MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 Isolate* isolate = GetIsolate();
3890 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003891 // Make sure that the top context does not change when doing
3892 // callbacks or interceptor calls.
3893 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003894 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003896 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003897 v8::IndexedPropertyDeleter deleter =
3898 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3899 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003900 LOG(isolate,
3901 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3902 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003903 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003904 v8::Handle<v8::Boolean> result;
3905 {
3906 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003907 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908 result = deleter(index, info);
3909 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003910 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911 if (!result.IsEmpty()) {
3912 ASSERT(result->IsBoolean());
3913 return *v8::Utils::OpenHandle(*result);
3914 }
danno@chromium.orgb6451162011-08-17 14:33:23 +00003915 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3916 *this_handle,
3917 index,
3918 NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003919 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003920 return raw_result;
3921}
3922
3923
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003924Handle<Object> JSObject::DeleteElement(Handle<JSObject> obj,
3925 uint32_t index) {
3926 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3927 obj->DeleteElement(index, JSObject::NORMAL_DELETION),
3928 Object);
3929}
3930
3931
lrn@chromium.org303ada72010-10-27 09:33:13 +00003932MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003933 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003934 // Check access rights if needed.
3935 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003936 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3937 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3938 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003939 }
3940
3941 if (IsJSGlobalProxy()) {
3942 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003943 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003944 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003945 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003946 }
3947
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 if (HasIndexedInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003949 // Skip interceptor if forcing deletion.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003950 if (mode != FORCE_DELETION) {
3951 return DeleteElementWithInterceptor(index);
3952 }
3953 mode = JSReceiver::FORCE_DELETION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003954 }
3955
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003956 return GetElementsAccessor()->Delete(this, index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003957}
3958
3959
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003960Handle<Object> JSObject::DeleteProperty(Handle<JSObject> obj,
3961 Handle<String> prop) {
3962 CALL_HEAP_FUNCTION(obj->GetIsolate(),
3963 obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION),
3964 Object);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003965}
3966
3967
lrn@chromium.org303ada72010-10-27 09:33:13 +00003968MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003969 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003970 // ECMA-262, 3rd, 8.6.2.5
3971 ASSERT(name->IsString());
3972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 // Check access rights if needed.
3974 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003975 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3976 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3977 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 }
3979
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003980 if (IsJSGlobalProxy()) {
3981 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003982 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003983 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003984 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003985 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003987 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003989 return DeleteElement(index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003991 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 LocalLookup(name, &result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003993 if (!result.IsProperty()) return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003994 // Ignore attributes if forcing a deletion.
3995 if (result.IsDontDelete() && mode != FORCE_DELETION) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003996 if (mode == STRICT_DELETION) {
3997 // Deleting a non-configurable property in strict mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003999 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 return isolate->Throw(*isolate->factory()->NewTypeError(
4001 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004002 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004003 return isolate->heap()->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004004 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005 // Check for interceptor.
4006 if (result.type() == INTERCEPTOR) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004007 // Skip interceptor if forcing a deletion.
4008 if (mode == FORCE_DELETION) {
4009 return DeletePropertyPostInterceptor(name, mode);
4010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 return DeletePropertyWithInterceptor(name);
4012 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004014 Object* obj;
4015 { MaybeObject* maybe_obj =
4016 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4017 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4018 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 // Make sure the properties are normalized before removing the entry.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004020 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
4022}
4023
4024
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004025MaybeObject* JSReceiver::DeleteElement(uint32_t index, DeleteMode mode) {
4026 if (IsJSProxy()) {
4027 return JSProxy::cast(this)->DeleteElementWithHandler(index, mode);
4028 }
4029 return JSObject::cast(this)->DeleteElement(index, mode);
4030}
4031
4032
4033MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
4034 if (IsJSProxy()) {
4035 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
4036 }
4037 return JSObject::cast(this)->DeleteProperty(name, mode);
4038}
4039
4040
whesse@chromium.org7b260152011-06-20 15:33:18 +00004041bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
4042 ElementsKind kind,
4043 Object* object) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004044 ASSERT(kind == FAST_ELEMENTS ||
4045 kind == DICTIONARY_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004046 if (kind == FAST_ELEMENTS) {
4047 int length = IsJSArray()
4048 ? Smi::cast(JSArray::cast(this)->length())->value()
4049 : elements->length();
4050 for (int i = 0; i < length; ++i) {
4051 Object* element = elements->get(i);
4052 if (!element->IsTheHole() && element == object) return true;
4053 }
4054 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004055 Object* key =
4056 SeededNumberDictionary::cast(elements)->SlowReverseLookup(object);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004057 if (!key->IsUndefined()) return true;
4058 }
4059 return false;
4060}
4061
4062
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063// Check whether this object references another object.
4064bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004065 Map* map_of_this = map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004066 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004067 AssertNoAllocation no_alloc;
4068
4069 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004070 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004071 return true;
4072 }
4073
4074 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004075 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004076 return true;
4077 }
4078
4079 // Check if the object is among the named properties.
4080 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004081 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082 return true;
4083 }
4084
4085 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004086 ElementsKind kind = GetElementsKind();
4087 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004088 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00004089 case EXTERNAL_BYTE_ELEMENTS:
4090 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4091 case EXTERNAL_SHORT_ELEMENTS:
4092 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4093 case EXTERNAL_INT_ELEMENTS:
4094 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4095 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004096 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00004097 case FAST_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00004098 // Raw pixels and external arrays do not reference other
4099 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004100 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004101 case FAST_SMI_ONLY_ELEMENTS:
4102 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004103 case FAST_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004104 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004105 FixedArray* elements = FixedArray::cast(this->elements());
4106 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004107 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004109 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4110 FixedArray* parameter_map = FixedArray::cast(elements());
4111 // Check the mapped parameters.
4112 int length = parameter_map->length();
4113 for (int i = 2; i < length; ++i) {
4114 Object* value = parameter_map->get(i);
4115 if (!value->IsTheHole() && value == obj) return true;
4116 }
4117 // Check the arguments.
4118 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4119 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
4120 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004121 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004122 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 }
4124
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00004125 // For functions check the context.
4126 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127 // Get the constructor function for arguments array.
4128 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129 heap->isolate()->context()->global_context()->
4130 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004131 JSFunction* arguments_function =
4132 JSFunction::cast(arguments_boilerplate->map()->constructor());
4133
4134 // Get the context and don't check if it is the global context.
4135 JSFunction* f = JSFunction::cast(this);
4136 Context* context = f->context();
4137 if (context->IsGlobalContext()) {
4138 return false;
4139 }
4140
4141 // Check the non-special context slots.
4142 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
4143 // Only check JS objects.
4144 if (context->get(i)->IsJSObject()) {
4145 JSObject* ctxobj = JSObject::cast(context->get(i));
4146 // If it is an arguments array check the content.
4147 if (ctxobj->map()->constructor() == arguments_function) {
4148 if (ctxobj->ReferencesObject(obj)) {
4149 return true;
4150 }
4151 } else if (ctxobj == obj) {
4152 return true;
4153 }
4154 }
4155 }
4156
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004157 // Check the context extension (if any) if it can have references.
4158 if (context->has_extension() && !context->IsCatchContext()) {
4159 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004160 }
4161 }
4162
4163 // No references to object.
4164 return false;
4165}
4166
4167
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004168Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
4169 CALL_HEAP_FUNCTION(object->GetIsolate(), object->PreventExtensions(), Object);
4170}
4171
4172
lrn@chromium.org303ada72010-10-27 09:33:13 +00004173MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004174 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004175 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004176 !isolate->MayNamedAccess(this,
4177 isolate->heap()->undefined_value(),
4178 v8::ACCESS_KEYS)) {
4179 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
4180 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004181 }
4182
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004183 if (IsJSGlobalProxy()) {
4184 Object* proto = GetPrototype();
4185 if (proto->IsNull()) return this;
4186 ASSERT(proto->IsJSGlobalObject());
4187 return JSObject::cast(proto)->PreventExtensions();
4188 }
4189
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004190 // It's not possible to seal objects with external array elements
4191 if (HasExternalArrayElements()) {
4192 HandleScope scope(isolate);
4193 Handle<Object> object(this);
4194 Handle<Object> error =
4195 isolate->factory()->NewTypeError(
4196 "cant_prevent_ext_external_array_elements",
4197 HandleVector(&object, 1));
4198 return isolate->Throw(*error);
4199 }
4200
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004201 // If there are fast elements we normalize.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004202 SeededNumberDictionary* dictionary = NULL;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004203 { MaybeObject* maybe = NormalizeElements();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004204 if (!maybe->To<SeededNumberDictionary>(&dictionary)) return maybe;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004205 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004206 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004207 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004208 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004209
4210 // Do a map transition, other objects with this map may still
4211 // be extensible.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004212 Map* new_map;
4213 { MaybeObject* maybe = map()->CopyDropTransitions();
4214 if (!maybe->To<Map>(&new_map)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004215 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00004216 new_map->set_is_extensible(false);
4217 set_map(new_map);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004218 ASSERT(!map()->is_extensible());
4219 return new_map;
4220}
4221
4222
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004223// Tests for the fast common case for property enumeration:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004224// - This object and all prototypes has an enum cache (which means that
4225// it is no proxy, has no interceptors and needs no access checks).
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004226// - This object has no elements.
4227// - No prototype has enumerable properties/elements.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004228bool JSReceiver::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004229 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004231 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232 o = JSObject::cast(o)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004233 if (!o->IsJSObject()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004234 JSObject* curr = JSObject::cast(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004235 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004236 ASSERT(!curr->HasNamedInterceptor());
4237 ASSERT(!curr->HasIndexedInterceptor());
4238 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239 if (curr->NumberOfEnumElements() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004240 if (curr != this) {
4241 FixedArray* curr_fixed_array =
4242 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00004243 if (curr_fixed_array->length() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 }
4245 }
4246 return true;
4247}
4248
4249
4250int Map::NumberOfDescribedProperties() {
4251 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004252 DescriptorArray* descs = instance_descriptors();
4253 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4254 if (descs->IsProperty(i)) result++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004255 }
4256 return result;
4257}
4258
4259
4260int Map::PropertyIndexFor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004261 DescriptorArray* descs = instance_descriptors();
4262 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4263 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
4264 return descs->GetFieldIndex(i);
4265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004266 }
4267 return -1;
4268}
4269
4270
4271int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004272 int max_index = -1;
4273 DescriptorArray* descs = instance_descriptors();
4274 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4275 if (descs->GetType(i) == FIELD) {
4276 int current_index = descs->GetFieldIndex(i);
4277 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004278 }
4279 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004280 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004281}
4282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004283
4284AccessorDescriptor* Map::FindAccessor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004285 DescriptorArray* descs = instance_descriptors();
4286 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4287 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
4288 return descs->GetCallbacks(i);
4289 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004290 }
4291 return NULL;
4292}
4293
4294
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004295void JSReceiver::LocalLookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 ASSERT(name->IsString());
4297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004298 Heap* heap = GetHeap();
4299
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004300 if (IsJSGlobalProxy()) {
4301 Object* proto = GetPrototype();
4302 if (proto->IsNull()) return result->NotFound();
4303 ASSERT(proto->IsJSGlobalObject());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004304 return JSReceiver::cast(proto)->LocalLookup(name, result);
4305 }
4306
4307 if (IsJSProxy()) {
4308 result->HandlerResult(JSProxy::cast(this));
4309 return;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004310 }
4311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 // Do not use inline caching if the object is a non-global object
4313 // that requires access checks.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004314 if (IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004315 result->DisallowCaching();
4316 }
4317
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004318 JSObject* js_object = JSObject::cast(this);
4319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 // Check __proto__ before interceptor.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004321 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004322 result->ConstantResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004323 return;
4324 }
4325
4326 // Check for lookup interceptor except when bootstrapping.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004327 if (js_object->HasNamedInterceptor() &&
4328 !heap->isolate()->bootstrapper()->IsActive()) {
4329 result->InterceptorResult(js_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004330 return;
4331 }
4332
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004333 js_object->LocalLookupRealNamedProperty(name, result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334}
4335
4336
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004337void JSReceiver::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004339 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004340 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004342 current = JSObject::cast(current)->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004343 JSReceiver::cast(current)->LocalLookup(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004344 if (result->IsProperty()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004345 }
4346 result->NotFound();
4347}
4348
4349
4350// Search object and it's prototype chain for callback properties.
4351void JSObject::LookupCallback(String* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004352 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004353 for (Object* current = this;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00004354 current != heap->null_value() && current->IsJSObject();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004355 current = JSObject::cast(current)->GetPrototype()) {
4356 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004357 if (result->IsFound() && result->type() == CALLBACKS) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004358 }
4359 result->NotFound();
4360}
4361
4362
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004363// Search for a getter or setter in an elements dictionary and update its
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004364// attributes. Returns either undefined if the element is non-deletable, or the
4365// getter/setter pair if there is an existing one, or the hole value if the
4366// element does not exist or is a normal non-getter/setter data element.
4367static Object* UpdateGetterSetterInDictionary(
4368 SeededNumberDictionary* dictionary,
4369 uint32_t index,
4370 PropertyAttributes attributes,
4371 Heap* heap) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004372 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004373 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004374 Object* result = dictionary->ValueAt(entry);
4375 PropertyDetails details = dictionary->DetailsAt(entry);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004376 // TODO(mstarzinger): We should check for details.IsDontDelete() here once
4377 // we only call into the runtime once to set both getter and setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004378 if (details.type() == CALLBACKS && result->IsAccessorPair()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004379 if (details.attributes() != attributes) {
4380 dictionary->DetailsAtPut(entry,
4381 PropertyDetails(attributes, CALLBACKS, index));
4382 }
4383 return result;
4384 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004385 }
4386 return heap->the_hole_value();
4387}
4388
4389
lrn@chromium.org303ada72010-10-27 09:33:13 +00004390MaybeObject* JSObject::DefineGetterSetter(String* name,
4391 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004392 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004393 // Make sure that the top context does not change when doing callbacks or
4394 // interceptor calls.
4395 AssertNoContextChange ncc;
4396
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004397 // Try to flatten before operating on the string.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004398 name->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004399
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004400 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004401 return heap->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004402 }
4403
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00004404 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004405 bool is_element = name->AsArrayIndex(&index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004406
4407 if (is_element) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004408 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004409 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004410 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004411 case FAST_DOUBLE_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004412 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004413 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00004414 case EXTERNAL_BYTE_ELEMENTS:
4415 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4416 case EXTERNAL_SHORT_ELEMENTS:
4417 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4418 case EXTERNAL_INT_ELEMENTS:
4419 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4420 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004421 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00004422 // Ignore getters and setters on pixel and external array
4423 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004424 return heap->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004425 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004426 Object* probe = UpdateGetterSetterInDictionary(element_dictionary(),
4427 index,
4428 attributes,
4429 heap);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004430 if (!probe->IsTheHole()) return probe;
4431 // Otherwise allow to override it.
4432 break;
4433 }
4434 case NON_STRICT_ARGUMENTS_ELEMENTS: {
4435 // Ascertain whether we have read-only properties or an existing
4436 // getter/setter pair in an arguments elements dictionary backing
4437 // store.
4438 FixedArray* parameter_map = FixedArray::cast(elements());
4439 uint32_t length = parameter_map->length();
4440 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00004441 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004442 if (probe == NULL || probe->IsTheHole()) {
4443 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
4444 if (arguments->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004445 SeededNumberDictionary* dictionary =
4446 SeededNumberDictionary::cast(arguments);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004447 probe = UpdateGetterSetterInDictionary(dictionary,
4448 index,
4449 attributes,
4450 heap);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004451 if (!probe->IsTheHole()) return probe;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004452 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004453 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004454 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004455 }
4456 }
4457 } else {
4458 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004459 LookupResult result(heap->isolate());
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00004460 LocalLookupRealNamedProperty(name, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004461 if (result.IsFound()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004462 // TODO(mstarzinger): We should check for result.IsDontDelete() here once
4463 // we only call into the runtime once to set both getter and setter.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004464 if (result.type() == CALLBACKS) {
4465 Object* obj = result.GetCallbackObject();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004466 // Need to preserve old getters/setters.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004467 if (obj->IsAccessorPair()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004468 // Use set to update attributes.
4469 return SetPropertyCallback(name, obj, attributes);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004470 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472 }
4473 }
4474
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004475 AccessorPair* accessors;
4476 { MaybeObject* maybe_accessors = heap->AllocateAccessorPair();
4477 if (!maybe_accessors->To<AccessorPair>(&accessors)) return maybe_accessors;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004478 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004479
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004480 if (is_element) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004481 return SetElementCallback(index, accessors, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004482 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004483 return SetPropertyCallback(name, accessors, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004484 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004485}
4486
4487
4488bool JSObject::CanSetCallback(String* name) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004489 ASSERT(!IsAccessCheckNeeded() ||
4490 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004491
4492 // Check if there is an API defined callback object which prohibits
4493 // callback overwriting in this object or it's prototype chain.
4494 // This mechanism is needed for instance in a browser setting, where
4495 // certain accessors such as window.location should not be allowed
4496 // to be overwritten because allowing overwriting could potentially
4497 // cause security problems.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004498 LookupResult callback_result(GetIsolate());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004499 LookupCallback(name, &callback_result);
4500 if (callback_result.IsProperty()) {
4501 Object* obj = callback_result.GetCallbackObject();
4502 if (obj->IsAccessorInfo() &&
4503 AccessorInfo::cast(obj)->prohibits_overwriting()) {
4504 return false;
4505 }
4506 }
4507
4508 return true;
4509}
4510
4511
lrn@chromium.org303ada72010-10-27 09:33:13 +00004512MaybeObject* JSObject::SetElementCallback(uint32_t index,
4513 Object* structure,
4514 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004515 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4516
4517 // Normalize elements to make this operation simple.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004518 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004519 { Object* result;
4520 MaybeObject* maybe = NormalizeElements();
4521 if (!maybe->ToObject(&result)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004522 dictionary = SeededNumberDictionary::cast(result);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004523 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00004524 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004525
4526 // Update the dictionary with the new CALLBACKS property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00004527 { Object* result;
4528 MaybeObject* maybe = dictionary->Set(index, structure, details);
4529 if (!maybe->ToObject(&result)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004530 dictionary = SeededNumberDictionary::cast(result);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004531 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004532
whesse@chromium.org7b260152011-06-20 15:33:18 +00004533 dictionary->set_requires_slow_elements();
4534 // Update the dictionary backing store on the object.
4535 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
4536 // Also delete any parameter alias.
4537 //
4538 // TODO(kmillikin): when deleting the last parameter alias we could
4539 // switch to a direct backing store without the parameter map. This
4540 // would allow GC of the context.
4541 FixedArray* parameter_map = FixedArray::cast(elements());
4542 uint32_t length = parameter_map->length();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00004543 if (index < length - 2) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004544 parameter_map->set(index + 2, GetHeap()->the_hole_value());
4545 }
4546 parameter_map->set(1, dictionary);
4547 } else {
4548 set_elements(dictionary);
4549 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004550
4551 return structure;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552}
4553
4554
lrn@chromium.org303ada72010-10-27 09:33:13 +00004555MaybeObject* JSObject::SetPropertyCallback(String* name,
4556 Object* structure,
4557 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004558 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
4559
4560 bool convert_back_to_fast = HasFastProperties() &&
4561 (map()->instance_descriptors()->number_of_descriptors()
4562 < DescriptorArray::kMaxNumberOfDescriptors);
4563
4564 // Normalize object to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004565 Object* ok;
4566 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
4567 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4568 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004569
4570 // For the global object allocate a new map to invalidate the global inline
4571 // caches which have a global property cell reference directly in the code.
4572 if (IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004573 Object* new_map;
4574 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
4575 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4576 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004577 set_map(Map::cast(new_map));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004578 // When running crankshaft, changing the map is not enough. We
4579 // need to deoptimize all functions that rely on this global
4580 // object.
4581 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004582 }
4583
4584 // Update the dictionary with the new CALLBACKS property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004585 Object* result;
4586 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
4587 if (!maybe_result->ToObject(&result)) return maybe_result;
4588 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004589
4590 if (convert_back_to_fast) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004591 { MaybeObject* maybe_ok = TransformToFastProperties(0);
4592 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4593 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004594 }
4595 return result;
4596}
4597
lrn@chromium.org303ada72010-10-27 09:33:13 +00004598MaybeObject* JSObject::DefineAccessor(String* name,
4599 bool is_getter,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004600 Object* fun,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004601 PropertyAttributes attributes) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004602 ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004603 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004604 // Check access rights if needed.
4605 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004606 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4607 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4608 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004609 }
4610
4611 if (IsJSGlobalProxy()) {
4612 Object* proto = GetPrototype();
4613 if (proto->IsNull()) return this;
4614 ASSERT(proto->IsJSGlobalObject());
4615 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
4616 fun, attributes);
4617 }
4618
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004619 Object* accessors;
4620 { MaybeObject* maybe_accessors = DefineGetterSetter(name, attributes);
4621 if (!maybe_accessors->To<Object>(&accessors)) return maybe_accessors;
lrn@chromium.org303ada72010-10-27 09:33:13 +00004622 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004623 if (accessors->IsUndefined()) return accessors;
4624 if (is_getter) {
4625 AccessorPair::cast(accessors)->set_getter(fun);
4626 } else {
4627 AccessorPair::cast(accessors)->set_setter(fun);
4628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004629 return this;
4630}
4631
4632
lrn@chromium.org303ada72010-10-27 09:33:13 +00004633MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004634 Isolate* isolate = GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004635 String* name = String::cast(info->name());
4636 // Check access rights if needed.
4637 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
4639 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
4640 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004641 }
4642
4643 if (IsJSGlobalProxy()) {
4644 Object* proto = GetPrototype();
4645 if (proto->IsNull()) return this;
4646 ASSERT(proto->IsJSGlobalObject());
4647 return JSObject::cast(proto)->DefineAccessor(info);
4648 }
4649
4650 // Make sure that the top context does not change when doing callbacks or
4651 // interceptor calls.
4652 AssertNoContextChange ncc;
4653
4654 // Try to flatten before operating on the string.
4655 name->TryFlatten();
4656
4657 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004658 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004659 }
4660
4661 uint32_t index = 0;
4662 bool is_element = name->AsArrayIndex(&index);
4663
4664 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004665 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004666
4667 // Accessors overwrite previous callbacks (cf. with getters/setters).
4668 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004669 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004670 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00004671 case FAST_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004672 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004673 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004674 case EXTERNAL_BYTE_ELEMENTS:
4675 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4676 case EXTERNAL_SHORT_ELEMENTS:
4677 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4678 case EXTERNAL_INT_ELEMENTS:
4679 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
4680 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00004681 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004682 // Ignore getters and setters on pixel and external array
4683 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004684 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004685 case DICTIONARY_ELEMENTS:
4686 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004687 case NON_STRICT_ARGUMENTS_ELEMENTS:
4688 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004689 break;
4690 }
4691
lrn@chromium.org303ada72010-10-27 09:33:13 +00004692 Object* ok;
4693 { MaybeObject* maybe_ok =
4694 SetElementCallback(index, info, info->property_attributes());
4695 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4696 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004697 } else {
4698 // Lookup the name.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004699 LookupResult result(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004700 LocalLookup(name, &result);
4701 // ES5 forbids turning a property into an accessor if it's not
4702 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
4703 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004704 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004705 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004706 Object* ok;
4707 { MaybeObject* maybe_ok =
4708 SetPropertyCallback(name, info, info->property_attributes());
4709 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4710 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004711 }
4712
4713 return this;
4714}
4715
4716
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717Object* JSObject::LookupAccessor(String* name, bool is_getter) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004718 Heap* heap = GetHeap();
4719
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004720 // Make sure that the top context does not change when doing callbacks or
4721 // interceptor calls.
4722 AssertNoContextChange ncc;
4723
4724 // Check access rights if needed.
4725 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
4727 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
4728 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004729 }
4730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731 // Make the lookup and include prototypes.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00004732 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004733 if (name->AsArrayIndex(&index)) {
4734 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004735 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004736 obj = JSObject::cast(obj)->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004737 JSObject* js_object = JSObject::cast(obj);
4738 if (js_object->HasDictionaryElements()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004739 SeededNumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004740 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004741 if (entry != SeededNumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004742 Object* element = dictionary->ValueAt(entry);
4743 PropertyDetails details = dictionary->DetailsAt(entry);
4744 if (details.type() == CALLBACKS) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004745 if (element->IsAccessorPair()) {
4746 AccessorPair* accessors = AccessorPair::cast(element);
4747 return is_getter ? accessors->getter() : accessors->setter();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004748 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004749 }
4750 }
4751 }
4752 }
4753 } else {
4754 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004756 obj = JSObject::cast(obj)->GetPrototype()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004757 LookupResult result(heap->isolate());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004758 JSObject::cast(obj)->LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004759 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004760 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004761 if (result.type() == CALLBACKS) {
4762 Object* obj = result.GetCallbackObject();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004763 if (obj->IsAccessorPair()) {
4764 AccessorPair* accessors = AccessorPair::cast(obj);
4765 return is_getter ? accessors->getter() : accessors->setter();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004767 }
4768 }
4769 }
4770 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004771 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772}
4773
4774
4775Object* JSObject::SlowReverseLookup(Object* value) {
4776 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004777 DescriptorArray* descs = map()->instance_descriptors();
4778 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4779 if (descs->GetType(i) == FIELD) {
4780 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4781 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004783 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4784 if (descs->GetConstantFunction(i) == value) {
4785 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 }
4787 }
4788 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004789 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004790 } else {
4791 return property_dictionary()->SlowReverseLookup(value);
4792 }
4793}
4794
4795
lrn@chromium.org303ada72010-10-27 09:33:13 +00004796MaybeObject* Map::CopyDropDescriptors() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004797 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004798 Object* result;
4799 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004800 heap->AllocateMap(instance_type(), instance_size());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004801 if (!maybe_result->ToObject(&result)) return maybe_result;
4802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004803 Map::cast(result)->set_prototype(prototype());
4804 Map::cast(result)->set_constructor(constructor());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004805 // Don't copy descriptors, so map transitions always remain a forest.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004806 // If we retained the same descriptors we would have two maps
4807 // pointing to the same transition which is bad because the garbage
4808 // collector relies on being able to reverse pointers from transitions
4809 // to maps. If properties need to be retained use CopyDropTransitions.
danno@chromium.org40cb8782011-05-25 07:58:50 +00004810 Map::cast(result)->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 // Please note instance_type and instance_size are set when allocated.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004812 Map::cast(result)->set_inobject_properties(inobject_properties());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 Map::cast(result)->set_unused_property_fields(unused_property_fields());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004814
4815 // If the map has pre-allocated properties always start out with a descriptor
4816 // array describing these properties.
4817 if (pre_allocated_property_fields() > 0) {
4818 ASSERT(constructor()->IsJSFunction());
4819 JSFunction* ctor = JSFunction::cast(constructor());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004820 Object* descriptors;
4821 { MaybeObject* maybe_descriptors =
4822 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4823 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4824 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004825 Map::cast(result)->set_instance_descriptors(
4826 DescriptorArray::cast(descriptors));
4827 Map::cast(result)->set_pre_allocated_property_fields(
4828 pre_allocated_property_fields());
4829 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 Map::cast(result)->set_bit_field(bit_field());
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004831 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004832 Map::cast(result)->set_bit_field3(bit_field3());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004833 Map::cast(result)->set_is_shared(false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004834 Map::cast(result)->ClearCodeCache(heap);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004835 return result;
4836}
4837
4838
lrn@chromium.org303ada72010-10-27 09:33:13 +00004839MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4840 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004841 int new_instance_size = instance_size();
4842 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4843 new_instance_size -= inobject_properties() * kPointerSize;
4844 }
4845
lrn@chromium.org303ada72010-10-27 09:33:13 +00004846 Object* result;
4847 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 GetHeap()->AllocateMap(instance_type(), new_instance_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004849 if (!maybe_result->ToObject(&result)) return maybe_result;
4850 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004851
4852 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4853 Map::cast(result)->set_inobject_properties(inobject_properties());
4854 }
4855
4856 Map::cast(result)->set_prototype(prototype());
4857 Map::cast(result)->set_constructor(constructor());
4858
4859 Map::cast(result)->set_bit_field(bit_field());
4860 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004861 Map::cast(result)->set_bit_field3(bit_field3());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004862
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004863 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4864
ricow@chromium.org65fae842010-08-25 15:26:24 +00004865#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004866 if (FLAG_verify_heap && Map::cast(result)->is_shared()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004867 Map::cast(result)->SharedMapVerify();
4868 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004869#endif
4870
4871 return result;
4872}
4873
4874
lrn@chromium.org303ada72010-10-27 09:33:13 +00004875MaybeObject* Map::CopyDropTransitions() {
4876 Object* new_map;
4877 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4878 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4879 }
4880 Object* descriptors;
4881 { MaybeObject* maybe_descriptors =
4882 instance_descriptors()->RemoveTransitions();
4883 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4884 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004885 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004886 return new_map;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004887}
4888
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004889void Map::UpdateCodeCache(Handle<Map> map,
4890 Handle<String> name,
4891 Handle<Code> code) {
4892 Isolate* isolate = map->GetIsolate();
4893 CALL_HEAP_FUNCTION_VOID(isolate,
4894 map->UpdateCodeCache(*name, *code));
4895}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004896
lrn@chromium.org303ada72010-10-27 09:33:13 +00004897MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004898 // Allocate the code cache if not present.
4899 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004900 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004901 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004902 if (!maybe_result->ToObject(&result)) return maybe_result;
4903 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004904 set_code_cache(result);
4905 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004906
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004907 // Update the code cache.
4908 return CodeCache::cast(code_cache())->Update(name, code);
4909}
4910
4911
4912Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4913 // Do a lookup if a code cache exists.
4914 if (!code_cache()->IsFixedArray()) {
4915 return CodeCache::cast(code_cache())->Lookup(name, flags);
4916 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004917 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004918 }
4919}
4920
4921
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004922int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004923 // Get the internal index if a code cache exists.
4924 if (!code_cache()->IsFixedArray()) {
4925 return CodeCache::cast(code_cache())->GetIndex(name, code);
4926 }
4927 return -1;
4928}
4929
4930
4931void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4932 // No GC is supposed to happen between a call to IndexInCodeCache and
4933 // RemoveFromCodeCache so the code cache must be there.
4934 ASSERT(!code_cache()->IsFixedArray());
4935 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4936}
4937
4938
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004939// An iterator over all map transitions in an descriptor array, reusing the map
4940// field of the contens array while it is running.
4941class IntrusiveMapTransitionIterator {
4942 public:
4943 explicit IntrusiveMapTransitionIterator(DescriptorArray* descriptor_array)
4944 : descriptor_array_(descriptor_array) { }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004945
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004946 void Start() {
4947 ASSERT(!IsIterating());
4948 if (HasContentArray()) *ContentHeader() = Smi::FromInt(0);
4949 }
4950
4951 bool IsIterating() {
4952 return HasContentArray() && (*ContentHeader())->IsSmi();
4953 }
4954
4955 Map* Next() {
4956 ASSERT(IsIterating());
4957 FixedArray* contents = ContentArray();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004958 // Attention, tricky index manipulation ahead: Every entry in the contents
4959 // array consists of a value/details pair, so the index is typically even.
4960 // An exception is made for CALLBACKS entries: An even index means we look
4961 // at its getter, and an odd index means we look at its setter.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004962 int index = Smi::cast(*ContentHeader())->value();
4963 while (index < contents->length()) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00004964 PropertyDetails details(Smi::cast(contents->get(index | 1)));
4965 switch (details.type()) {
4966 case MAP_TRANSITION:
4967 case CONSTANT_TRANSITION:
4968 case ELEMENTS_TRANSITION:
4969 // We definitely have a map transition.
4970 *ContentHeader() = Smi::FromInt(index + 2);
4971 return static_cast<Map*>(contents->get(index));
4972 case CALLBACKS: {
4973 // We might have a map transition in a getter or in a setter.
4974 AccessorPair* accessors =
4975 static_cast<AccessorPair*>(contents->get(index & ~1));
4976 Object* accessor =
4977 ((index & 1) == 0) ? accessors->getter() : accessors->setter();
4978 index++;
4979 if (accessor->IsMap()) {
4980 *ContentHeader() = Smi::FromInt(index);
4981 return static_cast<Map*>(accessor);
4982 }
4983 break;
4984 }
4985 case NORMAL:
4986 case FIELD:
4987 case CONSTANT_FUNCTION:
4988 case HANDLER:
4989 case INTERCEPTOR:
4990 case NULL_DESCRIPTOR:
4991 // We definitely have no map transition.
4992 index += 2;
4993 break;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004994 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004995 }
4996 *ContentHeader() = descriptor_array_->GetHeap()->fixed_array_map();
4997 return NULL;
4998 }
4999
5000 private:
5001 bool HasContentArray() {
5002 return descriptor_array_-> length() > DescriptorArray::kContentArrayIndex;
5003 }
5004
5005 FixedArray* ContentArray() {
5006 Object* array = descriptor_array_->get(DescriptorArray::kContentArrayIndex);
5007 return static_cast<FixedArray*>(array);
5008 }
5009
5010 Object** ContentHeader() {
5011 return HeapObject::RawField(ContentArray(), DescriptorArray::kMapOffset);
5012 }
5013
5014 DescriptorArray* descriptor_array_;
5015};
5016
5017
5018// An iterator over all prototype transitions, reusing the map field of the
5019// underlying array while it is running.
5020class IntrusivePrototypeTransitionIterator {
5021 public:
5022 explicit IntrusivePrototypeTransitionIterator(FixedArray* proto_trans)
5023 : proto_trans_(proto_trans) { }
5024
5025 void Start() {
5026 ASSERT(!IsIterating());
5027 if (HasTransitions()) *Header() = Smi::FromInt(0);
5028 }
5029
5030 bool IsIterating() {
5031 return HasTransitions() && (*Header())->IsSmi();
5032 }
5033
5034 Map* Next() {
5035 ASSERT(IsIterating());
5036 int transitionNumber = Smi::cast(*Header())->value();
5037 if (transitionNumber < NumberOfTransitions()) {
5038 *Header() = Smi::FromInt(transitionNumber + 1);
5039 return GetTransition(transitionNumber);
5040 }
5041 *Header() = proto_trans_->GetHeap()->fixed_array_map();
5042 return NULL;
5043 }
5044
5045 private:
5046 bool HasTransitions() {
5047 return proto_trans_->length() >= Map::kProtoTransitionHeaderSize;
5048 }
5049
5050 Object** Header() {
5051 return HeapObject::RawField(proto_trans_, FixedArray::kMapOffset);
5052 }
5053
5054 int NumberOfTransitions() {
5055 Object* num = proto_trans_->get(Map::kProtoTransitionNumberOfEntriesOffset);
5056 return Smi::cast(num)->value();
5057 }
5058
5059 Map* GetTransition(int transitionNumber) {
5060 return Map::cast(proto_trans_->get(IndexFor(transitionNumber)));
5061 }
5062
5063 int IndexFor(int transitionNumber) {
5064 return Map::kProtoTransitionHeaderSize +
5065 Map::kProtoTransitionMapOffset +
5066 transitionNumber * Map::kProtoTransitionElementsPerEntry;
5067 }
5068
5069 FixedArray* proto_trans_;
5070};
5071
5072
5073// To traverse the transition tree iteratively, we have to store two kinds of
5074// information in a map: The parent map in the traversal and which children of a
5075// node have already been visited. To do this without additional memory, we
5076// temporarily reuse two maps with known values:
5077//
5078// (1) The map of the map temporarily holds the parent, and is restored to the
5079// meta map afterwards.
5080//
5081// (2) The info which children have already been visited depends on which part
5082// of the map we currently iterate:
5083//
5084// (a) If we currently follow normal map transitions, we temporarily store
5085// the current index in the map of the FixedArray of the desciptor
5086// array's contents, and restore it to the fixed array map afterwards.
5087// Note that a single descriptor can have 0, 1, or 2 transitions.
5088//
5089// (b) If we currently follow prototype transitions, we temporarily store
5090// the current index in the map of the FixedArray holding the prototype
5091// transitions, and restore it to the fixed array map afterwards.
5092//
5093// Note that the child iterator is just a concatenation of two iterators: One
5094// iterating over map transitions and one iterating over prototype transisitons.
5095class TraversableMap : public Map {
5096 public:
5097 // Record the parent in the traversal within this map. Note that this destroys
5098 // this map's map!
5099 void SetParent(TraversableMap* parent) { set_map_no_write_barrier(parent); }
5100
5101 // Reset the current map's map, returning the parent previously stored in it.
5102 TraversableMap* GetAndResetParent() {
5103 TraversableMap* old_parent = static_cast<TraversableMap*>(map());
5104 set_map_no_write_barrier(GetHeap()->meta_map());
5105 return old_parent;
5106 }
5107
5108 // Start iterating over this map's children, possibly destroying a FixedArray
5109 // map (see explanation above).
5110 void ChildIteratorStart() {
5111 IntrusiveMapTransitionIterator(instance_descriptors()).Start();
5112 IntrusivePrototypeTransitionIterator(
5113 unchecked_prototype_transitions()).Start();
5114 }
5115
5116 // If we have an unvisited child map, return that one and advance. If we have
5117 // none, return NULL and reset any destroyed FixedArray maps.
5118 TraversableMap* ChildIteratorNext() {
5119 IntrusiveMapTransitionIterator descriptor_iterator(instance_descriptors());
5120 if (descriptor_iterator.IsIterating()) {
5121 Map* next = descriptor_iterator.Next();
5122 if (next != NULL) return static_cast<TraversableMap*>(next);
5123 }
5124 IntrusivePrototypeTransitionIterator
5125 proto_iterator(unchecked_prototype_transitions());
5126 if (proto_iterator.IsIterating()) {
5127 Map* next = proto_iterator.Next();
5128 if (next != NULL) return static_cast<TraversableMap*>(next);
5129 }
5130 return NULL;
5131 }
5132};
5133
5134
5135// Traverse the transition tree in postorder without using the C++ stack by
5136// doing pointer reversal.
5137void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
5138 TraversableMap* current = static_cast<TraversableMap*>(this);
5139 current->ChildIteratorStart();
5140 while (true) {
5141 TraversableMap* child = current->ChildIteratorNext();
5142 if (child != NULL) {
5143 child->ChildIteratorStart();
5144 child->SetParent(current);
5145 current = child;
5146 } else {
5147 TraversableMap* parent = current->GetAndResetParent();
5148 callback(current, data);
5149 if (current == this) break;
5150 current = parent;
5151 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005152 }
5153}
5154
5155
lrn@chromium.org303ada72010-10-27 09:33:13 +00005156MaybeObject* CodeCache::Update(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005157 // The number of monomorphic stubs for normal load/store/call IC's can grow to
5158 // a large number and therefore they need to go into a hash table. They are
5159 // used to load global properties from cells.
5160 if (code->type() == NORMAL) {
5161 // Make sure that a hash table is allocated for the normal load code cache.
5162 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005163 Object* result;
5164 { MaybeObject* maybe_result =
5165 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
5166 if (!maybe_result->ToObject(&result)) return maybe_result;
5167 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005168 set_normal_type_cache(result);
5169 }
5170 return UpdateNormalTypeCache(name, code);
5171 } else {
5172 ASSERT(default_cache()->IsFixedArray());
5173 return UpdateDefaultCache(name, code);
5174 }
5175}
5176
5177
lrn@chromium.org303ada72010-10-27 09:33:13 +00005178MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005179 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005180 // flags. This allows call constant stubs to overwrite call field
5181 // stubs, etc.
5182 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
5183
5184 // First check whether we can update existing code cache without
5185 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005186 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00005188 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005189 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005190 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00005191 if (key->IsNull()) {
5192 if (deleted_index < 0) deleted_index = i;
5193 continue;
5194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005195 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00005196 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005197 cache->set(i + kCodeCacheEntryNameOffset, name);
5198 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005199 return this;
5200 }
5201 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005202 Code::Flags found =
5203 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005205 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005206 return this;
5207 }
5208 }
5209 }
5210
ager@chromium.org236ad962008-09-25 09:45:57 +00005211 // Reached the end of the code cache. If there were deleted
5212 // elements, reuse the space for the first of them.
5213 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005214 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
5215 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00005216 return this;
5217 }
5218
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005219 // Extend the code cache with some new entries (at least one). Must be a
5220 // multiple of the entry size.
5221 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
5222 new_length = new_length - new_length % kCodeCacheEntrySize;
5223 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005224 Object* result;
5225 { MaybeObject* maybe_result = cache->CopySize(new_length);
5226 if (!maybe_result->ToObject(&result)) return maybe_result;
5227 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228
5229 // Add the (name, code) pair to the new cache.
5230 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005231 cache->set(length + kCodeCacheEntryNameOffset, name);
5232 cache->set(length + kCodeCacheEntryCodeOffset, code);
5233 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 return this;
5235}
5236
5237
lrn@chromium.org303ada72010-10-27 09:33:13 +00005238MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005239 // Adding a new entry can cause a new cache to be allocated.
5240 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00005241 Object* new_cache;
5242 { MaybeObject* maybe_new_cache = cache->Put(name, code);
5243 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5244 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005245 set_normal_type_cache(new_cache);
5246 return this;
5247}
5248
5249
5250Object* CodeCache::Lookup(String* name, Code::Flags flags) {
5251 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
5252 return LookupNormalTypeCache(name, flags);
5253 } else {
5254 return LookupDefaultCache(name, flags);
5255 }
5256}
5257
5258
5259Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
5260 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005261 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005262 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
5263 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00005264 // Skip deleted elements.
5265 if (key->IsNull()) continue;
5266 if (key->IsUndefined()) return key;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005268 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
5269 if (code->flags() == flags) {
5270 return code;
5271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005272 }
5273 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005274 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275}
5276
5277
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005278Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
5279 if (!normal_type_cache()->IsUndefined()) {
5280 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
5281 return cache->Lookup(name, flags);
5282 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005284 }
5285}
5286
5287
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005288int CodeCache::GetIndex(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005289 if (code->type() == NORMAL) {
5290 if (normal_type_cache()->IsUndefined()) return -1;
5291 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005292 return cache->GetIndex(String::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005293 }
5294
5295 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005296 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005297 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
5298 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005299 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005300 return -1;
5301}
5302
5303
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005304void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005305 if (code->type() == NORMAL) {
5306 ASSERT(!normal_type_cache()->IsUndefined());
5307 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00005308 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005309 cache->RemoveByIndex(index);
5310 } else {
5311 FixedArray* array = default_cache();
5312 ASSERT(array->length() >= index && array->get(index)->IsCode());
5313 // Use null instead of undefined for deleted elements to distinguish
5314 // deleted elements from unused elements. This distinction is used
5315 // when looking up in the cache and when updating the cache.
5316 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
5317 array->set_null(index - 1); // Name.
5318 array->set_null(index); // Code.
5319 }
5320}
5321
5322
5323// The key in the code cache hash table consists of the property name and the
5324// code object. The actual match is on the name and the code flags. If a key
5325// is created using the flags and not a code object it can only be used for
5326// lookup not to create a new entry.
5327class CodeCacheHashTableKey : public HashTableKey {
5328 public:
5329 CodeCacheHashTableKey(String* name, Code::Flags flags)
5330 : name_(name), flags_(flags), code_(NULL) { }
5331
5332 CodeCacheHashTableKey(String* name, Code* code)
5333 : name_(name),
5334 flags_(code->flags()),
5335 code_(code) { }
5336
5337
5338 bool IsMatch(Object* other) {
5339 if (!other->IsFixedArray()) return false;
5340 FixedArray* pair = FixedArray::cast(other);
5341 String* name = String::cast(pair->get(0));
5342 Code::Flags flags = Code::cast(pair->get(1))->flags();
5343 if (flags != flags_) {
5344 return false;
5345 }
5346 return name_->Equals(name);
5347 }
5348
5349 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
5350 return name->Hash() ^ flags;
5351 }
5352
5353 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
5354
5355 uint32_t HashForObject(Object* obj) {
5356 FixedArray* pair = FixedArray::cast(obj);
5357 String* name = String::cast(pair->get(0));
5358 Code* code = Code::cast(pair->get(1));
5359 return NameFlagsHashHelper(name, code->flags());
5360 }
5361
lrn@chromium.org303ada72010-10-27 09:33:13 +00005362 MUST_USE_RESULT MaybeObject* AsObject() {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005363 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005364 Object* obj;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005365 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005366 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5367 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005368 FixedArray* pair = FixedArray::cast(obj);
5369 pair->set(0, name_);
5370 pair->set(1, code_);
5371 return pair;
5372 }
5373
5374 private:
5375 String* name_;
5376 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005377 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005378 Code* code_;
5379};
5380
5381
5382Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
5383 CodeCacheHashTableKey key(name, flags);
5384 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005385 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005386 return get(EntryToIndex(entry) + 1);
5387}
5388
5389
lrn@chromium.org303ada72010-10-27 09:33:13 +00005390MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005391 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005392 Object* obj;
5393 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5394 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5395 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005396
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005397 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005398 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
5399
5400 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00005401 Object* k;
5402 { MaybeObject* maybe_k = key.AsObject();
5403 if (!maybe_k->ToObject(&k)) return maybe_k;
5404 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005405
5406 cache->set(EntryToIndex(entry), k);
5407 cache->set(EntryToIndex(entry) + 1, code);
5408 cache->ElementAdded();
5409 return cache;
5410}
5411
5412
5413int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
5414 CodeCacheHashTableKey key(name, flags);
5415 int entry = FindEntry(&key);
5416 return (entry == kNotFound) ? -1 : entry;
5417}
5418
5419
5420void CodeCacheHashTable::RemoveByIndex(int index) {
5421 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005422 Heap* heap = GetHeap();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00005423 set(EntryToIndex(index), heap->the_hole_value());
5424 set(EntryToIndex(index) + 1, heap->the_hole_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005425 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005426}
5427
5428
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005429void PolymorphicCodeCache::Update(Handle<PolymorphicCodeCache> cache,
5430 MapHandleList* maps,
5431 Code::Flags flags,
5432 Handle<Code> code) {
5433 Isolate* isolate = cache->GetIsolate();
5434 CALL_HEAP_FUNCTION_VOID(isolate, cache->Update(maps, flags, *code));
5435}
5436
5437
5438MaybeObject* PolymorphicCodeCache::Update(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005439 Code::Flags flags,
5440 Code* code) {
5441 // Initialize cache if necessary.
5442 if (cache()->IsUndefined()) {
5443 Object* result;
5444 { MaybeObject* maybe_result =
5445 PolymorphicCodeCacheHashTable::Allocate(
5446 PolymorphicCodeCacheHashTable::kInitialSize);
5447 if (!maybe_result->ToObject(&result)) return maybe_result;
5448 }
5449 set_cache(result);
5450 } else {
5451 // This entry shouldn't be contained in the cache yet.
5452 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
5453 ->Lookup(maps, flags)->IsUndefined());
5454 }
5455 PolymorphicCodeCacheHashTable* hash_table =
5456 PolymorphicCodeCacheHashTable::cast(cache());
5457 Object* new_cache;
5458 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
5459 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
5460 }
5461 set_cache(new_cache);
5462 return this;
5463}
5464
5465
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005466Handle<Object> PolymorphicCodeCache::Lookup(MapHandleList* maps,
5467 Code::Flags flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005468 if (!cache()->IsUndefined()) {
5469 PolymorphicCodeCacheHashTable* hash_table =
5470 PolymorphicCodeCacheHashTable::cast(cache());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005471 return Handle<Object>(hash_table->Lookup(maps, flags));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005472 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005473 return GetIsolate()->factory()->undefined_value();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005474 }
5475}
5476
5477
5478// Despite their name, object of this class are not stored in the actual
5479// hash table; instead they're temporarily used for lookups. It is therefore
5480// safe to have a weak (non-owning) pointer to a MapList as a member field.
5481class PolymorphicCodeCacheHashTableKey : public HashTableKey {
5482 public:
5483 // Callers must ensure that |maps| outlives the newly constructed object.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005484 PolymorphicCodeCacheHashTableKey(MapHandleList* maps, int code_flags)
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005485 : maps_(maps),
5486 code_flags_(code_flags) {}
5487
5488 bool IsMatch(Object* other) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005489 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005490 int other_flags;
5491 FromObject(other, &other_flags, &other_maps);
5492 if (code_flags_ != other_flags) return false;
5493 if (maps_->length() != other_maps.length()) return false;
5494 // Compare just the hashes first because it's faster.
5495 int this_hash = MapsHashHelper(maps_, code_flags_);
5496 int other_hash = MapsHashHelper(&other_maps, other_flags);
5497 if (this_hash != other_hash) return false;
5498
5499 // Full comparison: for each map in maps_, look for an equivalent map in
5500 // other_maps. This implementation is slow, but probably good enough for
5501 // now because the lists are short (<= 4 elements currently).
5502 for (int i = 0; i < maps_->length(); ++i) {
5503 bool match_found = false;
5504 for (int j = 0; j < other_maps.length(); ++j) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005505 if (maps_->at(i)->EquivalentTo(*other_maps.at(j))) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005506 match_found = true;
5507 break;
5508 }
5509 }
5510 if (!match_found) return false;
5511 }
5512 return true;
5513 }
5514
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005515 static uint32_t MapsHashHelper(MapHandleList* maps, int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005516 uint32_t hash = code_flags;
5517 for (int i = 0; i < maps->length(); ++i) {
5518 hash ^= maps->at(i)->Hash();
5519 }
5520 return hash;
5521 }
5522
5523 uint32_t Hash() {
5524 return MapsHashHelper(maps_, code_flags_);
5525 }
5526
5527 uint32_t HashForObject(Object* obj) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005528 MapHandleList other_maps(kDefaultListAllocationSize);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005529 int other_flags;
5530 FromObject(obj, &other_flags, &other_maps);
5531 return MapsHashHelper(&other_maps, other_flags);
5532 }
5533
5534 MUST_USE_RESULT MaybeObject* AsObject() {
5535 Object* obj;
5536 // The maps in |maps_| must be copied to a newly allocated FixedArray,
5537 // both because the referenced MapList is short-lived, and because C++
5538 // objects can't be stored in the heap anyway.
5539 { MaybeObject* maybe_obj =
5540 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
5541 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5542 }
5543 FixedArray* list = FixedArray::cast(obj);
5544 list->set(0, Smi::FromInt(code_flags_));
5545 for (int i = 0; i < maps_->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005546 list->set(i + 1, *maps_->at(i));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005547 }
5548 return list;
5549 }
5550
5551 private:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005552 static MapHandleList* FromObject(Object* obj,
5553 int* code_flags,
5554 MapHandleList* maps) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005555 FixedArray* list = FixedArray::cast(obj);
5556 maps->Rewind(0);
5557 *code_flags = Smi::cast(list->get(0))->value();
5558 for (int i = 1; i < list->length(); ++i) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005559 maps->Add(Handle<Map>(Map::cast(list->get(i))));
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005560 }
5561 return maps;
5562 }
5563
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005564 MapHandleList* maps_; // weak.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005565 int code_flags_;
whesse@chromium.org7b260152011-06-20 15:33:18 +00005566 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005567};
5568
5569
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005570Object* PolymorphicCodeCacheHashTable::Lookup(MapHandleList* maps,
5571 int code_flags) {
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005572 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5573 int entry = FindEntry(&key);
5574 if (entry == kNotFound) return GetHeap()->undefined_value();
5575 return get(EntryToIndex(entry) + 1);
5576}
5577
5578
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005579MaybeObject* PolymorphicCodeCacheHashTable::Put(MapHandleList* maps,
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00005580 int code_flags,
5581 Code* code) {
5582 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
5583 Object* obj;
5584 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
5585 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5586 }
5587 PolymorphicCodeCacheHashTable* cache =
5588 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
5589 int entry = cache->FindInsertionEntry(key.Hash());
5590 { MaybeObject* maybe_obj = key.AsObject();
5591 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5592 }
5593 cache->set(EntryToIndex(entry), obj);
5594 cache->set(EntryToIndex(entry) + 1, code);
5595 cache->ElementAdded();
5596 return cache;
5597}
5598
5599
lrn@chromium.org303ada72010-10-27 09:33:13 +00005600MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005601 ElementsAccessor* accessor = array->GetElementsAccessor();
5602 MaybeObject* maybe_result =
rossberg@chromium.org28a37082011-08-22 11:03:23 +00005603 accessor->AddElementsToFixedArray(array->elements(), this, array, array);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005604 FixedArray* result;
5605 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
5606#ifdef DEBUG
5607 if (FLAG_enable_slow_asserts) {
5608 for (int i = 0; i < result->length(); i++) {
5609 Object* current = result->get(i);
5610 ASSERT(current->IsNumber() || current->IsString());
5611 }
5612 }
5613#endif
5614 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005615}
5616
5617
lrn@chromium.org303ada72010-10-27 09:33:13 +00005618MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00005619 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
5620 MaybeObject* maybe_result =
5621 accessor->AddElementsToFixedArray(other, this, NULL, NULL);
5622 FixedArray* result;
5623 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005624#ifdef DEBUG
5625 if (FLAG_enable_slow_asserts) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00005626 for (int i = 0; i < result->length(); i++) {
5627 Object* current = result->get(i);
5628 ASSERT(current->IsNumber() || current->IsString());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00005629 }
5630 }
5631#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632 return result;
5633}
5634
5635
lrn@chromium.org303ada72010-10-27 09:33:13 +00005636MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005637 Heap* heap = GetHeap();
5638 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00005639 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005640 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005641 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5642 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005644 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005645 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005646 int len = length();
5647 if (new_length < len) len = new_length;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005648 // We are taking the map from the old fixed array so the map is sure to
5649 // be an immortal immutable object.
5650 result->set_map_no_write_barrier(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005651 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005652 for (int i = 0; i < len; i++) {
5653 result->set(i, get(i), mode);
5654 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005655 return result;
5656}
5657
5658
5659void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005660 AssertNoAllocation no_gc;
5661 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005662 for (int index = 0; index < len; index++) {
5663 dest->set(dest_pos+index, get(pos+index), mode);
5664 }
5665}
5666
5667
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005668#ifdef DEBUG
5669bool FixedArray::IsEqualTo(FixedArray* other) {
5670 if (length() != other->length()) return false;
5671 for (int i = 0 ; i < length(); ++i) {
5672 if (get(i) != other->get(i)) return false;
5673 }
5674 return true;
5675}
5676#endif
5677
5678
lrn@chromium.org303ada72010-10-27 09:33:13 +00005679MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005680 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005681 if (number_of_descriptors == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005682 return heap->empty_descriptor_array();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005683 }
5684 // Allocate the array of keys.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685 Object* array;
5686 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005687 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
lrn@chromium.org303ada72010-10-27 09:33:13 +00005688 if (!maybe_array->ToObject(&array)) return maybe_array;
5689 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005690 // Do not use DescriptorArray::cast on incomplete object.
5691 FixedArray* result = FixedArray::cast(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005692
5693 // Allocate the content array and set it in the descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005694 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005695 heap->AllocateFixedArray(number_of_descriptors << 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005696 if (!maybe_array->ToObject(&array)) return maybe_array;
5697 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00005698 result->set(kBitField3StorageIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005699 result->set(kContentArrayIndex, array);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005700 result->set(kEnumerationIndexIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005701 Smi::FromInt(PropertyDetails::kInitialIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005702 return result;
5703}
5704
5705
5706void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
5707 FixedArray* new_cache) {
5708 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
5709 if (HasEnumCache()) {
5710 FixedArray::cast(get(kEnumerationIndexIndex))->
5711 set(kEnumCacheBridgeCacheIndex, new_cache);
5712 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005713 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005714 FixedArray::cast(bridge_storage)->
5715 set(kEnumCacheBridgeCacheIndex, new_cache);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005716 NoWriteBarrierSet(FixedArray::cast(bridge_storage),
5717 kEnumCacheBridgeEnumIndex,
5718 get(kEnumerationIndexIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005719 set(kEnumerationIndexIndex, bridge_storage);
5720 }
5721}
5722
5723
lrn@chromium.org303ada72010-10-27 09:33:13 +00005724MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
5725 TransitionFlag transition_flag) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005726 // Transitions are only kept when inserting another transition.
5727 // This precondition is not required by this function's implementation, but
5728 // is currently required by the semantics of maps, so we check it.
5729 // Conversely, we filter after replacing, so replacing a transition and
5730 // removing all other transitions is not supported.
5731 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005732 ASSERT(remove_transitions == !descriptor->ContainsTransition());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005733 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005734
5735 // Ensure the key is a symbol.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005736 Object* result;
5737 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
5738 if (!maybe_result->ToObject(&result)) return maybe_result;
5739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005740
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005741 int new_size = 0;
5742 for (int i = 0; i < number_of_descriptors(); i++) {
5743 if (IsNullDescriptor(i)) continue;
5744 if (remove_transitions && IsTransitionOnly(i)) continue;
5745 new_size++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005747
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005748 // If key is in descriptor, we replace it in-place when filtering.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005749 // Count a null descriptor for key as inserted, not replaced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005750 int index = Search(descriptor->GetKey());
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005751 const bool replacing = (index != kNotFound);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005752 bool keep_enumeration_index = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005753 if (replacing) {
5754 // We are replacing an existing descriptor. We keep the enumeration
5755 // index of a visible property.
5756 PropertyType t = PropertyDetails(GetDetails(index)).type();
5757 if (t == CONSTANT_FUNCTION ||
5758 t == FIELD ||
5759 t == CALLBACKS ||
5760 t == INTERCEPTOR) {
5761 keep_enumeration_index = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005762 } else if (remove_transitions) {
5763 // Replaced descriptor has been counted as removed if it is
5764 // a transition that will be replaced. Adjust count in this case.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005765 ++new_size;
5766 }
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005767 } else {
5768 ++new_size;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005769 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005770
5771 DescriptorArray* new_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005772 { MaybeObject* maybe_result = Allocate(new_size);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005773 if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
5774 return maybe_result;
5775 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005776 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005777
5778 DescriptorArray::WhitenessWitness witness(new_descriptors);
5779
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005780 // Set the enumeration index in the descriptors and set the enumeration index
5781 // in the result.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005782 int enumeration_index = NextEnumerationIndex();
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005783 if (!descriptor->ContainsTransition()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005784 if (keep_enumeration_index) {
5785 descriptor->SetEnumerationIndex(
5786 PropertyDetails(GetDetails(index)).index());
5787 } else {
5788 descriptor->SetEnumerationIndex(enumeration_index);
5789 ++enumeration_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005790 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005791 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005792 new_descriptors->SetNextEnumerationIndex(enumeration_index);
5793
5794 // Copy the descriptors, filtering out transitions and null descriptors,
5795 // and inserting or replacing a descriptor.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005796 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005797 int from_index = 0;
5798 int to_index = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005799
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005800 for (; from_index < number_of_descriptors(); from_index++) {
5801 String* key = GetKey(from_index);
5802 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
5803 break;
5804 }
5805 if (IsNullDescriptor(from_index)) continue;
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005806 if (remove_transitions && IsTransitionOnly(from_index)) continue;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005807 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005808 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005809
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005810 new_descriptors->Set(to_index++, descriptor, witness);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005811 if (replacing) from_index++;
5812
5813 for (; from_index < number_of_descriptors(); from_index++) {
5814 if (IsNullDescriptor(from_index)) continue;
rossberg@chromium.org994edf62012-02-06 10:12:55 +00005815 if (remove_transitions && IsTransitionOnly(from_index)) continue;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005816 new_descriptors->CopyFrom(to_index++, this, from_index, witness);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005817 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005818
5819 ASSERT(to_index == new_descriptors->number_of_descriptors());
5820 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005821
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005822 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005823}
5824
5825
lrn@chromium.org303ada72010-10-27 09:33:13 +00005826MaybeObject* DescriptorArray::RemoveTransitions() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005827 // Remove all transitions and null descriptors. Return a copy of the array
5828 // with all transitions removed, or a Failure object if the new array could
5829 // not be allocated.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005830
5831 // Compute the size of the map transition entries to be removed.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005832 int num_removed = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005833 for (int i = 0; i < number_of_descriptors(); i++) {
5834 if (!IsProperty(i)) num_removed++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005835 }
5836
5837 // Allocate the new descriptor array.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005838 DescriptorArray* new_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005839 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005840 if (!maybe_result->To<DescriptorArray>(&new_descriptors)) {
5841 return maybe_result;
5842 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005843 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005844
5845 DescriptorArray::WhitenessWitness witness(new_descriptors);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005846
5847 // Copy the content.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005848 int next_descriptor = 0;
5849 for (int i = 0; i < number_of_descriptors(); i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005850 if (IsProperty(i)) {
5851 new_descriptors->CopyFrom(next_descriptor++, this, i, witness);
5852 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005853 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005854 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005855
5856 return new_descriptors;
5857}
5858
5859
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005860void DescriptorArray::SortUnchecked(const WhitenessWitness& witness) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005861 // In-place heap sort.
5862 int len = number_of_descriptors();
5863
5864 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005865 // Index of the last node with children
5866 const int max_parent_index = (len / 2) - 1;
5867 for (int i = max_parent_index; i >= 0; --i) {
5868 int parent_index = i;
5869 const uint32_t parent_hash = GetKey(i)->Hash();
5870 while (parent_index <= max_parent_index) {
5871 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005873 if (child_index + 1 < len) {
5874 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5875 if (right_child_hash > child_hash) {
5876 child_index++;
5877 child_hash = right_child_hash;
5878 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005879 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005880 if (child_hash <= parent_hash) break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005881 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005882 // Now element at child_index could be < its children.
5883 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005884 }
5885 }
5886
5887 // Extract elements and create sorted array.
5888 for (int i = len - 1; i > 0; --i) {
5889 // Put max element at the back of the array.
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005890 NoIncrementalWriteBarrierSwapDescriptors(0, i);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005891 // Shift down the new top element.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005892 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005893 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5894 const int max_parent_index = (i / 2) - 1;
5895 while (parent_index <= max_parent_index) {
5896 int child_index = parent_index * 2 + 1;
5897 uint32_t child_hash = GetKey(child_index)->Hash();
5898 if (child_index + 1 < i) {
5899 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5900 if (right_child_hash > child_hash) {
5901 child_index++;
5902 child_hash = right_child_hash;
5903 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005904 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005905 if (child_hash <= parent_hash) break;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00005906 NoIncrementalWriteBarrierSwapDescriptors(parent_index, child_index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005907 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005908 }
5909 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005910}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005911
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00005912
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005913void DescriptorArray::Sort(const WhitenessWitness& witness) {
5914 SortUnchecked(witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915 SLOW_ASSERT(IsSortedNoDuplicates());
5916}
5917
5918
5919int DescriptorArray::BinarySearch(String* name, int low, int high) {
5920 uint32_t hash = name->Hash();
5921
5922 while (low <= high) {
5923 int mid = (low + high) / 2;
5924 String* mid_name = GetKey(mid);
5925 uint32_t mid_hash = mid_name->Hash();
5926
5927 if (mid_hash > hash) {
5928 high = mid - 1;
5929 continue;
5930 }
5931 if (mid_hash < hash) {
5932 low = mid + 1;
5933 continue;
5934 }
5935 // Found an element with the same hash-code.
5936 ASSERT(hash == mid_hash);
5937 // There might be more, so we find the first one and
5938 // check them all to see if we have a match.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005939 if (name == mid_name && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005940 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5941 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005942 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005943 }
5944 break;
5945 }
5946 return kNotFound;
5947}
5948
5949
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005950int DescriptorArray::LinearSearch(String* name, int len) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005951 uint32_t hash = name->Hash();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005952 for (int number = 0; number < len; number++) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005953 String* entry = GetKey(number);
5954 if ((entry->Hash() == hash) &&
5955 name->Equals(entry) &&
5956 !is_null_descriptor(number)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005957 return number;
5958 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005959 }
5960 return kNotFound;
5961}
5962
5963
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005964MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5965 PretenureFlag pretenure) {
5966 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005967 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005968 pretenure);
5969}
5970
5971
5972MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5973 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005974 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5975 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005976 pretenure);
5977}
5978
5979
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005980#ifdef DEBUG
5981bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5982 if (IsEmpty()) return other->IsEmpty();
5983 if (other->IsEmpty()) return false;
5984 if (length() != other->length()) return false;
5985 for (int i = 0; i < length(); ++i) {
5986 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5987 }
5988 return GetContentArray()->IsEqualTo(other->GetContentArray());
5989}
5990#endif
5991
5992
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005994 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005995 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005996}
5997
5998
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005999String::FlatContent String::GetFlatContent() {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006000 int length = this->length();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006001 StringShape shape(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006002 String* string = this;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006003 int offset = 0;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006004 if (shape.representation_tag() == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006005 ConsString* cons = ConsString::cast(string);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006006 if (cons->second()->length() != 0) {
6007 return FlatContent();
6008 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006009 string = cons->first();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006010 shape = StringShape(string);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006011 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006012 if (shape.representation_tag() == kSlicedStringTag) {
6013 SlicedString* slice = SlicedString::cast(string);
6014 offset = slice->offset();
6015 string = slice->parent();
6016 shape = StringShape(string);
6017 ASSERT(shape.representation_tag() != kConsStringTag &&
6018 shape.representation_tag() != kSlicedStringTag);
6019 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006020 if (shape.encoding_tag() == kAsciiStringTag) {
6021 const char* start;
6022 if (shape.representation_tag() == kSeqStringTag) {
6023 start = SeqAsciiString::cast(string)->GetChars();
6024 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00006025 start = ExternalAsciiString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006026 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006027 return FlatContent(Vector<const char>(start + offset, length));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006028 } else {
6029 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
6030 const uc16* start;
6031 if (shape.representation_tag() == kSeqStringTag) {
6032 start = SeqTwoByteString::cast(string)->GetChars();
6033 } else {
erikcorry0ad885c2011-11-21 13:51:57 +00006034 start = ExternalTwoByteString::cast(string)->GetChars();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006035 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006036 return FlatContent(Vector<const uc16>(start + offset, length));
ager@chromium.org7c537e22008-10-16 08:43:32 +00006037 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006038}
6039
6040
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006041SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6042 RobustnessFlag robust_flag,
6043 int offset,
6044 int length,
6045 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006047 return SmartArrayPointer<char>(NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006049 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006050
6051 // Negative length means the to the end of the string.
6052 if (length < 0) length = kMaxInt - offset;
6053
6054 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006055 Access<StringInputBuffer> buffer(
6056 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057 buffer->Reset(offset, this);
6058 int character_position = offset;
6059 int utf8_bytes = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006060 while (buffer->has_more() && character_position++ < offset + length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006061 uint16_t character = buffer->GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00006062 utf8_bytes += unibrow::Utf8::Length(character);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006063 }
6064
6065 if (length_return) {
6066 *length_return = utf8_bytes;
6067 }
6068
6069 char* result = NewArray<char>(utf8_bytes + 1);
6070
6071 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
6072 buffer->Rewind();
6073 buffer->Seek(offset);
6074 character_position = offset;
6075 int utf8_byte_position = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006076 while (buffer->has_more() && character_position++ < offset + length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006077 uint16_t character = buffer->GetNext();
danno@chromium.orgc612e022011-11-10 11:38:15 +00006078 if (allow_nulls == DISALLOW_NULLS && character == 0) {
6079 character = ' ';
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006080 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00006081 utf8_byte_position +=
6082 unibrow::Utf8::Encode(result + utf8_byte_position, character);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006083 }
6084 result[utf8_byte_position] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006085 return SmartArrayPointer<char>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006086}
6087
6088
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006089SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
6090 RobustnessFlag robust_flag,
6091 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006092 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
6093}
6094
6095
6096const uc16* String::GetTwoByteData() {
6097 return GetTwoByteData(0);
6098}
6099
6100
6101const uc16* String::GetTwoByteData(unsigned start) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006102 ASSERT(!IsAsciiRepresentationUnderneath());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006103 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006104 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00006105 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006106 case kExternalStringTag:
6107 return ExternalTwoByteString::cast(this)->
6108 ExternalTwoByteStringGetData(start);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006109 case kSlicedStringTag: {
6110 SlicedString* slice = SlicedString::cast(this);
6111 return slice->parent()->GetTwoByteData(start + slice->offset());
6112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113 case kConsStringTag:
6114 UNREACHABLE();
6115 return NULL;
6116 }
6117 UNREACHABLE();
6118 return NULL;
6119}
6120
6121
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006122SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006123 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006124 return SmartArrayPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006125 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006126 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006128 Access<StringInputBuffer> buffer(
6129 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130 buffer->Reset(this);
6131
6132 uc16* result = NewArray<uc16>(length() + 1);
6133
6134 int i = 0;
6135 while (buffer->has_more()) {
6136 uint16_t character = buffer->GetNext();
6137 result[i++] = character;
6138 }
6139 result[i] = 0;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00006140 return SmartArrayPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006141}
6142
6143
ager@chromium.org7c537e22008-10-16 08:43:32 +00006144const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145 return reinterpret_cast<uc16*>(
6146 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
6147}
6148
6149
ager@chromium.org7c537e22008-10-16 08:43:32 +00006150void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00006151 unsigned* offset_ptr,
6152 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006153 unsigned chars_read = 0;
6154 unsigned offset = *offset_ptr;
6155 while (chars_read < max_chars) {
6156 uint16_t c = *reinterpret_cast<uint16_t*>(
6157 reinterpret_cast<char*>(this) -
6158 kHeapObjectTag + kHeaderSize + offset * kShortSize);
6159 if (c <= kMaxAsciiCharCode) {
6160 // Fast case for ASCII characters. Cursor is an input output argument.
6161 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6162 rbb->util_buffer,
6163 rbb->capacity,
6164 rbb->cursor)) {
6165 break;
6166 }
6167 } else {
6168 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6169 rbb->util_buffer,
6170 rbb->capacity,
6171 rbb->cursor)) {
6172 break;
6173 }
6174 }
6175 offset++;
6176 chars_read++;
6177 }
6178 *offset_ptr = offset;
6179 rbb->remaining += chars_read;
6180}
6181
6182
ager@chromium.org7c537e22008-10-16 08:43:32 +00006183const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
6184 unsigned* remaining,
6185 unsigned* offset_ptr,
6186 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
6188 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
6189 *remaining = max_chars;
6190 *offset_ptr += max_chars;
6191 return b;
6192}
6193
6194
6195// This will iterate unless the block of string data spans two 'halves' of
6196// a ConsString, in which case it will recurse. Since the block of string
6197// data to be read has a maximum size this limits the maximum recursion
6198// depth to something sane. Since C++ does not have tail call recursion
6199// elimination, the iteration must be explicit. Since this is not an
6200// -IntoBuffer method it can delegate to one of the efficient
6201// *AsciiStringReadBlock routines.
6202const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
6203 unsigned* offset_ptr,
6204 unsigned max_chars) {
6205 ConsString* current = this;
6206 unsigned offset = *offset_ptr;
6207 int offset_correction = 0;
6208
6209 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006210 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006211 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006212 if (left_length > offset &&
6213 (max_chars <= left_length - offset ||
6214 (rbb->capacity <= left_length - offset &&
6215 (max_chars = left_length - offset, true)))) { // comma operator!
6216 // Left hand side only - iterate unless we have reached the bottom of
6217 // the cons tree. The assignment on the left of the comma operator is
6218 // in order to make use of the fact that the -IntoBuffer routines can
6219 // produce at most 'capacity' characters. This enables us to postpone
6220 // the point where we switch to the -IntoBuffer routines (below) in order
6221 // to maximize the chances of delegating a big chunk of work to the
6222 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006223 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006224 current = ConsString::cast(left);
6225 continue;
6226 } else {
6227 const unibrow::byte* answer =
6228 String::ReadBlock(left, rbb, &offset, max_chars);
6229 *offset_ptr = offset + offset_correction;
6230 return answer;
6231 }
6232 } else if (left_length <= offset) {
6233 // Right hand side only - iterate unless we have reached the bottom of
6234 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00006235 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006236 offset -= left_length;
6237 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006238 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239 current = ConsString::cast(right);
6240 continue;
6241 } else {
6242 const unibrow::byte* answer =
6243 String::ReadBlock(right, rbb, &offset, max_chars);
6244 *offset_ptr = offset + offset_correction;
6245 return answer;
6246 }
6247 } else {
6248 // The block to be read spans two sides of the ConsString, so we call the
6249 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
6250 // are able to assemble data from several part strings because they use
6251 // the util_buffer to store their data and never return direct pointers
6252 // to their storage. We don't try to read more than the buffer capacity
6253 // here or we can get too much recursion.
6254 ASSERT(rbb->remaining == 0);
6255 ASSERT(rbb->cursor == 0);
6256 current->ConsStringReadBlockIntoBuffer(
6257 rbb,
6258 &offset,
6259 max_chars > rbb->capacity ? rbb->capacity : max_chars);
6260 *offset_ptr = offset + offset_correction;
6261 return rbb->util_buffer;
6262 }
6263 }
6264}
6265
6266
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006267const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
6268 unsigned* remaining,
6269 unsigned* offset_ptr,
6270 unsigned max_chars) {
6271 // Cast const char* to unibrow::byte* (signedness difference).
6272 const unibrow::byte* b =
erikcorry0ad885c2011-11-21 13:51:57 +00006273 reinterpret_cast<const unibrow::byte*>(GetChars()) + *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006274 *remaining = max_chars;
6275 *offset_ptr += max_chars;
6276 return b;
6277}
6278
6279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006280void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
6281 ReadBlockBuffer* rbb,
6282 unsigned* offset_ptr,
6283 unsigned max_chars) {
6284 unsigned chars_read = 0;
6285 unsigned offset = *offset_ptr;
erikcorry0ad885c2011-11-21 13:51:57 +00006286 const uint16_t* data = GetChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006287 while (chars_read < max_chars) {
6288 uint16_t c = data[offset];
6289 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00006290 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006291 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
6292 rbb->util_buffer,
6293 rbb->capacity,
6294 rbb->cursor))
6295 break;
6296 } else {
6297 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
6298 rbb->util_buffer,
6299 rbb->capacity,
6300 rbb->cursor))
6301 break;
6302 }
6303 offset++;
6304 chars_read++;
6305 }
6306 *offset_ptr = offset;
6307 rbb->remaining += chars_read;
6308}
6309
6310
ager@chromium.org7c537e22008-10-16 08:43:32 +00006311void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006312 unsigned* offset_ptr,
6313 unsigned max_chars) {
6314 unsigned capacity = rbb->capacity - rbb->cursor;
6315 if (max_chars > capacity) max_chars = capacity;
6316 memcpy(rbb->util_buffer + rbb->cursor,
6317 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
6318 *offset_ptr * kCharSize,
6319 max_chars);
6320 rbb->remaining += max_chars;
6321 *offset_ptr += max_chars;
6322 rbb->cursor += max_chars;
6323}
6324
6325
6326void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
6327 ReadBlockBuffer* rbb,
6328 unsigned* offset_ptr,
6329 unsigned max_chars) {
6330 unsigned capacity = rbb->capacity - rbb->cursor;
6331 if (max_chars > capacity) max_chars = capacity;
erikcorry0ad885c2011-11-21 13:51:57 +00006332 memcpy(rbb->util_buffer + rbb->cursor, GetChars() + *offset_ptr, max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333 rbb->remaining += max_chars;
6334 *offset_ptr += max_chars;
6335 rbb->cursor += max_chars;
6336}
6337
6338
6339// This method determines the type of string involved and then copies
6340// a whole chunk of characters into a buffer, or returns a pointer to a buffer
6341// where they can be found. The pointer is not necessarily valid across a GC
6342// (see AsciiStringReadBlock).
6343const unibrow::byte* String::ReadBlock(String* input,
6344 ReadBlockBuffer* rbb,
6345 unsigned* offset_ptr,
6346 unsigned max_chars) {
6347 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
6348 if (max_chars == 0) {
6349 rbb->remaining = 0;
6350 return NULL;
6351 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006352 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006353 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006354 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006355 SeqAsciiString* str = SeqAsciiString::cast(input);
6356 return str->SeqAsciiStringReadBlock(&rbb->remaining,
6357 offset_ptr,
6358 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006359 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006360 SeqTwoByteString* str = SeqTwoByteString::cast(input);
6361 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
6362 offset_ptr,
6363 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006364 return rbb->util_buffer;
6365 }
6366 case kConsStringTag:
6367 return ConsString::cast(input)->ConsStringReadBlock(rbb,
6368 offset_ptr,
6369 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006370 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006371 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006372 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
6373 &rbb->remaining,
6374 offset_ptr,
6375 max_chars);
6376 } else {
6377 ExternalTwoByteString::cast(input)->
6378 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6379 offset_ptr,
6380 max_chars);
6381 return rbb->util_buffer;
6382 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006383 case kSlicedStringTag:
6384 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
6385 offset_ptr,
6386 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006387 default:
6388 break;
6389 }
6390
6391 UNREACHABLE();
6392 return 0;
6393}
6394
6395
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00006396// This method determines the type of string involved and then gets the UTF8
6397// length of the string. It doesn't flatten the string and has log(n) recursion
6398// for a string of length n.
6399int String::Utf8Length(String* input, int from, int to) {
6400 if (from == to) return 0;
6401 int total = 0;
6402 while (true) {
6403 if (input->IsAsciiRepresentation()) return total + to - from;
6404 switch (StringShape(input).representation_tag()) {
6405 case kConsStringTag: {
6406 ConsString* str = ConsString::cast(input);
6407 String* first = str->first();
6408 String* second = str->second();
6409 int first_length = first->length();
6410 if (first_length - from < to - first_length) {
6411 if (first_length > from) {
6412 // Left hand side is shorter.
6413 total += Utf8Length(first, from, first_length);
6414 input = second;
6415 from = 0;
6416 to -= first_length;
6417 } else {
6418 // We only need the right hand side.
6419 input = second;
6420 from -= first_length;
6421 to -= first_length;
6422 }
6423 } else {
6424 if (first_length <= to) {
6425 // Right hand side is shorter.
6426 total += Utf8Length(second, 0, to - first_length);
6427 input = first;
6428 to = first_length;
6429 } else {
6430 // We only need the left hand side.
6431 input = first;
6432 }
6433 }
6434 continue;
6435 }
6436 case kExternalStringTag:
6437 case kSeqStringTag: {
6438 Vector<const uc16> vector = input->GetFlatContent().ToUC16Vector();
6439 const uc16* p = vector.start();
6440 for (int i = from; i < to; i++) {
6441 total += unibrow::Utf8::Length(p[i]);
6442 }
6443 return total;
6444 }
6445 case kSlicedStringTag: {
6446 SlicedString* str = SlicedString::cast(input);
6447 int offset = str->offset();
6448 input = str->parent();
6449 from += offset;
6450 to += offset;
6451 continue;
6452 }
6453 default:
6454 break;
6455 }
6456 UNREACHABLE();
6457 return 0;
6458 }
6459 return 0;
6460}
6461
6462
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006463void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006464 Isolate* isolate = Isolate::Current();
6465 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006466 while (current != NULL) {
6467 current->PostGarbageCollection();
6468 current = current->prev_;
6469 }
6470}
6471
6472
6473// Reserve space for statics needing saving and restoring.
6474int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006476}
6477
6478
6479// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006480char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006481 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
6482 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006483 return to + ArchiveSpacePerThread();
6484}
6485
6486
6487// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00006488char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006489 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006490 return from + ArchiveSpacePerThread();
6491}
6492
6493
6494char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
6495 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
6496 Iterate(v, top);
6497 return thread_storage + ArchiveSpacePerThread();
6498}
6499
6500
6501void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 Isolate* isolate = Isolate::Current();
6503 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006504}
6505
6506
6507void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
6508 Relocatable* current = top;
6509 while (current != NULL) {
6510 current->IterateInstance(v);
6511 current = current->prev_;
6512 }
6513}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006514
6515
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006516FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
6517 : Relocatable(isolate),
6518 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006519 length_(str->length()) {
6520 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006521}
6522
6523
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
6525 : Relocatable(isolate),
6526 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006527 is_ascii_(true),
6528 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006529 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006530
6531
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006532void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006533 if (str_ == NULL) return;
6534 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006535 ASSERT(str->IsFlat());
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006536 String::FlatContent content = str->GetFlatContent();
6537 ASSERT(content.IsFlat());
6538 is_ascii_ = content.IsAscii();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006539 if (is_ascii_) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006540 start_ = content.ToAsciiVector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006541 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006542 start_ = content.ToUC16Vector().start();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006543 }
6544}
6545
6546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006547void StringInputBuffer::Seek(unsigned pos) {
6548 Reset(pos, input_);
6549}
6550
6551
6552void SafeStringInputBuffer::Seek(unsigned pos) {
6553 Reset(pos, input_);
6554}
6555
6556
6557// This method determines the type of string involved and then copies
6558// a whole chunk of characters into a buffer. It can be used with strings
6559// that have been glued together to form a ConsString and which must cooperate
6560// to fill up a buffer.
6561void String::ReadBlockIntoBuffer(String* input,
6562 ReadBlockBuffer* rbb,
6563 unsigned* offset_ptr,
6564 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006565 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006566 if (max_chars == 0) return;
6567
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006568 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006570 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006571 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572 offset_ptr,
6573 max_chars);
6574 return;
6575 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006576 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577 offset_ptr,
6578 max_chars);
6579 return;
6580 }
6581 case kConsStringTag:
6582 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
6583 offset_ptr,
6584 max_chars);
6585 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006586 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00006587 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006588 ExternalAsciiString::cast(input)->
6589 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
6590 } else {
6591 ExternalTwoByteString::cast(input)->
6592 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
6593 offset_ptr,
6594 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595 }
6596 return;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006597 case kSlicedStringTag:
6598 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
6599 offset_ptr,
6600 max_chars);
6601 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006602 default:
6603 break;
6604 }
6605
6606 UNREACHABLE();
6607 return;
6608}
6609
6610
6611const unibrow::byte* String::ReadBlock(String* input,
6612 unibrow::byte* util_buffer,
6613 unsigned capacity,
6614 unsigned* remaining,
6615 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006616 ASSERT(*offset_ptr <= (unsigned)input->length());
6617 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6619 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006620 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006621 *remaining = rbb.remaining;
6622 return answer;
6623}
6624
6625
6626const unibrow::byte* String::ReadBlock(String** raw_input,
6627 unibrow::byte* util_buffer,
6628 unsigned capacity,
6629 unsigned* remaining,
6630 unsigned* offset_ptr) {
6631 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006632 ASSERT(*offset_ptr <= (unsigned)input->length());
6633 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634 if (chars > capacity) chars = capacity;
6635 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
6636 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006637 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006638 *remaining = rbb.remaining;
6639 return rbb.util_buffer;
6640}
6641
6642
6643// This will iterate unless the block of string data spans two 'halves' of
6644// a ConsString, in which case it will recurse. Since the block of string
6645// data to be read has a maximum size this limits the maximum recursion
6646// depth to something sane. Since C++ does not have tail call recursion
6647// elimination, the iteration must be explicit.
6648void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
6649 unsigned* offset_ptr,
6650 unsigned max_chars) {
6651 ConsString* current = this;
6652 unsigned offset = *offset_ptr;
6653 int offset_correction = 0;
6654
6655 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006656 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006657 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006658 if (left_length > offset &&
6659 max_chars <= left_length - offset) {
6660 // Left hand side only - iterate unless we have reached the bottom of
6661 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006662 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006663 current = ConsString::cast(left);
6664 continue;
6665 } else {
6666 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
6667 *offset_ptr = offset + offset_correction;
6668 return;
6669 }
6670 } else if (left_length <= offset) {
6671 // Right hand side only - iterate unless we have reached the bottom of
6672 // the cons tree.
6673 offset -= left_length;
6674 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006675 String* right = current->second();
6676 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677 current = ConsString::cast(right);
6678 continue;
6679 } else {
6680 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6681 *offset_ptr = offset + offset_correction;
6682 return;
6683 }
6684 } else {
6685 // The block to be read spans two sides of the ConsString, so we recurse.
6686 // First recurse on the left.
6687 max_chars -= left_length - offset;
6688 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
6689 // We may have reached the max or there may not have been enough space
6690 // in the buffer for the characters in the left hand side.
6691 if (offset == left_length) {
6692 // Recurse on the right.
6693 String* right = String::cast(current->second());
6694 offset -= left_length;
6695 offset_correction += left_length;
6696 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
6697 }
6698 *offset_ptr = offset + offset_correction;
6699 return;
6700 }
6701 }
6702}
6703
6704
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006705uint16_t ConsString::ConsStringGet(int index) {
6706 ASSERT(index >= 0 && index < this->length());
6707
6708 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00006709 if (second()->length() == 0) {
6710 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006711 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006712 }
6713
6714 String* string = String::cast(this);
6715
6716 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006717 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006718 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006719 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006720 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006721 string = left;
6722 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006723 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006724 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006725 }
6726 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006727 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006728 }
6729 }
6730
6731 UNREACHABLE();
6732 return 0;
6733}
6734
6735
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006736uint16_t SlicedString::SlicedStringGet(int index) {
6737 return parent()->Get(offset() + index);
6738}
6739
6740
6741const unibrow::byte* SlicedString::SlicedStringReadBlock(
6742 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6743 unsigned offset = this->offset();
6744 *offset_ptr += offset;
6745 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
6746 buffer, offset_ptr, chars);
6747 *offset_ptr -= offset;
6748 return answer;
6749}
6750
6751
6752void SlicedString::SlicedStringReadBlockIntoBuffer(
6753 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
6754 unsigned offset = this->offset();
6755 *offset_ptr += offset;
6756 String::ReadBlockIntoBuffer(String::cast(parent()),
6757 buffer, offset_ptr, chars);
6758 *offset_ptr -= offset;
6759}
6760
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006761template <typename sinkchar>
6762void String::WriteToFlat(String* src,
6763 sinkchar* sink,
6764 int f,
6765 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 String* source = src;
6767 int from = f;
6768 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006770 ASSERT(0 <= from && from <= to && to <= source->length());
6771 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006772 case kAsciiStringTag | kExternalStringTag: {
6773 CopyChars(sink,
erikcorry0ad885c2011-11-21 13:51:57 +00006774 ExternalAsciiString::cast(source)->GetChars() + from,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006775 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 return;
6777 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006778 case kTwoByteStringTag | kExternalStringTag: {
6779 const uc16* data =
erikcorry0ad885c2011-11-21 13:51:57 +00006780 ExternalTwoByteString::cast(source)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006781 CopyChars(sink,
6782 data + from,
6783 to - from);
6784 return;
6785 }
6786 case kAsciiStringTag | kSeqStringTag: {
6787 CopyChars(sink,
6788 SeqAsciiString::cast(source)->GetChars() + from,
6789 to - from);
6790 return;
6791 }
6792 case kTwoByteStringTag | kSeqStringTag: {
6793 CopyChars(sink,
6794 SeqTwoByteString::cast(source)->GetChars() + from,
6795 to - from);
6796 return;
6797 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006798 case kAsciiStringTag | kConsStringTag:
6799 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00006801 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006802 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006803 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804 // Right hand side is longer. Recurse over left.
6805 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006806 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006807 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006808 from = 0;
6809 } else {
6810 from -= boundary;
6811 }
6812 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00006813 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006815 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006816 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006817 String* second = cons_string->second();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006818 WriteToFlat(second,
6819 sink + boundary - from,
6820 0,
6821 to - boundary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 to = boundary;
6823 }
6824 source = first;
6825 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006826 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006827 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00006828 case kAsciiStringTag | kSlicedStringTag:
6829 case kTwoByteStringTag | kSlicedStringTag: {
6830 SlicedString* slice = SlicedString::cast(source);
6831 unsigned offset = slice->offset();
6832 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
6833 return;
6834 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006835 }
6836 }
6837}
6838
6839
ager@chromium.org7c537e22008-10-16 08:43:32 +00006840template <typename IteratorA, typename IteratorB>
6841static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
6842 // General slow case check. We know that the ia and ib iterators
6843 // have the same length.
6844 while (ia->has_more()) {
6845 uc32 ca = ia->GetNext();
6846 uc32 cb = ib->GetNext();
6847 if (ca != cb)
6848 return false;
6849 }
6850 return true;
6851}
6852
6853
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006854// Compares the contents of two strings by reading and comparing
6855// int-sized blocks of characters.
6856template <typename Char>
6857static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
6858 int length = a.length();
6859 ASSERT_EQ(length, b.length());
6860 const Char* pa = a.start();
6861 const Char* pb = b.start();
6862 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00006863#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006864 // If this architecture isn't comfortable reading unaligned ints
6865 // then we have to check that the strings are aligned before
6866 // comparing them blockwise.
6867 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
6868 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
6869 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00006870 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006871#endif
6872 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
6873 int endpoint = length - kStepSize;
6874 // Compare blocks until we reach near the end of the string.
6875 for (; i <= endpoint; i += kStepSize) {
6876 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
6877 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
6878 if (wa != wb) {
6879 return false;
6880 }
6881 }
ager@chromium.org9085a012009-05-11 19:22:57 +00006882#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006883 }
6884#endif
6885 // Compare the remaining characters that didn't fit into a block.
6886 for (; i < length; i++) {
6887 if (a[i] != b[i]) {
6888 return false;
6889 }
6890 }
6891 return true;
6892}
6893
6894
ager@chromium.org7c537e22008-10-16 08:43:32 +00006895template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006896static inline bool CompareStringContentsPartial(Isolate* isolate,
6897 IteratorA* ia,
6898 String* b) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006899 String::FlatContent content = b->GetFlatContent();
6900 if (content.IsFlat()) {
6901 if (content.IsAscii()) {
6902 VectorIterator<char> ib(content.ToAsciiVector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006903 return CompareStringContents(ia, &ib);
6904 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006905 VectorIterator<uc16> ib(content.ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006906 return CompareStringContents(ia, &ib);
6907 }
6908 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006909 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6910 return CompareStringContents(ia,
6911 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00006912 }
6913}
6914
6915
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006916bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006918 int len = length();
6919 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920 if (len == 0) return true;
6921
6922 // Fast check: if hash code is computed for both strings
6923 // a fast negative check can be performed.
6924 if (HasHashCode() && other->HasHashCode()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00006925#ifdef DEBUG
6926 if (FLAG_enable_slow_asserts) {
6927 if (Hash() != other->Hash()) {
6928 bool found_difference = false;
6929 for (int i = 0; i < len; i++) {
6930 if (Get(i) != other->Get(i)) {
6931 found_difference = true;
6932 break;
6933 }
6934 }
6935 ASSERT(found_difference);
6936 }
6937 }
6938#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006939 if (Hash() != other->Hash()) return false;
6940 }
6941
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006942 // We know the strings are both non-empty. Compare the first chars
6943 // before we try to flatten the strings.
6944 if (this->Get(0) != other->Get(0)) return false;
6945
6946 String* lhs = this->TryFlattenGetString();
6947 String* rhs = other->TryFlattenGetString();
6948
6949 if (StringShape(lhs).IsSequentialAscii() &&
6950 StringShape(rhs).IsSequentialAscii()) {
6951 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6952 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006953 return CompareRawStringContents(Vector<const char>(str1, len),
6954 Vector<const char>(str2, len));
6955 }
6956
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006957 Isolate* isolate = GetIsolate();
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006958 String::FlatContent lhs_content = lhs->GetFlatContent();
6959 String::FlatContent rhs_content = rhs->GetFlatContent();
6960 if (lhs_content.IsFlat()) {
6961 if (lhs_content.IsAscii()) {
6962 Vector<const char> vec1 = lhs_content.ToAsciiVector();
6963 if (rhs_content.IsFlat()) {
6964 if (rhs_content.IsAscii()) {
6965 Vector<const char> vec2 = rhs_content.ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006966 return CompareRawStringContents(vec1, vec2);
6967 } else {
6968 VectorIterator<char> buf1(vec1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006969 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006970 return CompareStringContents(&buf1, &ib);
6971 }
6972 } else {
6973 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006974 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6975 return CompareStringContents(&buf1,
6976 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006977 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006978 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006979 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
6980 if (rhs_content.IsFlat()) {
6981 if (rhs_content.IsAscii()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006982 VectorIterator<uc16> buf1(vec1);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006983 VectorIterator<char> ib(rhs_content.ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006984 return CompareStringContents(&buf1, &ib);
6985 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006986 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006987 return CompareRawStringContents(vec1, vec2);
6988 }
6989 } else {
6990 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006991 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6992 return CompareStringContents(&buf1,
6993 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006996 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006997 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6998 return CompareStringContentsPartial(isolate,
6999 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001}
7002
7003
7004bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00007005 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006
7007 Map* map = this->map();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007008 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007009 if (map == heap->string_map()) {
7010 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007012 } else if (map == heap->ascii_string_map()) {
7013 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014 return true;
7015 }
7016 // Rest cannot be marked as undetectable
7017 return false;
7018}
7019
7020
7021bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007022 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007023 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007024 Access<UnicodeCache::Utf8Decoder>
7025 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007026 decoder->Reset(str.start(), str.length());
7027 int i;
7028 for (i = 0; i < slen && decoder->has_more(); i++) {
7029 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007030 if (Get(i) != r) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007031 }
7032 return i == slen && !decoder->has_more();
7033}
7034
7035
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00007036bool String::IsAsciiEqualTo(Vector<const char> str) {
7037 int slen = length();
7038 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007039 FlatContent content = GetFlatContent();
7040 if (content.IsAscii()) {
7041 return CompareChars(content.ToAsciiVector().start(),
7042 str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007043 }
7044 for (int i = 0; i < slen; i++) {
7045 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00007046 }
7047 return true;
7048}
7049
7050
7051bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
7052 int slen = length();
7053 if (str.length() != slen) return false;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007054 FlatContent content = GetFlatContent();
7055 if (content.IsTwoByte()) {
7056 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007057 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00007058 for (int i = 0; i < slen; i++) {
7059 if (Get(i) != str[i]) return false;
7060 }
7061 return true;
7062}
7063
7064
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00007066 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007067 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007069 const int len = length();
7070
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007071 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007072 uint32_t field = 0;
7073 if (StringShape(this).IsSequentialAscii()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007074 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(),
7075 len,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00007076 GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007077 } else if (StringShape(this).IsSequentialTwoByte()) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007078 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(),
7079 len,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00007080 GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007081 } else {
7082 StringInputBuffer buffer(this);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00007083 field = ComputeHashField(&buffer, len, GetHeap()->HashSeed());
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00007084 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007085
7086 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007087 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088
7089 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007090 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00007091 uint32_t result = field >> kHashShift;
7092 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
7093 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094}
7095
7096
7097bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
7098 uint32_t* index,
7099 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007100 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101 uc32 ch = buffer->GetNext();
7102
7103 // If the string begins with a '0' character, it must only consist
7104 // of it to be a legal array index.
7105 if (ch == '0') {
7106 *index = 0;
7107 return length == 1;
7108 }
7109
7110 // Convert string to uint32 array index; character by character.
7111 int d = ch - '0';
7112 if (d < 0 || d > 9) return false;
7113 uint32_t result = d;
7114 while (buffer->has_more()) {
7115 d = buffer->GetNext() - '0';
7116 if (d < 0 || d > 9) return false;
7117 // Check that the new result is below the 32 bit limit.
7118 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
7119 result = (result * 10) + d;
7120 }
7121
7122 *index = result;
7123 return true;
7124}
7125
7126
7127bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007128 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007129 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007130 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007131 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007132 // Isolate the array index form the full hash field.
7133 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007134 return true;
7135 } else {
7136 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007137 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007138 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007139}
7140
7141
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007142uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007143 // For array indexes mix the length into the hash as an array index could
7144 // be zero.
7145 ASSERT(length > 0);
7146 ASSERT(length <= String::kMaxArrayIndexSize);
7147 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
7148 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007149
7150 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007151 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007152
7153 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
7154 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
7155 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007156 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007157}
7158
7159
ager@chromium.org7c537e22008-10-16 08:43:32 +00007160uint32_t StringHasher::GetHashField() {
7161 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007162 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007163 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00007164 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007165 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007166 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00007167 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00007168 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007169 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007170}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007172
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00007173uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00007174 int length,
7175 uint32_t seed) {
7176 StringHasher hasher(length, seed);
ager@chromium.org7c537e22008-10-16 08:43:32 +00007177
7178 // Very long strings have a trivial hash that doesn't inspect the
7179 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007180 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007181 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007182 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007183
7184 // Do the iterative array index computation as long as there is a
7185 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007186 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007187 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007188 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007189
7190 // Process the remaining characters without updating the array
7191 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007192 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00007193 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007194 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00007195
7196 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007197}
7198
7199
lrn@chromium.org303ada72010-10-27 09:33:13 +00007200MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007201 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007202 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007203 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007204 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007205}
7206
7207
7208void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007209 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007210 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007211 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007212 }
7213}
7214
7215
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007216void Map::CreateOneBackPointer(Object* transition_target) {
7217 if (!transition_target->IsMap()) return;
7218 Map* target = Map::cast(transition_target);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007219#ifdef DEBUG
7220 // Verify target.
7221 Object* source_prototype = prototype();
7222 Object* target_prototype = target->prototype();
7223 ASSERT(source_prototype->IsJSReceiver() ||
7224 source_prototype->IsMap() ||
7225 source_prototype->IsNull());
7226 ASSERT(target_prototype->IsJSReceiver() ||
7227 target_prototype->IsNull());
7228 ASSERT(source_prototype->IsMap() ||
7229 source_prototype == target_prototype);
7230#endif
7231 // Point target back to source. set_prototype() will not let us set
7232 // the prototype to a map, as we do here.
7233 *RawField(target, kPrototypeOffset) = this;
7234}
7235
7236
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007237void Map::CreateBackPointers() {
7238 DescriptorArray* descriptors = instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00007239 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007240 switch (descriptors->GetType(i)) {
7241 case MAP_TRANSITION:
7242 case CONSTANT_TRANSITION:
7243 CreateOneBackPointer(descriptors->GetValue(i));
7244 break;
7245 case ELEMENTS_TRANSITION: {
7246 Object* object = descriptors->GetValue(i);
7247 if (object->IsMap()) {
7248 CreateOneBackPointer(object);
7249 } else {
7250 FixedArray* array = FixedArray::cast(object);
7251 for (int i = 0; i < array->length(); ++i) {
7252 CreateOneBackPointer(array->get(i));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007253 }
7254 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007255 break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007256 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007257 case CALLBACKS: {
7258 Object* object = descriptors->GetValue(i);
7259 if (object->IsAccessorPair()) {
7260 AccessorPair* accessors = AccessorPair::cast(object);
7261 CreateOneBackPointer(accessors->getter());
7262 CreateOneBackPointer(accessors->setter());
7263 }
7264 break;
7265 }
7266 case NORMAL:
7267 case FIELD:
7268 case CONSTANT_FUNCTION:
7269 case HANDLER:
7270 case INTERCEPTOR:
7271 case NULL_DESCRIPTOR:
7272 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007273 }
7274 }
7275}
7276
7277
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007278bool Map::RestoreOneBackPointer(Object* object,
7279 Object* real_prototype,
7280 bool* keep_entry) {
7281 if (!object->IsMap()) return false;
7282 Map* map = Map::cast(object);
7283 if (Marking::MarkBitFrom(map).Get()) {
7284 *keep_entry = true;
7285 return false;
7286 }
7287 ASSERT(map->prototype() == this || map->prototype() == real_prototype);
7288 // Getter prototype() is read-only, set_prototype() has side effects.
7289 *RawField(map, Map::kPrototypeOffset) = real_prototype;
7290 return true;
7291}
7292
7293
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007294void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007295 DescriptorArray* d = DescriptorArray::cast(
danno@chromium.org40cb8782011-05-25 07:58:50 +00007296 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
7297 if (d->IsEmpty()) return;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007298 Smi* NullDescriptorDetails =
7299 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007300 FixedArray* contents = FixedArray::cast(
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007301 d->get(DescriptorArray::kContentArrayIndex));
7302 ASSERT(contents->length() >= 2);
7303 for (int i = 0; i < contents->length(); i += 2) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007304 // If the pair (value, details) is a map transition, check if the target is
7305 // live. If not, null the descriptor. Also drop the back pointer for that
7306 // map transition, so that this map is not reached again by following a back
7307 // pointer from a non-live object.
7308 bool keep_entry = false;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007309 PropertyDetails details(Smi::cast(contents->get(i + 1)));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007310 switch (details.type()) {
7311 case MAP_TRANSITION:
7312 case CONSTANT_TRANSITION:
7313 RestoreOneBackPointer(contents->get(i), real_prototype, &keep_entry);
7314 break;
7315 case ELEMENTS_TRANSITION: {
7316 Object* object = contents->get(i);
7317 if (object->IsMap()) {
7318 RestoreOneBackPointer(object, real_prototype, &keep_entry);
7319 } else {
7320 FixedArray* array = FixedArray::cast(object);
7321 for (int j = 0; j < array->length(); ++j) {
7322 if (RestoreOneBackPointer(array->get(j),
7323 real_prototype,
7324 &keep_entry)) {
7325 array->set_undefined(j);
7326 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007327 }
7328 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007329 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007330 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007331 case CALLBACKS: {
7332 Object* object = contents->get(i);
7333 if (object->IsAccessorPair()) {
7334 AccessorPair* accessors = AccessorPair::cast(object);
7335 if (RestoreOneBackPointer(accessors->getter(),
7336 real_prototype,
7337 &keep_entry)) {
7338 accessors->set_getter(heap->the_hole_value());
7339 }
7340 if (RestoreOneBackPointer(accessors->setter(),
7341 real_prototype,
7342 &keep_entry)) {
7343 accessors->set_setter(heap->the_hole_value());
7344 }
7345 } else {
7346 keep_entry = true;
7347 }
7348 break;
7349 }
7350 case NORMAL:
7351 case FIELD:
7352 case CONSTANT_FUNCTION:
7353 case HANDLER:
7354 case INTERCEPTOR:
7355 case NULL_DESCRIPTOR:
7356 keep_entry = true;
7357 break;
7358 }
7359 // Make sure that an entry containing only dead transitions gets collected.
7360 // What we *really* want to do here is removing this entry completely, but
7361 // for technical reasons we can't do this, so we zero it out instead.
7362 if (!keep_entry) {
7363 contents->set_unchecked(i + 1, NullDescriptorDetails);
7364 contents->set_null_unchecked(heap, i);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00007365 }
7366 }
7367}
7368
7369
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00007370int Map::Hash() {
7371 // For performance reasons we only hash the 3 most variable fields of a map:
7372 // constructor, prototype and bit_field2.
7373
7374 // Shift away the tag.
7375 int hash = (static_cast<uint32_t>(
7376 reinterpret_cast<uintptr_t>(constructor())) >> 2);
7377
7378 // XOR-ing the prototype and constructor directly yields too many zero bits
7379 // when the two pointers are close (which is fairly common).
7380 // To avoid this we shift the prototype 4 bits relatively to the constructor.
7381 hash ^= (static_cast<uint32_t>(
7382 reinterpret_cast<uintptr_t>(prototype())) << 2);
7383
7384 return hash ^ (hash >> 16) ^ bit_field2();
7385}
7386
7387
7388bool Map::EquivalentToForNormalization(Map* other,
7389 PropertyNormalizationMode mode) {
7390 return
7391 constructor() == other->constructor() &&
7392 prototype() == other->prototype() &&
7393 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
7394 0 :
7395 other->inobject_properties()) &&
7396 instance_type() == other->instance_type() &&
7397 bit_field() == other->bit_field() &&
7398 bit_field2() == other->bit_field2() &&
7399 (bit_field3() & ~(1<<Map::kIsShared)) ==
7400 (other->bit_field3() & ~(1<<Map::kIsShared));
7401}
7402
7403
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00007404void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
7405 // Iterate over all fields in the body but take care in dealing with
7406 // the code entry.
7407 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
7408 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
7409 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
7410}
7411
7412
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007413void JSFunction::MarkForLazyRecompilation() {
7414 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007415 ASSERT(shared()->allows_lazy_compilation() ||
7416 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007417 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007418 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007419}
7420
7421
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007422bool SharedFunctionInfo::EnsureCompiled(Handle<SharedFunctionInfo> shared,
7423 ClearExceptionFlag flag) {
7424 return shared->is_compiled() || CompileLazy(shared, flag);
7425}
7426
7427
7428static bool CompileLazyHelper(CompilationInfo* info,
7429 ClearExceptionFlag flag) {
7430 // Compile the source information to a code object.
7431 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled());
7432 ASSERT(!info->isolate()->has_pending_exception());
7433 bool result = Compiler::CompileLazy(info);
7434 ASSERT(result != Isolate::Current()->has_pending_exception());
7435 if (!result && flag == CLEAR_EXCEPTION) {
7436 info->isolate()->clear_pending_exception();
7437 }
7438 return result;
7439}
7440
7441
7442bool SharedFunctionInfo::CompileLazy(Handle<SharedFunctionInfo> shared,
7443 ClearExceptionFlag flag) {
7444 CompilationInfo info(shared);
7445 return CompileLazyHelper(&info, flag);
7446}
7447
7448
7449bool JSFunction::CompileLazy(Handle<JSFunction> function,
7450 ClearExceptionFlag flag) {
7451 bool result = true;
7452 if (function->shared()->is_compiled()) {
7453 function->ReplaceCode(function->shared()->code());
7454 function->shared()->set_code_age(0);
7455 } else {
7456 CompilationInfo info(function);
7457 result = CompileLazyHelper(&info, flag);
7458 ASSERT(!result || function->is_compiled());
7459 }
7460 return result;
7461}
7462
7463
7464bool JSFunction::CompileOptimized(Handle<JSFunction> function,
7465 int osr_ast_id,
7466 ClearExceptionFlag flag) {
7467 CompilationInfo info(function);
7468 info.SetOptimizing(osr_ast_id);
7469 return CompileLazyHelper(&info, flag);
7470}
7471
7472
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007473bool JSFunction::IsInlineable() {
7474 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007475 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007476 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007477 if (!shared_info->script()->IsScript()) return false;
7478 if (shared_info->optimization_disabled()) return false;
7479 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007480 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
7481 // If we never ran this (unlikely) then lets try to optimize it.
7482 if (code->kind() != Code::FUNCTION) return true;
7483 return code->optimizable();
7484}
7485
7486
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007487MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007488 ASSERT(value->IsJSObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490 if (has_initial_map()) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00007491 // If the function has allocated the initial map
7492 // replace it with a copy containing the new prototype.
7493 Map* new_map;
7494 MaybeObject* maybe_new_map = initial_map()->CopyDropTransitions();
7495 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
7496 new_map->set_prototype(value);
7497 MaybeObject* maybe_object =
7498 set_initial_map_and_cache_transitions(new_map);
7499 if (maybe_object->IsFailure()) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500 } else {
7501 // Put the value in the initial map field until an initial map is
7502 // needed. At that point, a new initial map is created and the
7503 // prototype is put into the initial map where it belongs.
7504 set_prototype_or_initial_map(value);
7505 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007506 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507 return value;
7508}
7509
7510
lrn@chromium.org303ada72010-10-27 09:33:13 +00007511MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007512 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513 Object* construct_prototype = value;
7514
7515 // If the value is not a JSObject, store the value in the map's
7516 // constructor field so it can be accessed. Also, set the prototype
7517 // used for constructing objects to the original object prototype.
7518 // See ECMA-262 13.2.2.
7519 if (!value->IsJSObject()) {
7520 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007521 // Remove map transitions because they point to maps with a
7522 // different prototype.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007523 Object* new_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007524 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007525 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00007526 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007527 Map* new_map = Map::cast(new_object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007528 Heap* heap = new_map->GetHeap();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007529 set_map(new_map);
7530 new_map->set_constructor(value);
7531 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007532 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007533 heap->isolate()->context()->global_context()->
7534 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007535 } else {
7536 map()->set_non_instance_prototype(false);
7537 }
7538
7539 return SetInstancePrototype(construct_prototype);
7540}
7541
7542
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007543Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007544 Context* global_context = context()->global_context();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007545 Map* no_prototype_map = shared()->is_classic_mode()
7546 ? global_context->function_without_prototype_map()
7547 : global_context->strict_mode_function_without_prototype_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007548
7549 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007550 // Be idempotent.
7551 return this;
7552 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007553
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00007554 ASSERT(map() == (shared()->is_classic_mode()
7555 ? global_context->function_map()
7556 : global_context->strict_mode_function_map()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007557
7558 set_map(no_prototype_map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007559 set_prototype_or_initial_map(no_prototype_map->GetHeap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007560 return this;
7561}
7562
7563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007564Object* JSFunction::SetInstanceClassName(String* name) {
7565 shared()->set_instance_class_name(name);
7566 return this;
7567}
7568
7569
whesse@chromium.org023421e2010-12-21 12:19:12 +00007570void JSFunction::PrintName(FILE* out) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007571 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00007572 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007573}
7574
7575
ager@chromium.org236ad962008-09-25 09:45:57 +00007576Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
7577 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
7578}
7579
7580
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007581MaybeObject* Oddball::Initialize(const char* to_string,
7582 Object* to_number,
7583 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007584 Object* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007585 { MaybeObject* maybe_symbol =
7586 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007587 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
7588 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007589 set_to_string(String::cast(symbol));
7590 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007591 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007592 return this;
7593}
7594
7595
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00007596String* SharedFunctionInfo::DebugName() {
7597 Object* n = name();
7598 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
7599 return String::cast(n);
7600}
7601
7602
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007603bool SharedFunctionInfo::HasSourceCode() {
7604 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007605 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007606}
7607
7608
7609Object* SharedFunctionInfo::GetSourceCode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007610 Isolate* isolate = GetIsolate();
7611 if (!HasSourceCode()) return isolate->heap()->undefined_value();
7612 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007613 Object* source = Script::cast(script())->source();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007614 return *SubString(Handle<String>(String::cast(source), isolate),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007615 start_position(), end_position());
7616}
7617
7618
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007619int SharedFunctionInfo::SourceSize() {
7620 return end_position() - start_position();
7621}
7622
7623
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007624int SharedFunctionInfo::CalculateInstanceSize() {
7625 int instance_size =
7626 JSObject::kHeaderSize +
7627 expected_nof_properties() * kPointerSize;
7628 if (instance_size > JSObject::kMaxInstanceSize) {
7629 instance_size = JSObject::kMaxInstanceSize;
7630 }
7631 return instance_size;
7632}
7633
7634
7635int SharedFunctionInfo::CalculateInObjectProperties() {
7636 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
7637}
7638
7639
ager@chromium.org5c838252010-02-19 08:53:10 +00007640bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
7641 // Check the basic conditions for generating inline constructor code.
7642 if (!FLAG_inline_new
7643 || !has_only_simple_this_property_assignments()
7644 || this_property_assignments_count() == 0) {
7645 return false;
7646 }
7647
7648 // If the prototype is null inline constructors cause no problems.
7649 if (!prototype->IsJSObject()) {
7650 ASSERT(prototype->IsNull());
7651 return true;
7652 }
7653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007654 Heap* heap = GetHeap();
7655
ager@chromium.org5c838252010-02-19 08:53:10 +00007656 // Traverse the proposed prototype chain looking for setters for properties of
7657 // the same names as are set by the inline constructor.
7658 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007659 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007660 obj = obj->GetPrototype()) {
7661 JSObject* js_object = JSObject::cast(obj);
7662 for (int i = 0; i < this_property_assignments_count(); i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007663 LookupResult result(heap->isolate());
ager@chromium.org5c838252010-02-19 08:53:10 +00007664 String* name = GetThisPropertyAssignmentName(i);
7665 js_object->LocalLookupRealNamedProperty(name, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00007666 if (result.IsFound() && result.type() == CALLBACKS) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007667 return false;
7668 }
7669 }
7670 }
7671
7672 return true;
7673}
7674
7675
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00007676void SharedFunctionInfo::ForbidInlineConstructor() {
7677 set_compiler_hints(BooleanBit::set(compiler_hints(),
7678 kHasOnlySimpleThisPropertyAssignments,
7679 false));
7680}
7681
7682
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007683void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007684 bool only_simple_this_property_assignments,
7685 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007686 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007687 kHasOnlySimpleThisPropertyAssignments,
7688 only_simple_this_property_assignments));
7689 set_this_property_assignments(assignments);
7690 set_this_property_assignments_count(assignments->length() / 3);
7691}
7692
7693
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007694void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007695 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007696 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007697 kHasOnlySimpleThisPropertyAssignments,
7698 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007699 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007700 set_this_property_assignments_count(0);
7701}
7702
7703
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00007704String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
7705 Object* obj = this_property_assignments();
7706 ASSERT(obj->IsFixedArray());
7707 ASSERT(index < this_property_assignments_count());
7708 obj = FixedArray::cast(obj)->get(index * 3);
7709 ASSERT(obj->IsString());
7710 return String::cast(obj);
7711}
7712
7713
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007714bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
7715 Object* obj = this_property_assignments();
7716 ASSERT(obj->IsFixedArray());
7717 ASSERT(index < this_property_assignments_count());
7718 obj = FixedArray::cast(obj)->get(index * 3 + 1);
7719 return Smi::cast(obj)->value() != -1;
7720}
7721
7722
7723int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
7724 ASSERT(IsThisPropertyAssignmentArgument(index));
7725 Object* obj =
7726 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
7727 return Smi::cast(obj)->value();
7728}
7729
7730
7731Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
7732 ASSERT(!IsThisPropertyAssignmentArgument(index));
7733 Object* obj =
7734 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
7735 return obj;
7736}
7737
7738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007739// Support function for printing the source code to a StringStream
7740// without any allocation in the heap.
7741void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
7742 int max_length) {
7743 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007744 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007745 accumulator->Add("<No Source>");
7746 return;
7747 }
7748
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007749 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007750 // Don't use String::cast because we don't want more assertion errors while
7751 // we are already creating a stack dump.
7752 String* script_source =
7753 reinterpret_cast<String*>(Script::cast(script())->source());
7754
7755 if (!script_source->LooksValid()) {
7756 accumulator->Add("<Invalid Source>");
7757 return;
7758 }
7759
7760 if (!is_toplevel()) {
7761 accumulator->Add("function ");
7762 Object* name = this->name();
7763 if (name->IsString() && String::cast(name)->length() > 0) {
7764 accumulator->PrintName(name);
7765 }
7766 }
7767
7768 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007769 if (len <= max_length || max_length < 0) {
7770 accumulator->Put(script_source, start_position(), end_position());
7771 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007772 accumulator->Put(script_source,
7773 start_position(),
7774 start_position() + max_length);
7775 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007776 }
7777}
7778
7779
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007780static bool IsCodeEquivalent(Code* code, Code* recompiled) {
7781 if (code->instruction_size() != recompiled->instruction_size()) return false;
7782 ByteArray* code_relocation = code->relocation_info();
7783 ByteArray* recompiled_relocation = recompiled->relocation_info();
7784 int length = code_relocation->length();
7785 if (length != recompiled_relocation->length()) return false;
7786 int compare = memcmp(code_relocation->GetDataStartAddress(),
7787 recompiled_relocation->GetDataStartAddress(),
7788 length);
7789 return compare == 0;
7790}
7791
7792
7793void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
7794 ASSERT(!has_deoptimization_support());
7795 AssertNoAllocation no_allocation;
7796 Code* code = this->code();
7797 if (IsCodeEquivalent(code, recompiled)) {
7798 // Copy the deoptimization data from the recompiled code.
7799 code->set_deoptimization_data(recompiled->deoptimization_data());
7800 code->set_has_deoptimization_support(true);
7801 } else {
7802 // TODO(3025757): In case the recompiled isn't equivalent to the
7803 // old code, we have to replace it. We should try to avoid this
7804 // altogether because it flushes valuable type feedback by
7805 // effectively resetting all IC state.
7806 set_code(recompiled);
7807 }
7808 ASSERT(has_deoptimization_support());
7809}
7810
7811
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007812void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
7813 // Disable optimization for the shared function info and mark the
7814 // code as non-optimizable. The marker on the shared function info
7815 // is there because we flush non-optimized code thereby loosing the
7816 // non-optimizable information for the code. When the code is
7817 // regenerated and set on the shared function info it is marked as
7818 // non-optimizable if optimization is disabled for the shared
7819 // function info.
7820 set_optimization_disabled(true);
7821 // Code should be the lazy compilation stub or else unoptimized. If the
7822 // latter, disable optimization for the code too.
7823 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
7824 if (code()->kind() == Code::FUNCTION) {
7825 code()->set_optimizable(false);
7826 }
7827 if (FLAG_trace_opt) {
7828 PrintF("[disabled optimization for: ");
7829 function->PrintName();
7830 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
7831 }
7832}
7833
7834
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007835bool SharedFunctionInfo::VerifyBailoutId(int id) {
7836 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
7837 // we are always bailing out on ARM.
7838
7839 ASSERT(id != AstNode::kNoNumber);
7840 Code* unoptimized = code();
7841 DeoptimizationOutputData* data =
7842 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
7843 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
7844 USE(ignore);
7845 return true; // Return true if there was no ASSERT.
7846}
7847
7848
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007849void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
7850 ASSERT(!IsInobjectSlackTrackingInProgress());
7851
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00007852 if (!FLAG_clever_optimizations) return;
7853
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007854 // Only initiate the tracking the first time.
7855 if (live_objects_may_exist()) return;
7856 set_live_objects_may_exist(true);
7857
7858 // No tracking during the snapshot construction phase.
7859 if (Serializer::enabled()) return;
7860
7861 if (map->unused_property_fields() == 0) return;
7862
7863 // Nonzero counter is a leftover from the previous attempt interrupted
7864 // by GC, keep it.
7865 if (construction_count() == 0) {
7866 set_construction_count(kGenerousAllocationCount);
7867 }
7868 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007869 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007870 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007871 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007872 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007873}
7874
7875
7876// Called from GC, hence reinterpret_cast and unchecked accessors.
7877void SharedFunctionInfo::DetachInitialMap() {
7878 Map* map = reinterpret_cast<Map*>(initial_map());
7879
7880 // Make the map remember to restore the link if it survives the GC.
7881 map->set_bit_field2(
7882 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
7883
7884 // Undo state changes made by StartInobjectTracking (except the
7885 // construction_count). This way if the initial map does not survive the GC
7886 // then StartInobjectTracking will be called again the next time the
7887 // constructor is called. The countdown will continue and (possibly after
7888 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007889 Heap* heap = map->GetHeap();
7890 set_initial_map(heap->raw_unchecked_undefined_value());
7891 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007892 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007893 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007894 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007895 // It is safe to clear the flag: it will be set again if the map is live.
7896 set_live_objects_may_exist(false);
7897}
7898
7899
7900// Called from GC, hence reinterpret_cast and unchecked accessors.
7901void SharedFunctionInfo::AttachInitialMap(Map* map) {
7902 map->set_bit_field2(
7903 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
7904
7905 // Resume inobject slack tracking.
7906 set_initial_map(map);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007907 Builtins* builtins = map->GetHeap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007908 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007909 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007910 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007911 // The map survived the gc, so there may be objects referencing it.
7912 set_live_objects_may_exist(true);
7913}
7914
7915
7916static void GetMinInobjectSlack(Map* map, void* data) {
7917 int slack = map->unused_property_fields();
7918 if (*reinterpret_cast<int*>(data) > slack) {
7919 *reinterpret_cast<int*>(data) = slack;
7920 }
7921}
7922
7923
7924static void ShrinkInstanceSize(Map* map, void* data) {
7925 int slack = *reinterpret_cast<int*>(data);
7926 map->set_inobject_properties(map->inobject_properties() - slack);
7927 map->set_unused_property_fields(map->unused_property_fields() - slack);
7928 map->set_instance_size(map->instance_size() - slack * kPointerSize);
7929
7930 // Visitor id might depend on the instance size, recalculate it.
7931 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
7932}
7933
7934
7935void SharedFunctionInfo::CompleteInobjectSlackTracking() {
7936 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
7937 Map* map = Map::cast(initial_map());
7938
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007939 Heap* heap = map->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007940 set_initial_map(heap->undefined_value());
7941 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007942 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007943 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007944 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007945
7946 int slack = map->unused_property_fields();
7947 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
7948 if (slack != 0) {
7949 // Resize the initial map and all maps in its transition tree.
7950 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007951
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007952 // Give the correct expected_nof_properties to initial maps created later.
7953 ASSERT(expected_nof_properties() >= slack);
7954 set_expected_nof_properties(expected_nof_properties() - slack);
7955 }
7956}
7957
7958
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007959#define DECLARE_TAG(ignore1, name, ignore2) name,
7960const char* const VisitorSynchronization::kTags[
7961 VisitorSynchronization::kNumberOfSyncTags] = {
7962 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7963};
7964#undef DECLARE_TAG
7965
7966
7967#define DECLARE_TAG(ignore1, ignore2, name) name,
7968const char* const VisitorSynchronization::kTagNames[
7969 VisitorSynchronization::kNumberOfSyncTags] = {
7970 VISITOR_SYNCHRONIZATION_TAGS_LIST(DECLARE_TAG)
7971};
7972#undef DECLARE_TAG
7973
7974
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007975void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00007976 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00007977 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
7978 Object* old_target = target;
7979 VisitPointer(&target);
7980 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007981}
7982
7983
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00007984void ObjectVisitor::VisitCodeEntry(Address entry_address) {
7985 Object* code = Code::GetObjectFromEntryAddress(entry_address);
7986 Object* old_code = code;
7987 VisitPointer(&code);
7988 if (code != old_code) {
7989 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
7990 }
7991}
7992
7993
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007994void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
7995 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
7996 Object* cell = rinfo->target_cell();
7997 Object* old_cell = cell;
7998 VisitPointer(&cell);
7999 if (cell != old_cell) {
8000 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
8001 }
8002}
8003
8004
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008005void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00008006 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
8007 rinfo->IsPatchedReturnSequence()) ||
8008 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
8009 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00008010 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
8011 Object* old_target = target;
8012 VisitPointer(&target);
8013 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008014}
8015
8016
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008017void ObjectVisitor::VisitEmbeddedPointer(RelocInfo* rinfo) {
8018 ASSERT(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
8019 VisitPointer(rinfo->target_object_address());
8020}
8021
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00008022void ObjectVisitor::VisitExternalReference(RelocInfo* rinfo) {
8023 Address* p = rinfo->target_reference_address();
8024 VisitExternalReferences(p, p + 1);
8025}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008026
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008027void Code::InvalidateRelocation() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008028 set_relocation_info(GetHeap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008029}
8030
8031
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008032void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008033 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
8034 it.rinfo()->apply(delta);
8035 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008036 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008037}
8038
8039
8040void Code::CopyFrom(const CodeDesc& desc) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008041 ASSERT(Marking::Color(this) == Marking::WHITE_OBJECT);
8042
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 // copy code
8044 memmove(instruction_start(), desc.buffer, desc.instr_size);
8045
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008046 // copy reloc info
8047 memmove(relocation_start(),
8048 desc.buffer + desc.buffer_size - desc.reloc_size,
8049 desc.reloc_size);
8050
8051 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00008052 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00008054 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008055 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008057 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008058 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008059 RelocInfo::Mode mode = it.rinfo()->rmode();
8060 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008061 Handle<Object> p = it.rinfo()->target_object_handle(origin);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008062 it.rinfo()->set_target_object(*p, SKIP_WRITE_BARRIER);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008063 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008064 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008065 it.rinfo()->set_target_cell(*cell, SKIP_WRITE_BARRIER);
ager@chromium.org236ad962008-09-25 09:45:57 +00008066 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067 // rewrite code handles in inline cache targets to direct
8068 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008069 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008070 Code* code = Code::cast(*p);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008071 it.rinfo()->set_target_address(code->instruction_start(),
8072 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008073 } else {
8074 it.rinfo()->apply(delta);
8075 }
8076 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008077 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008078}
8079
8080
8081// Locate the source position which is closest to the address in the code. This
8082// is using the source position information embedded in the relocation info.
8083// The position returned is relative to the beginning of the script where the
8084// source for this function is found.
8085int Code::SourcePosition(Address pc) {
8086 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00008087 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008088 // Run through all the relocation info to find the best matching source
8089 // position. All the code needs to be considered as the sequence of the
8090 // instructions in the code does not necessarily follow the same order as the
8091 // source.
8092 RelocIterator it(this, RelocInfo::kPositionMask);
8093 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008094 // Only look at positions after the current pc.
8095 if (it.rinfo()->pc() < pc) {
8096 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008097
8098 int dist = static_cast<int>(pc - it.rinfo()->pc());
8099 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00008100 // If this position is closer than the current candidate or if it has the
8101 // same distance as the current candidate and the position is higher then
8102 // this position is the new candidate.
8103 if ((dist < distance) ||
8104 (dist == distance && pos > position)) {
8105 position = pos;
8106 distance = dist;
8107 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008108 }
8109 it.next();
8110 }
8111 return position;
8112}
8113
8114
8115// Same as Code::SourcePosition above except it only looks for statement
8116// positions.
8117int Code::SourceStatementPosition(Address pc) {
8118 // First find the position as close as possible using all position
8119 // information.
8120 int position = SourcePosition(pc);
8121 // Now find the closest statement position before the position.
8122 int statement_position = 0;
8123 RelocIterator it(this, RelocInfo::kPositionMask);
8124 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00008125 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008126 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127 if (statement_position < p && p <= position) {
8128 statement_position = p;
8129 }
8130 }
8131 it.next();
8132 }
8133 return statement_position;
8134}
8135
8136
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008137SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008138 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008139 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008140}
8141
8142
8143void Code::SetNoStackCheckTable() {
8144 // Indicate the absence of a stack-check table by a table start after the
8145 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008146 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008147}
8148
8149
8150Map* Code::FindFirstMap() {
8151 ASSERT(is_inline_cache_stub());
8152 AssertNoAllocation no_allocation;
8153 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
8154 for (RelocIterator it(this, mask); !it.done(); it.next()) {
8155 RelocInfo* info = it.rinfo();
8156 Object* object = info->target_object();
8157 if (object->IsMap()) return Map::cast(object);
8158 }
8159 return NULL;
8160}
8161
8162
ricow@chromium.org4f693d62011-07-04 14:01:31 +00008163#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008164
whesse@chromium.org023421e2010-12-21 12:19:12 +00008165void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008166 disasm::NameConverter converter;
8167 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00008168 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008169 if (0 == deopt_count) return;
8170
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008171 PrintF(out, "%6s %6s %6s %6s %12s\n", "index", "ast id", "argc", "pc",
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008172 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008173 for (int i = 0; i < deopt_count; i++) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +00008174 PrintF(out, "%6d %6d %6d %6d",
8175 i,
8176 AstId(i)->value(),
8177 ArgumentsStackHeight(i)->value(),
8178 Pc(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008179
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008180 if (!FLAG_print_code_verbose) {
8181 PrintF(out, "\n");
8182 continue;
8183 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008184 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008185 int translation_index = TranslationIndex(i)->value();
8186 TranslationIterator iterator(TranslationByteArray(), translation_index);
8187 Translation::Opcode opcode =
8188 static_cast<Translation::Opcode>(iterator.Next());
8189 ASSERT(Translation::BEGIN == opcode);
8190 int frame_count = iterator.Next();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008191 int jsframe_count = iterator.Next();
8192 PrintF(out, " %s {frame count=%d, js frame count=%d}\n",
8193 Translation::StringFor(opcode),
8194 frame_count,
8195 jsframe_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008196
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008197 while (iterator.HasNext() &&
8198 Translation::BEGIN !=
8199 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
8200 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
8201
8202 switch (opcode) {
8203 case Translation::BEGIN:
8204 UNREACHABLE();
8205 break;
8206
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008207 case Translation::JS_FRAME: {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008208 int ast_id = iterator.Next();
8209 int function_id = iterator.Next();
8210 JSFunction* function =
8211 JSFunction::cast(LiteralArray()->get(function_id));
8212 unsigned height = iterator.Next();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008213 PrintF(out, "{ast_id=%d, function=", ast_id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008214 function->PrintName(out);
8215 PrintF(out, ", height=%u}", height);
8216 break;
8217 }
8218
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008219 case Translation::ARGUMENTS_ADAPTOR_FRAME: {
8220 unsigned height = iterator.Next();
8221 PrintF(out, "{arguments adaptor, height=%d}", height);
8222 break;
8223 }
8224
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008225 case Translation::DUPLICATE:
8226 break;
8227
8228 case Translation::REGISTER: {
8229 int reg_code = iterator.Next();
8230 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8231 break;
8232 }
8233
8234 case Translation::INT32_REGISTER: {
8235 int reg_code = iterator.Next();
8236 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
8237 break;
8238 }
8239
8240 case Translation::DOUBLE_REGISTER: {
8241 int reg_code = iterator.Next();
8242 PrintF(out, "{input=%s}",
8243 DoubleRegister::AllocationIndexToString(reg_code));
8244 break;
8245 }
8246
8247 case Translation::STACK_SLOT: {
8248 int input_slot_index = iterator.Next();
8249 PrintF(out, "{input=%d}", input_slot_index);
8250 break;
8251 }
8252
8253 case Translation::INT32_STACK_SLOT: {
8254 int input_slot_index = iterator.Next();
8255 PrintF(out, "{input=%d}", input_slot_index);
8256 break;
8257 }
8258
8259 case Translation::DOUBLE_STACK_SLOT: {
8260 int input_slot_index = iterator.Next();
8261 PrintF(out, "{input=%d}", input_slot_index);
8262 break;
8263 }
8264
8265 case Translation::LITERAL: {
8266 unsigned literal_index = iterator.Next();
8267 PrintF(out, "{literal_id=%u}", literal_index);
8268 break;
8269 }
8270
8271 case Translation::ARGUMENTS_OBJECT:
8272 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008273 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008274 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008275 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008276 }
8277}
8278
8279
whesse@chromium.org023421e2010-12-21 12:19:12 +00008280void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
8281 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008282 this->DeoptPoints());
8283 if (this->DeoptPoints() == 0) return;
8284
8285 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
8286 for (int i = 0; i < this->DeoptPoints(); i++) {
8287 int pc_and_state = this->PcAndState(i)->value();
8288 PrintF("%6d %8d %s\n",
8289 this->AstId(i)->value(),
8290 FullCodeGenerator::PcField::decode(pc_and_state),
8291 FullCodeGenerator::State2String(
8292 FullCodeGenerator::StateField::decode(pc_and_state)));
8293 }
8294}
8295
whesse@chromium.org7b260152011-06-20 15:33:18 +00008296
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008297// Identify kind of code.
8298const char* Code::Kind2String(Kind kind) {
8299 switch (kind) {
8300 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008301 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008302 case STUB: return "STUB";
8303 case BUILTIN: return "BUILTIN";
8304 case LOAD_IC: return "LOAD_IC";
8305 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
8306 case STORE_IC: return "STORE_IC";
8307 case KEYED_STORE_IC: return "KEYED_STORE_IC";
8308 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008309 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00008310 case UNARY_OP_IC: return "UNARY_OP_IC";
8311 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008312 case COMPARE_IC: return "COMPARE_IC";
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008313 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008314 }
8315 UNREACHABLE();
8316 return NULL;
8317}
mads.s.ager31e71382008-08-13 09:32:07 +00008318
8319
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008320const char* Code::ICState2String(InlineCacheState state) {
8321 switch (state) {
8322 case UNINITIALIZED: return "UNINITIALIZED";
8323 case PREMONOMORPHIC: return "PREMONOMORPHIC";
8324 case MONOMORPHIC: return "MONOMORPHIC";
8325 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
8326 case MEGAMORPHIC: return "MEGAMORPHIC";
8327 case DEBUG_BREAK: return "DEBUG_BREAK";
8328 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
8329 }
8330 UNREACHABLE();
8331 return NULL;
8332}
8333
8334
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008335const char* Code::PropertyType2String(PropertyType type) {
8336 switch (type) {
8337 case NORMAL: return "NORMAL";
8338 case FIELD: return "FIELD";
8339 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
8340 case CALLBACKS: return "CALLBACKS";
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00008341 case HANDLER: return "HANDLER";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008342 case INTERCEPTOR: return "INTERCEPTOR";
8343 case MAP_TRANSITION: return "MAP_TRANSITION";
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008344 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008345 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
8346 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
8347 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00008348 UNREACHABLE(); // keep the compiler happy
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008349 return NULL;
8350}
8351
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008352
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008353void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
8354 const char* name = NULL;
8355 switch (kind) {
8356 case CALL_IC:
8357 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
8358 name = "STRING_INDEX_OUT_OF_BOUNDS";
8359 }
8360 break;
8361 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008362 case KEYED_STORE_IC:
8363 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008364 name = "STRICT";
8365 }
8366 break;
8367 default:
8368 break;
8369 }
8370 if (name != NULL) {
8371 PrintF(out, "extra_ic_state = %s\n", name);
8372 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008373 PrintF(out, "extra_ic_state = %d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008374 }
8375}
8376
8377
whesse@chromium.org023421e2010-12-21 12:19:12 +00008378void Code::Disassemble(const char* name, FILE* out) {
8379 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008380 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008381 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00008382 PrintExtraICState(out, kind(), extra_ic_state());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008383 if (ic_state() == MONOMORPHIC) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008384 PrintF(out, "type = %s\n", PropertyType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008385 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00008386 if (is_call_stub() || is_keyed_call_stub()) {
8387 PrintF(out, "argc = %d\n", arguments_count());
8388 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008389 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008390 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008391 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008392 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008393 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008394 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008395 }
mads.s.ager31e71382008-08-13 09:32:07 +00008396
whesse@chromium.org023421e2010-12-21 12:19:12 +00008397 PrintF(out, "Instructions (size = %d)\n", instruction_size());
8398 Disassembler::Decode(out, this);
8399 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00008400
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008401 if (kind() == FUNCTION) {
8402 DeoptimizationOutputData* data =
8403 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008404 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008405 } else if (kind() == OPTIMIZED_FUNCTION) {
8406 DeoptimizationInputData* data =
8407 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008408 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008409 }
8410 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411
8412 if (kind() == OPTIMIZED_FUNCTION) {
8413 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008414 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008415 for (unsigned i = 0; i < table.length(); i++) {
8416 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008417 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008418 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00008419 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008420 SafepointEntry entry = table.GetEntry(i);
8421 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
8422 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008423 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008424 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008425 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008426 if (entry.argument_count() > 0) {
8427 PrintF(out, " argc: %d", entry.argument_count());
8428 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008429 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008430 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008431 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008432 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008433 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 // If there is no stack check table, the "table start" will at or after
8435 // (due to alignment) the end of the instruction stream.
8436 if (static_cast<int>(offset) < instruction_size()) {
8437 unsigned* address =
8438 reinterpret_cast<unsigned*>(instruction_start() + offset);
8439 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00008440 PrintF(out, "Stack checks (size = %u)\n", length);
8441 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 for (unsigned i = 0; i < length; ++i) {
8443 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00008444 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008445 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008446 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008447 }
8448 }
8449
mads.s.ager31e71382008-08-13 09:32:07 +00008450 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00008451 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
8452 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00008453}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00008454#endif // ENABLE_DISASSEMBLER
8455
8456
whesse@chromium.org7b260152011-06-20 15:33:18 +00008457static void CopyFastElementsToFast(FixedArray* source,
8458 FixedArray* destination,
8459 WriteBarrierMode mode) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008460 int count = source->length();
8461 int copy_size = Min(count, destination->length());
8462 if (mode == SKIP_WRITE_BARRIER ||
8463 !Page::FromAddress(destination->address())->IsFlagSet(
8464 MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING)) {
8465 Address to = destination->address() + FixedArray::kHeaderSize;
8466 Address from = source->address() + FixedArray::kHeaderSize;
8467 memcpy(reinterpret_cast<void*>(to),
8468 reinterpret_cast<void*>(from),
8469 kPointerSize * copy_size);
8470 } else {
8471 for (int i = 0; i < copy_size; ++i) {
8472 destination->set(i, source->get(i), mode);
8473 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008474 }
8475}
8476
8477
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008478static void CopySlowElementsToFast(SeededNumberDictionary* source,
whesse@chromium.org7b260152011-06-20 15:33:18 +00008479 FixedArray* destination,
8480 WriteBarrierMode mode) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008481 int destination_length = destination->length();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008482 for (int i = 0; i < source->Capacity(); ++i) {
8483 Object* key = source->KeyAt(i);
8484 if (key->IsNumber()) {
8485 uint32_t entry = static_cast<uint32_t>(key->Number());
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008486 if (entry < static_cast<uint32_t>(destination_length)) {
8487 destination->set(entry, source->ValueAt(i), mode);
8488 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008489 }
8490 }
8491}
8492
8493
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008494MaybeObject* JSObject::SetFastElementsCapacityAndLength(
8495 int capacity,
8496 int length,
8497 SetFastElementsCapacityMode set_capacity_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008498 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00008499 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008500 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008501
whesse@chromium.org7b260152011-06-20 15:33:18 +00008502 // Allocate a new fast elements backing store.
8503 FixedArray* new_elements = NULL;
8504 { Object* object;
8505 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
8506 if (!maybe->ToObject(&object)) return maybe;
8507 new_elements = FixedArray::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008508 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008509
whesse@chromium.org7b260152011-06-20 15:33:18 +00008510 // Find the new map to use for this object if there is a map change.
8511 Map* new_map = NULL;
8512 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
8513 Object* object;
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008514 // The resized array has FAST_SMI_ONLY_ELEMENTS if the capacity mode forces
8515 // it, or if it's allowed and the old elements array contained only SMIs.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008516 bool has_fast_smi_only_elements =
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008517 (set_capacity_mode == kForceSmiOnlyElements) ||
8518 ((set_capacity_mode == kAllowSmiOnlyElements) &&
8519 (elements()->map()->has_fast_smi_only_elements() ||
8520 elements() == heap->empty_fixed_array()));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008521 ElementsKind elements_kind = has_fast_smi_only_elements
8522 ? FAST_SMI_ONLY_ELEMENTS
8523 : FAST_ELEMENTS;
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008524 MaybeObject* maybe = GetElementsTransitionMap(GetIsolate(), elements_kind);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008525 if (!maybe->ToObject(&object)) return maybe;
8526 new_map = Map::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008527 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008528
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008529 FixedArrayBase* old_elements_raw = elements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008530 ElementsKind elements_kind = GetElementsKind();
8531 switch (elements_kind) {
8532 case FAST_SMI_ONLY_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008533 case FAST_ELEMENTS: {
8534 AssertNoAllocation no_gc;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008535 WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008536 CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
8537 new_elements, mode);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008538 set_map_and_elements(new_map, new_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008539 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008540 }
8541 case DICTIONARY_ELEMENTS: {
8542 AssertNoAllocation no_gc;
8543 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008544 CopySlowElementsToFast(SeededNumberDictionary::cast(old_elements_raw),
whesse@chromium.org7b260152011-06-20 15:33:18 +00008545 new_elements,
8546 mode);
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00008547 set_map_and_elements(new_map, new_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008548 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008549 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008550 case NON_STRICT_ARGUMENTS_ELEMENTS: {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008551 AssertNoAllocation no_gc;
8552 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008553 // The object's map and the parameter map are unchanged, the unaliased
8554 // arguments are copied to the new backing store.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008555 FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008556 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8557 if (arguments->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008558 CopySlowElementsToFast(SeededNumberDictionary::cast(arguments),
whesse@chromium.org7b260152011-06-20 15:33:18 +00008559 new_elements,
8560 mode);
8561 } else {
8562 CopyFastElementsToFast(arguments, new_elements, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008563 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008564 parameter_map->set(1, new_elements);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008565 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008567 case FAST_DOUBLE_ELEMENTS: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008568 FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008569 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
8570 // Fill out the new array with this content and array holes.
8571 for (uint32_t i = 0; i < old_length; i++) {
8572 if (!old_elements->is_the_hole(i)) {
8573 Object* obj;
8574 // Objects must be allocated in the old object space, since the
8575 // overall number of HeapNumbers needed for the conversion might
8576 // exceed the capacity of new space, and we would fail repeatedly
8577 // trying to convert the FixedDoubleArray.
8578 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008579 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
8580 TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008581 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
8582 // Force write barrier. It's not worth trying to exploit
8583 // elems->GetWriteBarrierMode(), since it requires an
8584 // AssertNoAllocation stack object that would have to be positioned
8585 // after the HeapNumber allocation anyway.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008586 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008587 }
8588 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008589 set_map(new_map);
8590 set_elements(new_elements);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008591 break;
8592 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008593 case EXTERNAL_BYTE_ELEMENTS:
8594 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8595 case EXTERNAL_SHORT_ELEMENTS:
8596 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8597 case EXTERNAL_INT_ELEMENTS:
8598 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8599 case EXTERNAL_FLOAT_ELEMENTS:
8600 case EXTERNAL_DOUBLE_ELEMENTS:
8601 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008602 UNREACHABLE();
8603 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008604 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008605
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008606 if (FLAG_trace_elements_transitions) {
8607 PrintElementsTransition(stdout, elements_kind, old_elements_raw,
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008608 GetElementsKind(), new_elements);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008609 }
8610
whesse@chromium.org7b260152011-06-20 15:33:18 +00008611 // Update the length if necessary.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00008612 if (IsJSArray()) {
8613 JSArray::cast(this)->set_length(Smi::FromInt(length));
8614 }
8615
whesse@chromium.org7b260152011-06-20 15:33:18 +00008616 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008617}
8618
8619
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008620MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
8621 int capacity,
8622 int length) {
8623 Heap* heap = GetHeap();
8624 // We should never end in here with a pixel or external array.
8625 ASSERT(!HasExternalArrayElements());
8626
8627 Object* obj;
8628 { MaybeObject* maybe_obj =
8629 heap->AllocateUninitializedFixedDoubleArray(capacity);
8630 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8631 }
8632 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
8633
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008634 { MaybeObject* maybe_obj =
danno@chromium.orgfa458e42012-02-01 10:48:36 +00008635 GetElementsTransitionMap(heap->isolate(), FAST_DOUBLE_ELEMENTS);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008636 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8637 }
8638 Map* new_map = Map::cast(obj);
8639
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008640 FixedArrayBase* old_elements = elements();
8641 ElementsKind elements_kind(GetElementsKind());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008642 AssertNoAllocation no_gc;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008643 switch (elements_kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008644 case FAST_SMI_ONLY_ELEMENTS:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008645 case FAST_ELEMENTS: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008646 elems->Initialize(FixedArray::cast(old_elements));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008647 break;
8648 }
8649 case FAST_DOUBLE_ELEMENTS: {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008650 elems->Initialize(FixedDoubleArray::cast(old_elements));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008651 break;
8652 }
8653 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008654 elems->Initialize(SeededNumberDictionary::cast(old_elements));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008655 break;
8656 }
8657 default:
8658 UNREACHABLE();
8659 break;
8660 }
8661
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008662 if (FLAG_trace_elements_transitions) {
8663 PrintElementsTransition(stdout, elements_kind, old_elements,
8664 FAST_DOUBLE_ELEMENTS, elems);
8665 }
8666
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008667 ASSERT(new_map->has_fast_double_elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008668 set_map(new_map);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008669 ASSERT(elems->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008670 set_elements(elems);
8671
8672 if (IsJSArray()) {
8673 JSArray::cast(this)->set_length(Smi::FromInt(length));
8674 }
8675
8676 return this;
8677}
8678
8679
lrn@chromium.org303ada72010-10-27 09:33:13 +00008680MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008682 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008683 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 FixedArray* new_elements;
8685 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008686 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008688 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008690 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008692 new_elements = FixedArray::cast(obj);
8693 }
8694 set_elements(new_elements);
8695 return this;
8696}
8697
8698
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008699void JSArray::Expand(int required_size) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008700 GetIsolate()->factory()->SetElementsCapacityAndLength(
8701 Handle<JSArray>(this), required_size, required_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00008702}
8703
8704
ricow@chromium.org7ad65222011-12-19 12:13:11 +00008705MaybeObject* JSArray::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00008706 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00008707 ASSERT(AllowsSetElementsLength());
danno@chromium.orgc612e022011-11-10 11:38:15 +00008708 return GetElementsAccessor()->SetLength(this, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008709}
8710
8711
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008712Object* Map::GetPrototypeTransition(Object* prototype) {
8713 FixedArray* cache = prototype_transitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008714 int number_of_transitions = NumberOfProtoTransitions();
8715 const int proto_offset =
8716 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
8717 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
8718 const int step = kProtoTransitionElementsPerEntry;
8719 for (int i = 0; i < number_of_transitions; i++) {
8720 if (cache->get(proto_offset + i * step) == prototype) {
8721 Object* map = cache->get(map_offset + i * step);
8722 ASSERT(map->IsMap());
8723 return map;
8724 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008725 }
8726 return NULL;
8727}
8728
8729
8730MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008731 ASSERT(map->IsMap());
8732 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008733 // Don't cache prototype transition if this map is shared.
8734 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
8735
8736 FixedArray* cache = prototype_transitions();
8737
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008738 const int step = kProtoTransitionElementsPerEntry;
8739 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008740
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008741 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008742
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008743 int transitions = NumberOfProtoTransitions() + 1;
8744
8745 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008746 if (capacity > kMaxCachedPrototypeTransitions) return this;
8747
8748 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008749 // Grow array by factor 2 over and above what we need.
8750 { MaybeObject* maybe_cache =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008751 GetHeap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008752 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
8753 }
8754
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008755 for (int i = 0; i < capacity * step; i++) {
8756 new_cache->set(i + header, cache->get(i + header));
8757 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008758 cache = new_cache;
8759 set_prototype_transitions(cache);
8760 }
8761
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008762 int last = transitions - 1;
8763
8764 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
8765 cache->set(header + last * step + kProtoTransitionMapOffset, map);
8766 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008767
8768 return cache;
8769}
8770
8771
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008772MaybeObject* JSReceiver::SetPrototype(Object* value,
8773 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008774#ifdef DEBUG
8775 int size = Size();
8776#endif
8777
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008778 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00008779 // Silently ignore the change if value is not a JSObject or null.
8780 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008781 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00008782
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008783 // From 8.6.2 Object Internal Methods
8784 // ...
8785 // In addition, if [[Extensible]] is false the value of the [[Class]] and
8786 // [[Prototype]] internal properties of the object may not be modified.
8787 // ...
8788 // Implementation specific extensions that modify [[Class]], [[Prototype]]
8789 // or [[Extensible]] must not violate the invariants defined in the preceding
8790 // paragraph.
8791 if (!this->map()->is_extensible()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008792 HandleScope scope(heap->isolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008793 Handle<Object> handle(this, heap->isolate());
8794 return heap->isolate()->Throw(
8795 *FACTORY->NewTypeError("non_extensible_proto",
8796 HandleVector<Object>(&handle, 1)));
8797 }
8798
ager@chromium.org5c838252010-02-19 08:53:10 +00008799 // Before we can set the prototype we need to be sure
8800 // prototype cycles are prevented.
8801 // It is sufficient to validate that the receiver is not in the new prototype
8802 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008803 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008804 if (JSReceiver::cast(pt) == this) {
ager@chromium.org5c838252010-02-19 08:53:10 +00008805 // Cycle detected.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008806 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008807 return heap->isolate()->Throw(
8808 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00008809 }
8810 }
8811
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008812 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00008813
8814 if (skip_hidden_prototypes) {
8815 // Find the first object in the chain whose prototype object is not
8816 // hidden and set the new prototype on that object.
8817 Object* current_proto = real_receiver->GetPrototype();
8818 while (current_proto->IsJSObject() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008819 JSReceiver::cast(current_proto)->map()->is_hidden_prototype()) {
8820 real_receiver = JSReceiver::cast(current_proto);
ager@chromium.org5c838252010-02-19 08:53:10 +00008821 current_proto = current_proto->GetPrototype();
8822 }
8823 }
8824
8825 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008826 Map* map = real_receiver->map();
8827
8828 // Nothing to do if prototype is already set.
8829 if (map->prototype() == value) return value;
8830
8831 Object* new_map = map->GetPrototypeTransition(value);
8832 if (new_map == NULL) {
8833 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
8834 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
8835 }
8836
8837 { MaybeObject* maybe_new_cache =
8838 map->PutPrototypeTransition(value, Map::cast(new_map));
8839 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
8840 }
8841
8842 Map::cast(new_map)->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008843 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008844 ASSERT(Map::cast(new_map)->prototype() == value);
ager@chromium.org5c838252010-02-19 08:53:10 +00008845 real_receiver->set_map(Map::cast(new_map));
8846
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008847 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00008848 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +00008849 return value;
8850}
8851
8852
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008853MaybeObject* JSObject::EnsureCanContainElements(Arguments* args,
8854 uint32_t first_arg,
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008855 uint32_t arg_count,
8856 EnsureElementsMode mode) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008857 // Elements in |Arguments| are ordered backwards (because they're on the
8858 // stack), but the method that's called here iterates over them in forward
8859 // direction.
8860 return EnsureCanContainElements(
8861 args->arguments() - first_arg - (arg_count - 1),
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008862 arg_count, mode);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008863}
8864
8865
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008866bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008867 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008868 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008869 case FAST_ELEMENTS: {
8870 uint32_t length = IsJSArray() ?
8871 static_cast<uint32_t>
8872 (Smi::cast(JSArray::cast(this)->length())->value()) :
8873 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8874 if ((index < length) &&
8875 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8876 return true;
8877 }
8878 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008880 case FAST_DOUBLE_ELEMENTS: {
8881 uint32_t length = IsJSArray() ?
8882 static_cast<uint32_t>
8883 (Smi::cast(JSArray::cast(this)->length())->value()) :
8884 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8885 if ((index < length) &&
8886 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
8887 return true;
8888 }
8889 break;
8890 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008891 case EXTERNAL_PIXEL_ELEMENTS: {
8892 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008893 if (index < static_cast<uint32_t>(pixels->length())) {
8894 return true;
8895 }
8896 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008897 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008898 case EXTERNAL_BYTE_ELEMENTS:
8899 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8900 case EXTERNAL_SHORT_ELEMENTS:
8901 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8902 case EXTERNAL_INT_ELEMENTS:
8903 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008904 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008905 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008906 ExternalArray* array = ExternalArray::cast(elements());
8907 if (index < static_cast<uint32_t>(array->length())) {
8908 return true;
8909 }
8910 break;
8911 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008912 case DICTIONARY_ELEMENTS: {
8913 if (element_dictionary()->FindEntry(index)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00008914 != SeededNumberDictionary::kNotFound) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008915 return true;
8916 }
8917 break;
8918 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008919 case NON_STRICT_ARGUMENTS_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008920 UNREACHABLE();
8921 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 }
8923
8924 // Handle [] on String objects.
8925 if (this->IsStringObjectWithCharacterAt(index)) return true;
8926
8927 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008928 if (pt->IsNull()) return false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008929 if (pt->IsJSProxy()) {
8930 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
8931 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
8932 receiver, index) != ABSENT;
8933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8935}
8936
8937
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008938bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008939 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008940 // Make sure that the top context does not change when doing
8941 // callbacks or interceptor calls.
8942 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008943 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008944 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008945 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008948 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008949 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008950 v8::IndexedPropertyQuery query =
8951 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 LOG(isolate,
8953 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008954 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955 {
8956 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008957 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008958 result = query(index, info);
8959 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008960 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00008961 ASSERT(result->IsInt32());
8962 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008963 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 } else if (!interceptor->getter()->IsUndefined()) {
8965 v8::IndexedPropertyGetter getter =
8966 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 LOG(isolate,
8968 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969 v8::Handle<v8::Value> result;
8970 {
8971 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 result = getter(index, info);
8974 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008975 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976 }
8977 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
8978}
8979
8980
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008981JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008983 if (IsAccessCheckNeeded()) {
8984 Heap* heap = GetHeap();
8985 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8986 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8987 return UNDEFINED_ELEMENT;
8988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989 }
8990
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008991 if (IsJSGlobalProxy()) {
8992 Object* proto = GetPrototype();
8993 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8994 ASSERT(proto->IsJSGlobalObject());
8995 return JSObject::cast(proto)->HasLocalElement(index);
8996 }
8997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008998 // Check for lookup interceptor
8999 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009000 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
9001 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009002 }
9003
9004 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009005 if (this->IsStringObjectWithCharacterAt(index)) {
9006 return STRING_CHARACTER_ELEMENT;
9007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009009 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009010 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009011 case FAST_ELEMENTS: {
9012 uint32_t length = IsJSArray() ?
9013 static_cast<uint32_t>
9014 (Smi::cast(JSArray::cast(this)->length())->value()) :
9015 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009016 if ((index < length) &&
9017 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
9018 return FAST_ELEMENT;
9019 }
9020 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009021 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00009022 case FAST_DOUBLE_ELEMENTS: {
9023 uint32_t length = IsJSArray() ?
9024 static_cast<uint32_t>
9025 (Smi::cast(JSArray::cast(this)->length())->value()) :
9026 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9027 if ((index < length) &&
9028 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
9029 return FAST_ELEMENT;
9030 }
9031 break;
9032 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009033 case EXTERNAL_PIXEL_ELEMENTS: {
9034 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009035 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
9036 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009037 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009038 case EXTERNAL_BYTE_ELEMENTS:
9039 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9040 case EXTERNAL_SHORT_ELEMENTS:
9041 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9042 case EXTERNAL_INT_ELEMENTS:
9043 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009044 case EXTERNAL_FLOAT_ELEMENTS:
9045 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009046 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009047 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
9048 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00009049 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009050 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009051 if (element_dictionary()->FindEntry(index) !=
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009052 SeededNumberDictionary::kNotFound) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009053 return DICTIONARY_ELEMENT;
9054 }
9055 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009056 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009057 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9058 // Aliased parameters and non-aliased elements in a fast backing store
9059 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
9060 // backing store behave as DICTIONARY_ELEMENT.
9061 FixedArray* parameter_map = FixedArray::cast(elements());
9062 uint32_t length = parameter_map->length();
9063 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00009064 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009065 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
9066 // If not aliased, check the arguments.
9067 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9068 if (arguments->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009069 SeededNumberDictionary* dictionary =
9070 SeededNumberDictionary::cast(arguments);
9071 if (dictionary->FindEntry(index) != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009072 return DICTIONARY_ELEMENT;
9073 }
9074 } else {
9075 length = arguments->length();
9076 probe = (index < length) ? arguments->get(index) : NULL;
9077 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
9078 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009079 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009080 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009081 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009082
9083 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084}
9085
9086
whesse@chromium.org7b260152011-06-20 15:33:18 +00009087bool JSObject::HasElementInElements(FixedArray* elements,
9088 ElementsKind kind,
9089 uint32_t index) {
9090 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
9091 if (kind == FAST_ELEMENTS) {
9092 int length = IsJSArray()
9093 ? Smi::cast(JSArray::cast(this)->length())->value()
9094 : elements->length();
9095 if (index < static_cast<uint32_t>(length) &&
9096 !elements->get(index)->IsTheHole()) {
9097 return true;
9098 }
9099 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009100 if (SeededNumberDictionary::cast(elements)->FindEntry(index) !=
9101 SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009102 return true;
9103 }
9104 }
9105 return false;
9106}
9107
9108
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00009109bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009111 if (IsAccessCheckNeeded()) {
9112 Heap* heap = GetHeap();
9113 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9114 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9115 return false;
9116 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009117 }
9118
9119 // Check for lookup interceptor
9120 if (HasIndexedInterceptor()) {
9121 return HasElementWithInterceptor(receiver, index);
9122 }
9123
whesse@chromium.org7b260152011-06-20 15:33:18 +00009124 ElementsKind kind = GetElementsKind();
9125 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009126 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009127 case FAST_ELEMENTS: {
9128 uint32_t length = IsJSArray() ?
9129 static_cast<uint32_t>
9130 (Smi::cast(JSArray::cast(this)->length())->value()) :
9131 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9132 if ((index < length) &&
9133 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
9134 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009135 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00009136 case FAST_DOUBLE_ELEMENTS: {
9137 uint32_t length = IsJSArray() ?
9138 static_cast<uint32_t>
9139 (Smi::cast(JSArray::cast(this)->length())->value()) :
9140 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9141 if ((index < length) &&
9142 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
9143 break;
9144 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009145 case EXTERNAL_PIXEL_ELEMENTS: {
9146 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009147 if (index < static_cast<uint32_t>(pixels->length())) {
9148 return true;
9149 }
9150 break;
9151 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009152 case EXTERNAL_BYTE_ELEMENTS:
9153 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9154 case EXTERNAL_SHORT_ELEMENTS:
9155 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9156 case EXTERNAL_INT_ELEMENTS:
9157 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009158 case EXTERNAL_FLOAT_ELEMENTS:
9159 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009160 ExternalArray* array = ExternalArray::cast(elements());
9161 if (index < static_cast<uint32_t>(array->length())) {
9162 return true;
9163 }
9164 break;
9165 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009166 case DICTIONARY_ELEMENTS: {
9167 if (element_dictionary()->FindEntry(index)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009168 != SeededNumberDictionary::kNotFound) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009169 return true;
9170 }
9171 break;
9172 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009173 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9174 FixedArray* parameter_map = FixedArray::cast(elements());
9175 uint32_t length = parameter_map->length();
9176 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00009177 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009178 if (probe != NULL && !probe->IsTheHole()) return true;
9179
9180 // Not a mapped parameter, check the arguments.
9181 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9182 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
9183 if (HasElementInElements(arguments, kind, index)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009184 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186 }
9187
9188 // Handle [] on String objects.
9189 if (this->IsStringObjectWithCharacterAt(index)) return true;
9190
9191 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 if (pt->IsNull()) return false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009193 if (pt->IsJSProxy()) {
9194 // We need to follow the spec and simulate a call to [[GetOwnProperty]].
9195 return JSProxy::cast(pt)->GetElementAttributeWithHandler(
9196 receiver, index) != ABSENT;
9197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
9199}
9200
9201
lrn@chromium.org303ada72010-10-27 09:33:13 +00009202MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009203 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009204 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009205 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009206 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009207 // Make sure that the top context does not change when doing
9208 // callbacks or interceptor calls.
9209 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009210 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009211 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
9212 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009214 if (!interceptor->setter()->IsUndefined()) {
9215 v8::IndexedPropertySetter setter =
9216 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009217 LOG(isolate,
9218 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
9219 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009220 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221 v8::Handle<v8::Value> result;
9222 {
9223 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225 result = setter(index, v8::Utils::ToLocal(value_handle), info);
9226 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009227 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 if (!result.IsEmpty()) return *value_handle;
9229 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009230 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009231 this_handle->SetElementWithoutInterceptor(index,
9232 *value_handle,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009233 strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009234 check_prototype);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009235 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236 return raw_result;
9237}
9238
9239
lrn@chromium.org303ada72010-10-27 09:33:13 +00009240MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
9241 Object* structure,
9242 uint32_t index,
9243 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009244 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009245 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009246
9247 // api style callbacks.
9248 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009249 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009250 Object* fun_obj = data->getter();
9251 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009252 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009253 Handle<JSObject> self(JSObject::cast(receiver));
9254 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009255 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009256 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
9258 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009259 v8::AccessorInfo info(args.end());
9260 v8::Handle<v8::Value> result;
9261 {
9262 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009263 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009264 result = call_fun(v8::Utils::ToLocal(key), info);
9265 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009266 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
9267 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009268 return *v8::Utils::OpenHandle(*result);
9269 }
9270
9271 // __defineGetter__ callback
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009272 if (structure->IsAccessorPair()) {
9273 Object* getter = AccessorPair::cast(structure)->getter();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009274 if (getter->IsSpecFunction()) {
9275 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9276 return GetPropertyWithDefinedGetter(receiver, JSReceiver::cast(getter));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009277 }
9278 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009280 }
9281
9282 UNREACHABLE();
9283 return NULL;
9284}
9285
9286
lrn@chromium.org303ada72010-10-27 09:33:13 +00009287MaybeObject* JSObject::SetElementWithCallback(Object* structure,
9288 uint32_t index,
9289 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009290 JSObject* holder,
9291 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009292 Isolate* isolate = GetIsolate();
9293 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009294
9295 // We should never get here to initialize a const with the hole
9296 // value since a const declaration would conflict with the setter.
9297 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009298 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009299
9300 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009301 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009302 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009303 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009304
9305 if (structure->IsAccessorInfo()) {
9306 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009307 Handle<JSObject> self(this);
9308 Handle<JSObject> holder_handle(JSObject::cast(holder));
9309 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009310 Object* call_obj = data->setter();
9311 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
9312 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009313 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9314 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009315 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
9316 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009317 v8::AccessorInfo info(args.end());
9318 {
9319 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009320 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009321 call_fun(v8::Utils::ToLocal(key),
9322 v8::Utils::ToLocal(value_handle),
9323 info);
9324 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009325 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009326 return *value_handle;
9327 }
9328
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009329 if (structure->IsAccessorPair()) {
9330 Handle<Object> setter(AccessorPair::cast(structure)->setter());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009331 if (setter->IsSpecFunction()) {
9332 // TODO(rossberg): nicer would be to cast to some JSCallable here...
9333 return SetPropertyWithDefinedSetter(JSReceiver::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009334 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009335 if (strict_mode == kNonStrictMode) {
9336 return value;
9337 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009338 Handle<Object> holder_handle(holder, isolate);
9339 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009340 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 return isolate->Throw(
9342 *isolate->factory()->NewTypeError("no_setter_in_callback",
9343 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00009344 }
9345 }
9346
9347 UNREACHABLE();
9348 return NULL;
9349}
9350
9351
whesse@chromium.org7b260152011-06-20 15:33:18 +00009352bool JSObject::HasFastArgumentsElements() {
9353 Heap* heap = GetHeap();
9354 if (!elements()->IsFixedArray()) return false;
9355 FixedArray* elements = FixedArray::cast(this->elements());
9356 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9357 return false;
9358 }
9359 FixedArray* arguments = FixedArray::cast(elements->get(1));
9360 return !arguments->IsDictionary();
9361}
9362
9363
9364bool JSObject::HasDictionaryArgumentsElements() {
9365 Heap* heap = GetHeap();
9366 if (!elements()->IsFixedArray()) return false;
9367 FixedArray* elements = FixedArray::cast(this->elements());
9368 if (elements->map() != heap->non_strict_arguments_elements_map()) {
9369 return false;
9370 }
9371 FixedArray* arguments = FixedArray::cast(elements->get(1));
9372 return arguments->IsDictionary();
9373}
9374
9375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009376// Adding n elements in fast case is O(n*n).
9377// Note: revisit design to have dual undefined values to capture absent
9378// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009379MaybeObject* JSObject::SetFastElement(uint32_t index,
9380 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009381 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009382 bool check_prototype) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009383 ASSERT(HasFastTypeElements() ||
9384 HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385
whesse@chromium.org7b260152011-06-20 15:33:18 +00009386 FixedArray* backing_store = FixedArray::cast(elements());
9387 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
9388 backing_store = FixedArray::cast(backing_store->get(1));
9389 } else {
9390 Object* writable;
9391 MaybeObject* maybe = EnsureWritableFastElements();
9392 if (!maybe->ToObject(&writable)) return maybe;
9393 backing_store = FixedArray::cast(writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009394 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009395 uint32_t capacity = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009396
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009397 if (check_prototype &&
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009398 (index >= capacity || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00009399 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00009400 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9401 value,
9402 &found,
9403 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00009404 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009405 }
9406
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009407 uint32_t new_capacity = capacity;
9408 // Check if the length property of this object needs to be updated.
9409 uint32_t array_length = 0;
9410 bool must_update_array_length = false;
9411 if (IsJSArray()) {
9412 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9413 if (index >= array_length) {
9414 must_update_array_length = true;
9415 array_length = index + 1;
9416 }
9417 }
9418 // Check if the capacity of the backing store needs to be increased, or if
9419 // a transition to slow elements is necessary.
9420 if (index >= capacity) {
9421 bool convert_to_slow = true;
9422 if ((index - capacity) < kMaxGap) {
9423 new_capacity = NewElementsCapacity(index + 1);
9424 ASSERT(new_capacity > index);
9425 if (!ShouldConvertToSlowElements(new_capacity)) {
9426 convert_to_slow = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009427 }
9428 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009429 if (convert_to_slow) {
9430 MaybeObject* result = NormalizeElements();
9431 if (result->IsFailure()) return result;
9432 return SetDictionaryElement(index, value, strict_mode, check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009433 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009434 }
9435 // Convert to fast double elements if appropriate.
9436 if (HasFastSmiOnlyElements() && !value->IsSmi() && value->IsNumber()) {
9437 MaybeObject* maybe =
9438 SetFastDoubleElementsCapacityAndLength(new_capacity, array_length);
9439 if (maybe->IsFailure()) return maybe;
9440 FixedDoubleArray::cast(elements())->set(index, value->Number());
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00009441 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009442 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009443 // Change elements kind from SMI_ONLY to generic FAST if necessary.
9444 if (HasFastSmiOnlyElements() && !value->IsSmi()) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009445 MaybeObject* maybe_new_map = GetElementsTransitionMap(GetIsolate(),
9446 FAST_ELEMENTS);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009447 Map* new_map;
9448 if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
9449 set_map(new_map);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009450 if (FLAG_trace_elements_transitions) {
9451 PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
9452 FAST_ELEMENTS, elements());
9453 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009454 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00009455 // Increase backing store capacity if that's been decided previously.
9456 if (new_capacity != capacity) {
9457 Object* new_elements;
9458 SetFastElementsCapacityMode set_capacity_mode =
9459 value->IsSmi() && HasFastSmiOnlyElements()
9460 ? kAllowSmiOnlyElements
9461 : kDontAllowSmiOnlyElements;
9462 MaybeObject* maybe =
9463 SetFastElementsCapacityAndLength(new_capacity,
9464 array_length,
9465 set_capacity_mode);
9466 if (!maybe->ToObject(&new_elements)) return maybe;
9467 FixedArray::cast(new_elements)->set(index, value);
9468 return value;
9469 }
9470 // Finally, set the new element and length.
9471 ASSERT(elements()->IsFixedArray());
9472 backing_store->set(index, value);
9473 if (must_update_array_length) {
9474 JSArray::cast(this)->set_length(Smi::FromInt(array_length));
9475 }
9476 return value;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009477}
9478
9479
9480MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
9481 Object* value,
9482 StrictModeFlag strict_mode,
9483 bool check_prototype) {
9484 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
9485 Isolate* isolate = GetIsolate();
9486 Heap* heap = isolate->heap();
9487
9488 // Insert element in the dictionary.
9489 FixedArray* elements = FixedArray::cast(this->elements());
9490 bool is_arguments =
9491 (elements->map() == heap->non_strict_arguments_elements_map());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009492 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009493 if (is_arguments) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009494 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00009495 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009496 dictionary = SeededNumberDictionary::cast(elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009497 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009498
9499 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009500 if (entry != SeededNumberDictionary::kNotFound) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009501 Object* element = dictionary->ValueAt(entry);
9502 PropertyDetails details = dictionary->DetailsAt(entry);
9503 if (details.type() == CALLBACKS) {
9504 return SetElementWithCallback(element, index, value, this, strict_mode);
9505 } else {
9506 dictionary->UpdateMaxNumberKey(index);
9507 // If put fails in strict mode, throw an exception.
9508 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009509 Handle<Object> holder(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00009510 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009511 Handle<Object> args[2] = { number, holder };
9512 Handle<Object> error =
9513 isolate->factory()->NewTypeError("strict_read_only_property",
9514 HandleVector(args, 2));
9515 return isolate->Throw(*error);
9516 }
9517 }
9518 } else {
9519 // Index not already used. Look for an accessor in the prototype chain.
9520 if (check_prototype) {
9521 bool found;
9522 MaybeObject* result =
9523 SetElementWithCallbackSetterInPrototypes(
9524 index, value, &found, strict_mode);
9525 if (found) return result;
9526 }
9527 // When we set the is_extensible flag to false we always force the
9528 // element into dictionary mode (and force them to stay there).
9529 if (!map()->is_extensible()) {
9530 if (strict_mode == kNonStrictMode) {
9531 return isolate->heap()->undefined_value();
9532 } else {
9533 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
9534 Handle<String> name = isolate->factory()->NumberToString(number);
9535 Handle<Object> args[1] = { name };
9536 Handle<Object> error =
9537 isolate->factory()->NewTypeError("object_not_extensible",
9538 HandleVector(args, 1));
9539 return isolate->Throw(*error);
9540 }
9541 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009542 FixedArrayBase* new_dictionary;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009543 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009544 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009545 if (dictionary != SeededNumberDictionary::cast(new_dictionary)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009546 if (is_arguments) {
9547 elements->set(1, new_dictionary);
9548 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009549 set_elements(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009550 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009551 dictionary = SeededNumberDictionary::cast(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009552 }
9553 }
9554
9555 // Update the array length if this JSObject is an array.
9556 if (IsJSArray()) {
9557 MaybeObject* result =
9558 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
9559 if (result->IsFailure()) return result;
9560 }
9561
9562 // Attempt to put this object back in fast case.
9563 if (ShouldConvertToFastElements()) {
9564 uint32_t new_length = 0;
9565 if (IsJSArray()) {
9566 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
9567 } else {
9568 new_length = dictionary->max_number_key() + 1;
9569 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00009570 SetFastElementsCapacityMode set_capacity_mode = FLAG_smi_only_arrays
9571 ? kAllowSmiOnlyElements
9572 : kDontAllowSmiOnlyElements;
9573 bool has_smi_only_elements = false;
9574 bool should_convert_to_fast_double_elements =
9575 ShouldConvertToFastDoubleElements(&has_smi_only_elements);
9576 if (has_smi_only_elements) {
9577 set_capacity_mode = kForceSmiOnlyElements;
9578 }
9579 MaybeObject* result = should_convert_to_fast_double_elements
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009580 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009581 : SetFastElementsCapacityAndLength(new_length,
9582 new_length,
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +00009583 set_capacity_mode);
whesse@chromium.org7b260152011-06-20 15:33:18 +00009584 if (result->IsFailure()) return result;
9585#ifdef DEBUG
9586 if (FLAG_trace_normalization) {
9587 PrintF("Object elements are fast case again:\n");
9588 Print();
9589 }
9590#endif
9591 }
9592 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593}
9594
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009595
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009596MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
9597 uint32_t index,
9598 Object* value,
9599 StrictModeFlag strict_mode,
9600 bool check_prototype) {
9601 ASSERT(HasFastDoubleElements());
9602
9603 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
9604 uint32_t elms_length = static_cast<uint32_t>(elms->length());
9605
9606 // If storing to an element that isn't in the array, pass the store request
9607 // up the prototype chain before storing in the receiver's elements.
9608 if (check_prototype &&
9609 (index >= elms_length || elms->is_the_hole(index))) {
9610 bool found;
9611 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
9612 value,
9613 &found,
9614 strict_mode);
9615 if (found) return result;
9616 }
9617
9618 // If the value object is not a heap number, switch to fast elements and try
9619 // again.
9620 bool value_is_smi = value->IsSmi();
9621 if (!value->IsNumber()) {
9622 Object* obj;
9623 uint32_t length = elms_length;
9624 if (IsJSArray()) {
9625 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
9626 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009627 MaybeObject* maybe_obj = SetFastElementsCapacityAndLength(
9628 elms_length,
9629 length,
9630 kDontAllowSmiOnlyElements);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009631 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009632 return SetFastElement(index,
9633 value,
9634 strict_mode,
9635 check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009636 }
9637
9638 double double_value = value_is_smi
9639 ? static_cast<double>(Smi::cast(value)->value())
9640 : HeapNumber::cast(value)->value();
9641
9642 // Check whether there is extra space in the fixed array.
9643 if (index < elms_length) {
9644 elms->set(index, double_value);
9645 if (IsJSArray()) {
9646 // Update the length of the array if needed.
9647 uint32_t array_length = 0;
9648 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
9649 if (index >= array_length) {
9650 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
9651 }
9652 }
9653 return value;
9654 }
9655
9656 // Allow gap in fast case.
9657 if ((index - elms_length) < kMaxGap) {
9658 // Try allocating extra space.
9659 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00009660 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009661 ASSERT(static_cast<uint32_t>(new_capacity) > index);
9662 Object* obj;
9663 { MaybeObject* maybe_obj =
9664 SetFastDoubleElementsCapacityAndLength(new_capacity,
9665 index + 1);
9666 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9667 }
9668 FixedDoubleArray::cast(elements())->set(index, double_value);
9669 return value;
9670 }
9671 }
9672
9673 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009674 ASSERT(HasFastDoubleElements());
9675 ASSERT(map()->has_fast_double_elements());
9676 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009677 Object* obj;
9678 { MaybeObject* maybe_obj = NormalizeElements();
9679 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9680 }
9681 ASSERT(HasDictionaryElements());
9682 return SetElement(index, value, strict_mode, check_prototype);
9683}
9684
9685
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009686MaybeObject* JSReceiver::SetElement(uint32_t index,
9687 Object* value,
9688 StrictModeFlag strict_mode,
9689 bool check_proto) {
9690 return IsJSProxy()
9691 ? JSProxy::cast(this)->SetElementWithHandler(index, value, strict_mode)
9692 : JSObject::cast(this)->SetElement(index, value, strict_mode, check_proto)
9693 ;
9694}
9695
9696
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009697Handle<Object> JSObject::SetOwnElement(Handle<JSObject> object,
9698 uint32_t index,
9699 Handle<Object> value,
9700 StrictModeFlag strict_mode) {
9701 ASSERT(!object->HasExternalArrayElements());
9702 CALL_HEAP_FUNCTION(object->GetIsolate(),
9703 object->SetElement(index, *value, strict_mode, false),
9704 Object);
9705}
9706
9707
9708Handle<Object> JSObject::SetElement(Handle<JSObject> object,
9709 uint32_t index,
9710 Handle<Object> value,
9711 StrictModeFlag strict_mode) {
9712 if (object->HasExternalArrayElements()) {
9713 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) {
9714 bool has_exception;
9715 Handle<Object> number = Execution::ToNumber(value, &has_exception);
9716 if (has_exception) return Handle<Object>();
9717 value = number;
9718 }
9719 }
9720 CALL_HEAP_FUNCTION(object->GetIsolate(),
9721 object->SetElement(index, *value, strict_mode, true),
9722 Object);
9723}
9724
9725
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009726MaybeObject* JSObject::SetElement(uint32_t index,
9727 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009728 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009729 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009730 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009731 if (IsAccessCheckNeeded()) {
9732 Heap* heap = GetHeap();
9733 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009734 HandleScope scope(heap->isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009735 Handle<Object> value_handle(value);
9736 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
9737 return *value_handle;
9738 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009739 }
9740
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009741 if (IsJSGlobalProxy()) {
9742 Object* proto = GetPrototype();
9743 if (proto->IsNull()) return value;
9744 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009745 return JSObject::cast(proto)->SetElement(index,
9746 value,
9747 strict_mode,
9748 check_prototype);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009749 }
9750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009751 // Check for lookup interceptor
9752 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009753 return SetElementWithInterceptor(index,
9754 value,
9755 strict_mode,
9756 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 }
9758
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009759 return SetElementWithoutInterceptor(index,
9760 value,
9761 strict_mode,
9762 check_prototype);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009763}
9764
9765
lrn@chromium.org303ada72010-10-27 09:33:13 +00009766MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009767 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009768 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00009769 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009770 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009771 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009772 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009773 case FAST_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009774 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009775 case FAST_DOUBLE_ELEMENTS:
9776 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009777 case EXTERNAL_PIXEL_ELEMENTS: {
9778 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009779 return pixels->SetValue(index, value);
9780 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009781 case EXTERNAL_BYTE_ELEMENTS: {
9782 ExternalByteArray* array = ExternalByteArray::cast(elements());
9783 return array->SetValue(index, value);
9784 }
9785 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9786 ExternalUnsignedByteArray* array =
9787 ExternalUnsignedByteArray::cast(elements());
9788 return array->SetValue(index, value);
9789 }
9790 case EXTERNAL_SHORT_ELEMENTS: {
9791 ExternalShortArray* array = ExternalShortArray::cast(elements());
9792 return array->SetValue(index, value);
9793 }
9794 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9795 ExternalUnsignedShortArray* array =
9796 ExternalUnsignedShortArray::cast(elements());
9797 return array->SetValue(index, value);
9798 }
9799 case EXTERNAL_INT_ELEMENTS: {
9800 ExternalIntArray* array = ExternalIntArray::cast(elements());
9801 return array->SetValue(index, value);
9802 }
9803 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9804 ExternalUnsignedIntArray* array =
9805 ExternalUnsignedIntArray::cast(elements());
9806 return array->SetValue(index, value);
9807 }
9808 case EXTERNAL_FLOAT_ELEMENTS: {
9809 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9810 return array->SetValue(index, value);
9811 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009812 case EXTERNAL_DOUBLE_ELEMENTS: {
9813 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9814 return array->SetValue(index, value);
9815 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009816 case DICTIONARY_ELEMENTS:
9817 return SetDictionaryElement(index, value, strict_mode, check_prototype);
9818 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9819 FixedArray* parameter_map = FixedArray::cast(elements());
9820 uint32_t length = parameter_map->length();
9821 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00009822 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009823 if (probe != NULL && !probe->IsTheHole()) {
9824 Context* context = Context::cast(parameter_map->get(0));
9825 int context_index = Smi::cast(probe)->value();
9826 ASSERT(!context->get(context_index)->IsTheHole());
9827 context->set(context_index, value);
9828 return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009829 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009830 // Object is not mapped, defer to the arguments.
9831 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9832 if (arguments->IsDictionary()) {
9833 return SetDictionaryElement(index, value, strict_mode,
9834 check_prototype);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009835 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009836 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009837 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009838 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009839 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009840 }
9841 // All possible cases have been handled above. Add a return to avoid the
9842 // complaints from the compiler.
9843 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009844 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009845}
9846
9847
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009848Handle<Object> JSObject::TransitionElementsKind(Handle<JSObject> object,
9849 ElementsKind to_kind) {
9850 CALL_HEAP_FUNCTION(object->GetIsolate(),
9851 object->TransitionElementsKind(to_kind),
9852 Object);
9853}
9854
9855
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009856MaybeObject* JSObject::TransitionElementsKind(ElementsKind to_kind) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009857 ElementsKind from_kind = map()->elements_kind();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00009858
9859 Isolate* isolate = GetIsolate();
9860 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9861 (to_kind == FAST_ELEMENTS ||
9862 elements() == isolate->heap()->empty_fixed_array())) {
9863 MaybeObject* maybe_new_map = GetElementsTransitionMap(isolate, to_kind);
9864 Map* new_map;
9865 if (!maybe_new_map->To(&new_map)) return maybe_new_map;
9866 set_map(new_map);
9867 if (FLAG_trace_elements_transitions) {
9868 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9869 PrintElementsTransition(stdout, from_kind, elms, to_kind, elms);
9870 }
9871 return this;
9872 }
9873
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009874 FixedArrayBase* elms = FixedArrayBase::cast(elements());
9875 uint32_t capacity = static_cast<uint32_t>(elms->length());
9876 uint32_t length = capacity;
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009877
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009878 if (IsJSArray()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009879 Object* raw_length = JSArray::cast(this)->length();
9880 if (raw_length->IsUndefined()) {
9881 // If length is undefined, then JSArray is being initialized and has no
9882 // elements, assume a length of zero.
9883 length = 0;
9884 } else {
9885 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009886 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009887 }
9888
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009889 if (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9890 to_kind == FAST_DOUBLE_ELEMENTS) {
9891 MaybeObject* maybe_result =
9892 SetFastDoubleElementsCapacityAndLength(capacity, length);
9893 if (maybe_result->IsFailure()) return maybe_result;
9894 return this;
9895 }
9896
9897 if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009898 MaybeObject* maybe_result = SetFastElementsCapacityAndLength(
9899 capacity, length, kDontAllowSmiOnlyElements);
9900 if (maybe_result->IsFailure()) return maybe_result;
9901 return this;
9902 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009903
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009904 // This method should never be called for any other case than the ones
9905 // handled above.
9906 UNREACHABLE();
9907 return GetIsolate()->heap()->null_value();
9908}
9909
9910
9911// static
9912bool Map::IsValidElementsTransition(ElementsKind from_kind,
9913 ElementsKind to_kind) {
9914 return
9915 (from_kind == FAST_SMI_ONLY_ELEMENTS &&
9916 (to_kind == FAST_DOUBLE_ELEMENTS || to_kind == FAST_ELEMENTS)) ||
9917 (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS);
9918}
9919
9920
lrn@chromium.org303ada72010-10-27 09:33:13 +00009921MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
9922 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009924 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925 // Check to see if we need to update the length. For now, we make
9926 // sure that the length stays within 32-bits (unsigned).
9927 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009928 Object* len;
9929 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009930 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009931 if (!maybe_len->ToObject(&len)) return maybe_len;
9932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933 set_length(len);
9934 }
9935 return value;
9936}
9937
9938
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00009939MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009940 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009941 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942 // Make sure that the top context does not change when doing
9943 // callbacks or interceptor calls.
9944 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009945 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009946 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
9947 Handle<Object> this_handle(receiver, isolate);
9948 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009949 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950 v8::IndexedPropertyGetter getter =
9951 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009952 LOG(isolate,
9953 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
9954 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00009955 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956 v8::Handle<v8::Value> result;
9957 {
9958 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009959 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009960 result = getter(index, info);
9961 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009962 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009963 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
9964 }
9965
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009966 Heap* heap = holder_handle->GetHeap();
9967 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
rossberg@chromium.org28a37082011-08-22 11:03:23 +00009968 MaybeObject* raw_result = handler->Get(holder_handle->elements(),
9969 index,
9970 *holder_handle,
9971 *this_handle);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009972 if (raw_result != heap->the_hole_value()) return raw_result;
9973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009974 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009976 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009977 if (pt == heap->null_value()) return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009978 return pt->GetElementWithReceiver(*this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009979}
9980
9981
9982bool JSObject::HasDenseElements() {
9983 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009984 int used = 0;
9985 GetElementsCapacityAndUsage(&capacity, &used);
9986 return (capacity == 0) || (used > (capacity / 2));
9987}
9988
9989
9990void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
9991 *capacity = 0;
9992 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009994 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9995 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009996 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00009997 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00009998 backing_store_base =
9999 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
10000 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +000010001 if (backing_store->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010002 SeededNumberDictionary* dictionary =
10003 SeededNumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010004 *capacity = dictionary->Capacity();
10005 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +000010006 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010007 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010008 // Fall through.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010009 case FAST_SMI_ONLY_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +000010010 case FAST_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010011 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010012 *capacity = backing_store->length();
10013 for (int i = 0; i < *capacity; ++i) {
10014 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +000010015 }
10016 break;
10017 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010018 SeededNumberDictionary* dictionary =
10019 SeededNumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010020 *capacity = dictionary->Capacity();
10021 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010022 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010023 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010024 case FAST_DOUBLE_ELEMENTS: {
10025 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010026 *capacity = elms->length();
10027 for (int i = 0; i < *capacity; i++) {
10028 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010029 }
10030 break;
10031 }
ager@chromium.org3811b432009-10-28 14:53:37 +000010032 case EXTERNAL_BYTE_ELEMENTS:
10033 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10034 case EXTERNAL_SHORT_ELEMENTS:
10035 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10036 case EXTERNAL_INT_ELEMENTS:
10037 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010038 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010039 case EXTERNAL_DOUBLE_ELEMENTS:
10040 case EXTERNAL_PIXEL_ELEMENTS:
10041 // External arrays are considered 100% used.
10042 ExternalArray* external_array = ExternalArray::cast(elements());
10043 *capacity = external_array->length();
10044 *used = external_array->length();
10045 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047}
10048
10049
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010050bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010051 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
10052 kMaxUncheckedFastElementsLength);
10053 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
10054 (new_capacity <= kMaxUncheckedFastElementsLength &&
10055 GetHeap()->InNewSpace(this))) {
10056 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010057 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010058 // If the fast-case backing storage takes up roughly three times as
10059 // much space (in machine words) as a dictionary backing storage
10060 // would, the object should have slow elements.
10061 int old_capacity = 0;
10062 int used_elements = 0;
10063 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010064 int dictionary_size = SeededNumberDictionary::ComputeCapacity(used_elements) *
10065 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010066 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067}
10068
10069
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010070bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +000010071 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072 // If the elements are sparse, we should not go back to fast case.
10073 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010074 // An object requiring access checks is never allowed to have fast
10075 // elements. If it had fast elements we would skip security checks.
10076 if (IsAccessCheckNeeded()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010077
10078 FixedArray* elements = FixedArray::cast(this->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010079 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010080 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010081 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +000010082 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010083 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +000010084 }
10085 // If an element has been added at a very high index in the elements
10086 // dictionary, we cannot go back to fast case.
10087 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010088 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010089 // space (in machine words) as a fast-case backing storage would,
10090 // the object should have fast elements.
10091 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010093 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010094 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010095 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010096 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010097 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010098 SeededNumberDictionary::kEntrySize;
ricow@chromium.org2c99e282011-07-28 09:15:17 +000010099 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010100}
10101
10102
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010103bool JSObject::ShouldConvertToFastDoubleElements(
10104 bool* has_smi_only_elements) {
10105 *has_smi_only_elements = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010106 if (FLAG_unbox_double_arrays) {
10107 ASSERT(HasDictionaryElements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010108 SeededNumberDictionary* dictionary =
10109 SeededNumberDictionary::cast(elements());
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010110 bool found_double = false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010111 for (int i = 0; i < dictionary->Capacity(); i++) {
10112 Object* key = dictionary->KeyAt(i);
10113 if (key->IsNumber()) {
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010114 Object* value = dictionary->ValueAt(i);
10115 if (!value->IsNumber()) return false;
10116 if (!value->IsSmi()) {
10117 found_double = true;
10118 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010119 }
10120 }
svenpanne@chromium.org3c93e772012-01-02 09:26:59 +000010121 *has_smi_only_elements = !found_double;
10122 return found_double;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010123 } else {
10124 return false;
10125 }
10126}
10127
10128
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010129// Certain compilers request function template instantiation when they
10130// see the definition of the other template functions in the
10131// class. This requires us to have the template functions put
10132// together, so even though this function belongs in objects-debug.cc,
10133// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +000010134#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010135template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +000010136void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010137 int capacity = HashTable<Shape, Key>::Capacity();
10138 for (int i = 0; i < capacity; i++) {
10139 Object* k = HashTable<Shape, Key>::KeyAt(i);
10140 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010141 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010142 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010143 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010144 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +000010145 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010146 }
whesse@chromium.org023421e2010-12-21 12:19:12 +000010147 PrintF(out, ": ");
10148 ValueAt(i)->ShortPrint(out);
10149 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010150 }
10151 }
10152}
10153#endif
10154
10155
10156template<typename Shape, typename Key>
10157void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010158 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010159 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010160 AssertNoAllocation no_gc;
10161 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010163 Object* k = Dictionary<Shape, Key>::KeyAt(i);
10164 if (Dictionary<Shape, Key>::IsKey(k)) {
10165 elements->set(pos++, ValueAt(i), mode);
10166 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167 }
10168 ASSERT(pos == elements->length());
10169}
10170
10171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172InterceptorInfo* JSObject::GetNamedInterceptor() {
10173 ASSERT(map()->has_named_interceptor());
10174 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010175 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010177 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178 return InterceptorInfo::cast(result);
10179}
10180
10181
10182InterceptorInfo* JSObject::GetIndexedInterceptor() {
10183 ASSERT(map()->has_indexed_interceptor());
10184 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010185 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010186 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000010187 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 return InterceptorInfo::cast(result);
10189}
10190
10191
lrn@chromium.org303ada72010-10-27 09:33:13 +000010192MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010193 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010194 String* name,
10195 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010197 LookupResult result(GetIsolate());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010198 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +000010199 if (result.IsProperty()) {
10200 return GetProperty(receiver, &result, name, attributes);
10201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010202 // Continue searching via the prototype chain.
10203 Object* pt = GetPrototype();
10204 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010205 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010206 return pt->GetPropertyWithReceiver(receiver, name, attributes);
10207}
10208
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010209
lrn@chromium.org303ada72010-10-27 09:33:13 +000010210MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010211 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010212 String* name,
10213 PropertyAttributes* attributes) {
10214 // Check local property in holder, ignore interceptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010215 LookupResult result(GetIsolate());
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010216 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +000010217 if (result.IsProperty()) {
10218 return GetProperty(receiver, &result, name, attributes);
10219 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010220 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +000010221}
10222
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223
lrn@chromium.org303ada72010-10-27 09:33:13 +000010224MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010225 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +000010226 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010227 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010229 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010230 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +000010231 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 Handle<JSObject> holder_handle(this);
10233 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010234
10235 if (!interceptor->getter()->IsUndefined()) {
10236 v8::NamedPropertyGetter getter =
10237 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010238 LOG(isolate,
10239 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
10240 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +000010241 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242 v8::Handle<v8::Value> result;
10243 {
10244 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010245 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010246 result = getter(v8::Utils::ToLocal(name_handle), info);
10247 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010248 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010249 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010250 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +000010251 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010252 }
10253 }
10254
lrn@chromium.org303ada72010-10-27 09:33:13 +000010255 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 *receiver_handle,
10257 *name_handle,
10258 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010260 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010261}
10262
10263
10264bool JSObject::HasRealNamedProperty(String* key) {
10265 // Check access rights if needed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010266 Isolate* isolate = GetIsolate();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010267 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010268 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10269 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010270 return false;
10271 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010272 }
10273
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010274 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +000010276 return result.IsProperty() && (result.type() != INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277}
10278
10279
10280bool JSObject::HasRealElementProperty(uint32_t index) {
10281 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010282 if (IsAccessCheckNeeded()) {
10283 Heap* heap = GetHeap();
10284 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
10285 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
10286 return false;
10287 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010288 }
10289
10290 // Handle [] on String objects.
10291 if (this->IsStringObjectWithCharacterAt(index)) return true;
10292
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010293 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010294 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010295 case FAST_ELEMENTS: {
10296 uint32_t length = IsJSArray() ?
10297 static_cast<uint32_t>(
10298 Smi::cast(JSArray::cast(this)->length())->value()) :
10299 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10300 return (index < length) &&
10301 !FixedArray::cast(elements())->get(index)->IsTheHole();
10302 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +000010303 case FAST_DOUBLE_ELEMENTS: {
10304 uint32_t length = IsJSArray() ?
10305 static_cast<uint32_t>(
10306 Smi::cast(JSArray::cast(this)->length())->value()) :
10307 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
10308 return (index < length) &&
10309 !FixedDoubleArray::cast(elements())->is_the_hole(index);
10310 break;
10311 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010312 case EXTERNAL_PIXEL_ELEMENTS: {
10313 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010314 return index < static_cast<uint32_t>(pixels->length());
10315 }
ager@chromium.org3811b432009-10-28 14:53:37 +000010316 case EXTERNAL_BYTE_ELEMENTS:
10317 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10318 case EXTERNAL_SHORT_ELEMENTS:
10319 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10320 case EXTERNAL_INT_ELEMENTS:
10321 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010322 case EXTERNAL_FLOAT_ELEMENTS:
10323 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000010324 ExternalArray* array = ExternalArray::cast(elements());
10325 return index < static_cast<uint32_t>(array->length());
10326 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010327 case DICTIONARY_ELEMENTS: {
10328 return element_dictionary()->FindEntry(index)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010329 != SeededNumberDictionary::kNotFound;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010330 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010331 case NON_STRICT_ARGUMENTS_ELEMENTS:
10332 UNIMPLEMENTED();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010333 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010335 // All possibilities have been handled above already.
10336 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010337 return GetHeap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338}
10339
10340
10341bool JSObject::HasRealNamedCallbackProperty(String* key) {
10342 // Check access rights if needed.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010343 Isolate* isolate = GetIsolate();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010344 if (IsAccessCheckNeeded()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010345 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
10346 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010347 return false;
10348 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349 }
10350
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010351 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 LocalLookupRealNamedProperty(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +000010353 return result.IsFound() && (result.type() == CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010354}
10355
10356
10357int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
10358 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010359 DescriptorArray* descs = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010360 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010361 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010362 PropertyDetails details(descs->GetDetails(i));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010363 if (details.IsProperty() && (details.attributes() & filter) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010364 result++;
10365 }
10366 }
10367 return result;
10368 } else {
10369 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
10370 }
10371}
10372
10373
10374int JSObject::NumberOfEnumProperties() {
10375 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
10376}
10377
10378
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010379void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010380 Object* temp = get(i);
10381 set(i, get(j));
10382 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010383 if (this != numbers) {
10384 temp = numbers->get(i);
erikcorry0ad885c2011-11-21 13:51:57 +000010385 numbers->set(i, Smi::cast(numbers->get(j)));
10386 numbers->set(j, Smi::cast(temp));
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010387 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388}
10389
10390
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010391static void InsertionSortPairs(FixedArray* content,
10392 FixedArray* numbers,
10393 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394 for (int i = 1; i < len; i++) {
10395 int j = i;
10396 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010397 (NumberToUint32(numbers->get(j - 1)) >
10398 NumberToUint32(numbers->get(j)))) {
10399 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010400 j--;
10401 }
10402 }
10403}
10404
10405
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010406void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010408 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409
10410 // Bottom-up max-heap construction.
10411 for (int i = 1; i < len; ++i) {
10412 int child_index = i;
10413 while (child_index > 0) {
10414 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010415 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
10416 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010417 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010418 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 } else {
10420 break;
10421 }
10422 child_index = parent_index;
10423 }
10424 }
10425
10426 // Extract elements and create sorted array.
10427 for (int i = len - 1; i > 0; --i) {
10428 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010429 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 // Sift down the new top element.
10431 int parent_index = 0;
10432 while (true) {
10433 int child_index = ((parent_index + 1) << 1) - 1;
10434 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010435 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
10436 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
10437 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010438 if (child_index + 1 >= i || child1_value > child2_value) {
10439 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010440 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010441 parent_index = child_index;
10442 } else {
10443 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010444 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445 parent_index = child_index + 1;
10446 }
10447 }
10448 }
10449}
10450
10451
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010452// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
10453void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
10454 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 // For small arrays, simply use insertion sort.
10456 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010457 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010458 return;
10459 }
10460 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010461 uint32_t min_index = NumberToUint32(numbers->get(0));
10462 uint32_t max_index = min_index;
10463 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010464 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010465 if (NumberToUint32(numbers->get(i)) < min_index) {
10466 min_index = NumberToUint32(numbers->get(i));
10467 } else if (NumberToUint32(numbers->get(i)) > max_index) {
10468 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010469 }
10470 }
10471 if (max_index - min_index + 1 == len) {
10472 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010473 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010474 // avoid hanging in case they are not.
10475 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010476 uint32_t p;
10477 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010478 // While the current element at i is not at its correct position p,
10479 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010480 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010482 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483 }
10484 }
10485 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010486 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010487 return;
10488 }
10489}
10490
10491
10492// Fill in the names of local properties into the supplied storage. The main
10493// purpose of this function is to provide reflection information for the object
10494// mirrors.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010495void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010496 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010497 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010498 DescriptorArray* descs = map()->instance_descriptors();
10499 for (int i = 0; i < descs->number_of_descriptors(); i++) {
10500 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010502 ASSERT(storage->length() >= index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010503 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010504 property_dictionary()->CopyKeysTo(storage,
10505 index,
10506 StringDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010507 }
10508}
10509
10510
10511int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
10512 return GetLocalElementKeys(NULL, filter);
10513}
10514
10515
10516int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010517 // Fast case for objects with no elements.
10518 if (!IsJSValue() && HasFastElements()) {
10519 uint32_t length = IsJSArray() ?
10520 static_cast<uint32_t>(
10521 Smi::cast(JSArray::cast(this)->length())->value()) :
10522 static_cast<uint32_t>(FixedArray::cast(elements())->length());
10523 if (length == 0) return 0;
10524 }
10525 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010526 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
10527}
10528
10529
10530int JSObject::GetLocalElementKeys(FixedArray* storage,
10531 PropertyAttributes filter) {
10532 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010533 switch (GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010534 case FAST_SMI_ONLY_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010535 case FAST_ELEMENTS: {
10536 int length = IsJSArray() ?
10537 Smi::cast(JSArray::cast(this)->length())->value() :
10538 FixedArray::cast(elements())->length();
10539 for (int i = 0; i < length; i++) {
10540 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
10541 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010542 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010543 }
10544 counter++;
10545 }
10546 }
10547 ASSERT(!storage || storage->length() >= counter);
10548 break;
10549 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010550 case FAST_DOUBLE_ELEMENTS: {
10551 int length = IsJSArray() ?
10552 Smi::cast(JSArray::cast(this)->length())->value() :
10553 FixedDoubleArray::cast(elements())->length();
10554 for (int i = 0; i < length; i++) {
10555 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
10556 if (storage != NULL) {
10557 storage->set(counter, Smi::FromInt(i));
10558 }
10559 counter++;
10560 }
10561 }
10562 ASSERT(!storage || storage->length() >= counter);
10563 break;
10564 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010565 case EXTERNAL_PIXEL_ELEMENTS: {
10566 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010567 while (counter < length) {
10568 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010569 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570 }
10571 counter++;
10572 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010573 ASSERT(!storage || storage->length() >= counter);
10574 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010575 }
ager@chromium.org3811b432009-10-28 14:53:37 +000010576 case EXTERNAL_BYTE_ELEMENTS:
10577 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
10578 case EXTERNAL_SHORT_ELEMENTS:
10579 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
10580 case EXTERNAL_INT_ELEMENTS:
10581 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010582 case EXTERNAL_FLOAT_ELEMENTS:
10583 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +000010584 int length = ExternalArray::cast(elements())->length();
10585 while (counter < length) {
10586 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010587 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +000010588 }
10589 counter++;
10590 }
10591 ASSERT(!storage || storage->length() >= counter);
10592 break;
10593 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010594 case DICTIONARY_ELEMENTS: {
10595 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010596 element_dictionary()->CopyKeysTo(storage,
10597 filter,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010598 SeededNumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010599 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010600 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010601 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010602 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010603 case NON_STRICT_ARGUMENTS_ELEMENTS: {
10604 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010605 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010606 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
10607 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010608 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
10609 // will insert in storage starting at index 0.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010610 SeededNumberDictionary* dictionary =
10611 SeededNumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010612 if (storage != NULL) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010613 dictionary->CopyKeysTo(
10614 storage, filter, SeededNumberDictionary::UNSORTED);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010615 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010616 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010617 for (int i = 0; i < mapped_length; ++i) {
10618 if (!parameter_map->get(i + 2)->IsTheHole()) {
10619 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +000010620 ++counter;
10621 }
10622 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010623 if (storage != NULL) storage->SortPairs(storage, counter);
10624
10625 } else {
10626 int backing_length = arguments->length();
10627 int i = 0;
10628 for (; i < mapped_length; ++i) {
10629 if (!parameter_map->get(i + 2)->IsTheHole()) {
10630 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10631 ++counter;
10632 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
10633 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10634 ++counter;
10635 }
10636 }
10637 for (; i < backing_length; ++i) {
10638 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
10639 ++counter;
10640 }
whesse@chromium.org7b260152011-06-20 15:33:18 +000010641 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010642 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +000010643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010644 }
10645
10646 if (this->IsJSValue()) {
10647 Object* val = JSValue::cast(this)->value();
10648 if (val->IsString()) {
10649 String* str = String::cast(val);
10650 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010651 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010652 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653 }
10654 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010655 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010656 }
10657 }
10658 ASSERT(!storage || storage->length() == counter);
10659 return counter;
10660}
10661
10662
10663int JSObject::GetEnumElementKeys(FixedArray* storage) {
10664 return GetLocalElementKeys(storage,
10665 static_cast<PropertyAttributes>(DONT_ENUM));
10666}
10667
10668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010669// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010670class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010671 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010672 explicit StringKey(String* string) :
10673 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010674 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010676 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010677 // We know that all entries in a hash table had their hash keys created.
10678 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010679 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010680 return false;
10681 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010682 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 }
10684
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010685 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010686
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010687 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010688
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010689 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690
10691 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010692 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010693};
10694
ager@chromium.org381abbb2009-02-25 13:23:22 +000010695
10696// StringSharedKeys are used as keys in the eval cache.
10697class StringSharedKey : public HashTableKey {
10698 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010699 StringSharedKey(String* source,
10700 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010701 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010702 int scope_position)
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010703 : source_(source),
10704 shared_(shared),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010705 language_mode_(language_mode),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010706 scope_position_(scope_position) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010707
10708 bool IsMatch(Object* other) {
10709 if (!other->IsFixedArray()) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010710 FixedArray* other_array = FixedArray::cast(other);
10711 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
ager@chromium.org381abbb2009-02-25 13:23:22 +000010712 if (shared != shared_) return false;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010713 int language_unchecked = Smi::cast(other_array->get(2))->value();
10714 ASSERT(language_unchecked == CLASSIC_MODE ||
10715 language_unchecked == STRICT_MODE ||
10716 language_unchecked == EXTENDED_MODE);
10717 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
10718 if (language_mode != language_mode_) return false;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010719 int scope_position = Smi::cast(other_array->get(3))->value();
10720 if (scope_position != scope_position_) return false;
10721 String* source = String::cast(other_array->get(1));
ager@chromium.org381abbb2009-02-25 13:23:22 +000010722 return source->Equals(source_);
10723 }
10724
ager@chromium.org381abbb2009-02-25 13:23:22 +000010725 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010726 SharedFunctionInfo* shared,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010727 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010728 int scope_position) {
ager@chromium.org381abbb2009-02-25 13:23:22 +000010729 uint32_t hash = source->Hash();
10730 if (shared->HasSourceCode()) {
10731 // Instead of using the SharedFunctionInfo pointer in the hash
10732 // code computation, we use a combination of the hash of the
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010733 // script source code and the start position of the calling scope.
10734 // We do this to ensure that the cache entries can survive garbage
ager@chromium.org381abbb2009-02-25 13:23:22 +000010735 // collection.
10736 Script* script = Script::cast(shared->script());
10737 hash ^= String::cast(script->source())->Hash();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010738 if (language_mode == STRICT_MODE) hash ^= 0x8000;
10739 if (language_mode == EXTENDED_MODE) hash ^= 0x0080;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010740 hash += scope_position;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010741 }
10742 return hash;
10743 }
10744
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010745 uint32_t Hash() {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010746 return StringSharedHashHelper(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010747 source_, shared_, language_mode_, scope_position_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010748 }
10749
10750 uint32_t HashForObject(Object* obj) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010751 FixedArray* other_array = FixedArray::cast(obj);
10752 SharedFunctionInfo* shared = SharedFunctionInfo::cast(other_array->get(0));
10753 String* source = String::cast(other_array->get(1));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010754 int language_unchecked = Smi::cast(other_array->get(2))->value();
10755 ASSERT(language_unchecked == CLASSIC_MODE ||
10756 language_unchecked == STRICT_MODE ||
10757 language_unchecked == EXTENDED_MODE);
10758 LanguageMode language_mode = static_cast<LanguageMode>(language_unchecked);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010759 int scope_position = Smi::cast(other_array->get(3))->value();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010760 return StringSharedHashHelper(
10761 source, shared, language_mode, scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010762 }
10763
lrn@chromium.org303ada72010-10-27 09:33:13 +000010764 MUST_USE_RESULT MaybeObject* AsObject() {
10765 Object* obj;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010766 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010767 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10768 }
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010769 FixedArray* other_array = FixedArray::cast(obj);
10770 other_array->set(0, shared_);
10771 other_array->set(1, source_);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010772 other_array->set(2, Smi::FromInt(language_mode_));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010773 other_array->set(3, Smi::FromInt(scope_position_));
10774 return other_array;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010775 }
10776
ager@chromium.org381abbb2009-02-25 13:23:22 +000010777 private:
10778 String* source_;
10779 SharedFunctionInfo* shared_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010780 LanguageMode language_mode_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000010781 int scope_position_;
ager@chromium.org381abbb2009-02-25 13:23:22 +000010782};
10783
10784
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010785// RegExpKey carries the source and flags of a regular expression as key.
10786class RegExpKey : public HashTableKey {
10787 public:
10788 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010789 : string_(string),
10790 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010791
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010792 // Rather than storing the key in the hash table, a pointer to the
10793 // stored value is stored where the key should be. IsMatch then
10794 // compares the search key to the found object, rather than comparing
10795 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010796 bool IsMatch(Object* obj) {
10797 FixedArray* val = FixedArray::cast(obj);
10798 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
10799 && (flags_ == val->get(JSRegExp::kFlagsIndex));
10800 }
10801
10802 uint32_t Hash() { return RegExpHash(string_, flags_); }
10803
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010804 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010805 // Plain hash maps, which is where regexp keys are used, don't
10806 // use this function.
10807 UNREACHABLE();
10808 return NULL;
10809 }
10810
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010811 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010812 FixedArray* val = FixedArray::cast(obj);
10813 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
10814 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
10815 }
10816
10817 static uint32_t RegExpHash(String* string, Smi* flags) {
10818 return string->Hash() + flags->value();
10819 }
10820
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010821 String* string_;
10822 Smi* flags_;
10823};
10824
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010825// Utf8SymbolKey carries a vector of chars as key.
10826class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010828 explicit Utf8SymbolKey(Vector<const char> string, uint32_t seed)
10829 : string_(string), hash_field_(0), seed_(seed) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010830
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010831 bool IsMatch(Object* string) {
10832 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010833 }
10834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010835 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010836 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837 unibrow::Utf8InputBuffer<> buffer(string_.start(),
10838 static_cast<unsigned>(string_.length()));
10839 chars_ = buffer.Length();
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010840 hash_field_ = String::ComputeHashField(&buffer, chars_, seed_);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010841 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +000010842 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10843 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844 }
10845
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010846 uint32_t HashForObject(Object* other) {
10847 return String::cast(other)->Hash();
10848 }
10849
lrn@chromium.org303ada72010-10-27 09:33:13 +000010850 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010851 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010852 return Isolate::Current()->heap()->AllocateSymbol(
10853 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 }
10855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010856 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000010857 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010858 int chars_; // Caches the number of characters when computing the hash code.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010859 uint32_t seed_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860};
10861
10862
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010863template <typename Char>
10864class SequentialSymbolKey : public HashTableKey {
10865 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010866 explicit SequentialSymbolKey(Vector<const Char> string, uint32_t seed)
10867 : string_(string), hash_field_(0), seed_(seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010868
10869 uint32_t Hash() {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010870 StringHasher hasher(string_.length(), seed_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010871
10872 // Very long strings have a trivial hash that doesn't inspect the
10873 // string contents.
10874 if (hasher.has_trivial_hash()) {
10875 hash_field_ = hasher.GetHashField();
10876 } else {
10877 int i = 0;
10878 // Do the iterative array index computation as long as there is a
10879 // chance this is an array index.
10880 while (i < string_.length() && hasher.is_array_index()) {
10881 hasher.AddCharacter(static_cast<uc32>(string_[i]));
10882 i++;
10883 }
10884
10885 // Process the remaining characters without updating the array
10886 // index.
10887 while (i < string_.length()) {
10888 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
10889 i++;
10890 }
10891 hash_field_ = hasher.GetHashField();
10892 }
10893
10894 uint32_t result = hash_field_ >> String::kHashShift;
10895 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10896 return result;
10897 }
10898
10899
10900 uint32_t HashForObject(Object* other) {
10901 return String::cast(other)->Hash();
10902 }
10903
10904 Vector<const Char> string_;
10905 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010906 uint32_t seed_;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010907};
10908
10909
10910
10911class AsciiSymbolKey : public SequentialSymbolKey<char> {
10912 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010913 AsciiSymbolKey(Vector<const char> str, uint32_t seed)
10914 : SequentialSymbolKey<char>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010915
10916 bool IsMatch(Object* string) {
10917 return String::cast(string)->IsAsciiEqualTo(string_);
10918 }
10919
10920 MaybeObject* AsObject() {
10921 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010923 }
10924};
10925
10926
danno@chromium.org40cb8782011-05-25 07:58:50 +000010927class SubStringAsciiSymbolKey : public HashTableKey {
10928 public:
10929 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
10930 int from,
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010931 int length,
10932 uint32_t seed)
10933 : string_(string), from_(from), length_(length), seed_(seed) { }
danno@chromium.org40cb8782011-05-25 07:58:50 +000010934
10935 uint32_t Hash() {
10936 ASSERT(length_ >= 0);
10937 ASSERT(from_ + length_ <= string_->length());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010938 StringHasher hasher(length_, string_->GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000010939
10940 // Very long strings have a trivial hash that doesn't inspect the
10941 // string contents.
10942 if (hasher.has_trivial_hash()) {
10943 hash_field_ = hasher.GetHashField();
10944 } else {
10945 int i = 0;
10946 // Do the iterative array index computation as long as there is a
10947 // chance this is an array index.
10948 while (i < length_ && hasher.is_array_index()) {
10949 hasher.AddCharacter(static_cast<uc32>(
10950 string_->SeqAsciiStringGet(i + from_)));
10951 i++;
10952 }
10953
10954 // Process the remaining characters without updating the array
10955 // index.
10956 while (i < length_) {
10957 hasher.AddCharacterNoIndex(static_cast<uc32>(
10958 string_->SeqAsciiStringGet(i + from_)));
10959 i++;
10960 }
10961 hash_field_ = hasher.GetHashField();
10962 }
10963
10964 uint32_t result = hash_field_ >> String::kHashShift;
10965 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10966 return result;
10967 }
10968
10969
10970 uint32_t HashForObject(Object* other) {
10971 return String::cast(other)->Hash();
10972 }
10973
10974 bool IsMatch(Object* string) {
10975 Vector<const char> chars(string_->GetChars() + from_, length_);
10976 return String::cast(string)->IsAsciiEqualTo(chars);
10977 }
10978
10979 MaybeObject* AsObject() {
10980 if (hash_field_ == 0) Hash();
10981 Vector<const char> chars(string_->GetChars() + from_, length_);
10982 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10983 }
10984
10985 private:
10986 Handle<SeqAsciiString> string_;
10987 int from_;
10988 int length_;
10989 uint32_t hash_field_;
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010990 uint32_t seed_;
danno@chromium.org40cb8782011-05-25 07:58:50 +000010991};
10992
10993
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010994class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10995 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000010996 explicit TwoByteSymbolKey(Vector<const uc16> str, uint32_t seed)
10997 : SequentialSymbolKey<uc16>(str, seed) { }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010998
10999 bool IsMatch(Object* string) {
11000 return String::cast(string)->IsTwoByteEqualTo(string_);
11001 }
11002
11003 MaybeObject* AsObject() {
11004 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011005 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011006 }
11007};
11008
11009
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011010// SymbolKey carries a string/symbol object as key.
11011class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011012 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 explicit SymbolKey(String* string)
11014 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011015
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011016 bool IsMatch(Object* string) {
11017 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011018 }
11019
11020 uint32_t Hash() { return string_->Hash(); }
11021
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011022 uint32_t HashForObject(Object* other) {
11023 return String::cast(other)->Hash();
11024 }
11025
lrn@chromium.org303ada72010-10-27 09:33:13 +000011026 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000011027 // Attempt to flatten the string, so that symbols will most often
11028 // be flat strings.
11029 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011030 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011031 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011032 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011033 if (map != NULL) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +000011034 string_->set_map_no_write_barrier(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011035 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011036 return string_;
11037 }
11038 // Otherwise allocate a new symbol.
11039 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011040 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011041 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011042 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 }
11044
11045 static uint32_t StringHash(Object* obj) {
11046 return String::cast(obj)->Hash();
11047 }
11048
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011049 String* string_;
11050};
11051
11052
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011053template<typename Shape, typename Key>
11054void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011055 IteratePointers(v, 0, kElementsStartOffset);
11056}
11057
11058
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011059template<typename Shape, typename Key>
11060void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061 IteratePointers(v,
11062 kElementsStartOffset,
11063 kHeaderSize + length() * kPointerSize);
11064}
11065
11066
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011067template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000011068MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
11069 PretenureFlag pretenure) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +000011070 int capacity = ComputeCapacity(at_least_space_for);
11071 if (capacity > HashTable::kMaxCapacity) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011072 return Failure::OutOfMemoryException();
11073 }
11074
lrn@chromium.org303ada72010-10-27 09:33:13 +000011075 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011076 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
11077 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011078 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011080 HashTable::cast(obj)->SetNumberOfElements(0);
11081 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
11082 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011083 return obj;
11084}
11085
11086
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011087// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011088int StringDictionary::FindEntry(String* key) {
11089 if (!key->IsSymbol()) {
11090 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
11091 }
11092
11093 // Optimized for symbol key. Knowledge of the key type allows:
11094 // 1. Move the check if the key is a symbol out of the loop.
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011095 // 2. Avoid comparing hash codes in symbol to symbol comparison.
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011096 // 3. Detect a case when a dictionary key is not a symbol but the key is.
11097 // In case of positive result the dictionary key may be replaced by
11098 // the symbol with minimal performance penalty. It gives a chance to
11099 // perform further lookups in code stubs (and significant performance boost
11100 // a certain style of code).
11101
11102 // EnsureCapacity will guarantee the hash table is never full.
11103 uint32_t capacity = Capacity();
11104 uint32_t entry = FirstProbe(key->Hash(), capacity);
11105 uint32_t count = 1;
11106
11107 while (true) {
11108 int index = EntryToIndex(entry);
11109 Object* element = get(index);
11110 if (element->IsUndefined()) break; // Empty entry.
11111 if (key == element) return entry;
11112 if (!element->IsSymbol() &&
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011113 !element->IsTheHole() &&
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011114 String::cast(element)->Equals(key)) {
11115 // Replace a non-symbol key by the equivalent symbol for faster further
11116 // lookups.
11117 set(index, key);
11118 return entry;
11119 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011120 ASSERT(element->IsTheHole() || !String::cast(element)->Equals(key));
ricow@chromium.org4980dff2010-07-19 08:33:45 +000011121 entry = NextProbe(entry, count++, capacity);
11122 }
11123 return kNotFound;
11124}
11125
11126
rossberg@chromium.org994edf62012-02-06 10:12:55 +000011127bool StringDictionary::ContainsTransition(int entry) {
11128 switch (DetailsAt(entry).type()) {
11129 case MAP_TRANSITION:
11130 case CONSTANT_TRANSITION:
11131 case ELEMENTS_TRANSITION:
11132 return true;
11133 case CALLBACKS: {
11134 Object* value = ValueAt(entry);
11135 if (!value->IsAccessorPair()) return false;
11136 AccessorPair* accessors = AccessorPair::cast(value);
11137 return accessors->getter()->IsMap() || accessors->setter()->IsMap();
11138 }
11139 case NORMAL:
11140 case FIELD:
11141 case CONSTANT_FUNCTION:
11142 case HANDLER:
11143 case INTERCEPTOR:
11144 case NULL_DESCRIPTOR:
11145 return false;
11146 }
11147 UNREACHABLE(); // Keep the compiler happy.
11148 return false;
11149}
11150
11151
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011152template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000011153MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
11154 ASSERT(NumberOfElements() < new_table->Capacity());
11155
11156 AssertNoAllocation no_gc;
11157 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
11158
11159 // Copy prefix to new array.
11160 for (int i = kPrefixStartIndex;
11161 i < kPrefixStartIndex + Shape::kPrefixSize;
11162 i++) {
11163 new_table->set(i, get(i), mode);
11164 }
11165
11166 // Rehash the elements.
11167 int capacity = Capacity();
11168 for (int i = 0; i < capacity; i++) {
11169 uint32_t from_index = EntryToIndex(i);
11170 Object* k = get(from_index);
11171 if (IsKey(k)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011172 uint32_t hash = HashTable<Shape, Key>::HashForObject(key, k);
ager@chromium.org04921a82011-06-27 13:21:41 +000011173 uint32_t insertion_index =
11174 EntryToIndex(new_table->FindInsertionEntry(hash));
11175 for (int j = 0; j < Shape::kEntrySize; j++) {
11176 new_table->set(insertion_index + j, get(from_index + j), mode);
11177 }
11178 }
11179 }
11180 new_table->SetNumberOfElements(NumberOfElements());
11181 new_table->SetNumberOfDeletedElements(0);
11182 return new_table;
11183}
11184
11185
11186template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000011187MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011188 int capacity = Capacity();
11189 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000011190 int nod = NumberOfDeletedElements();
11191 // Return if:
11192 // 50% is still free after adding n elements and
11193 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011194 if (nod <= (capacity - nof) >> 1) {
11195 int needed_free = nof >> 1;
11196 if (nof + needed_free <= capacity) return this;
11197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011198
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011199 const int kMinCapacityForPretenure = 256;
11200 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011201 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011202 Object* obj;
11203 { MaybeObject* maybe_obj =
11204 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
11205 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11206 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011207
ager@chromium.org04921a82011-06-27 13:21:41 +000011208 return Rehash(HashTable::cast(obj), key);
11209}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011210
ager@chromium.org04921a82011-06-27 13:21:41 +000011211
11212template<typename Shape, typename Key>
11213MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
11214 int capacity = Capacity();
11215 int nof = NumberOfElements();
11216
11217 // Shrink to fit the number of elements if only a quarter of the
11218 // capacity is filled with elements.
11219 if (nof > (capacity >> 2)) return this;
11220 // Allocate a new dictionary with room for at least the current
11221 // number of elements. The allocation method will make sure that
11222 // there is extra room in the dictionary for additions. Don't go
11223 // lower than room for 16 elements.
11224 int at_least_room_for = nof;
11225 if (at_least_room_for < 16) return this;
11226
11227 const int kMinCapacityForPretenure = 256;
11228 bool pretenure =
11229 (at_least_room_for > kMinCapacityForPretenure) &&
11230 !GetHeap()->InNewSpace(this);
11231 Object* obj;
11232 { MaybeObject* maybe_obj =
11233 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
11234 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011235 }
ager@chromium.org04921a82011-06-27 13:21:41 +000011236
11237 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011238}
11239
11240
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011241template<typename Shape, typename Key>
11242uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011244 uint32_t entry = FirstProbe(hash, capacity);
11245 uint32_t count = 1;
11246 // EnsureCapacity will guarantee the hash table is never full.
11247 while (true) {
11248 Object* element = KeyAt(entry);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011249 if (element->IsUndefined() || element->IsTheHole()) break;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011250 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011252 return entry;
11253}
11254
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011255// Force instantiation of template instances class.
11256// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011257
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011258template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011259
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011260template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011261
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011262template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011263
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011264template class HashTable<ObjectHashTableShape<1>, Object*>;
11265
11266template class HashTable<ObjectHashTableShape<2>, Object*>;
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011267
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011268template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011270template class Dictionary<SeededNumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011271
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011272template class Dictionary<UnseededNumberDictionaryShape, uint32_t>;
11273
11274template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11275 Allocate(int at_least_space_for);
11276
11277template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11278 Allocate(int at_least_space_for);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011279
lrn@chromium.org303ada72010-10-27 09:33:13 +000011280template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011281 int);
11282
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011283template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011284 uint32_t, Object*);
11285
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011286template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11287 AtPut(uint32_t, Object*);
11288
11289template Object* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11290 SlowReverseLookup(Object* value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011291
11292template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
11293 Object*);
11294
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011295template void Dictionary<SeededNumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011296 FixedArray*,
11297 PropertyAttributes,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011298 Dictionary<SeededNumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011299
11300template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
11301 int, JSObject::DeleteMode);
11302
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011303template Object* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11304 DeleteProperty(int, JSObject::DeleteMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011305
ager@chromium.org04921a82011-06-27 13:21:41 +000011306template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
11307 String*);
11308
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011309template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Shrink(
ager@chromium.org04921a82011-06-27 13:21:41 +000011310 uint32_t);
11311
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011312template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011313 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011314 int,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011315 Dictionary<StringDictionaryShape, String*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011316
11317template int
11318Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
11319 PropertyAttributes);
11320
lrn@chromium.org303ada72010-10-27 09:33:13 +000011321template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011322 String*, Object*, PropertyDetails);
11323
lrn@chromium.org303ada72010-10-27 09:33:13 +000011324template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011325Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
11326
11327template int
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011328Dictionary<SeededNumberDictionaryShape, uint32_t>::
11329 NumberOfElementsFilterAttributes(PropertyAttributes);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011330
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011331template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011332 uint32_t, Object*, PropertyDetails);
11333
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011334template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::Add(
11335 uint32_t, Object*, PropertyDetails);
11336
11337template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11338 EnsureCapacity(int, uint32_t);
11339
11340template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
lrn@chromium.org303ada72010-10-27 09:33:13 +000011341 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011342
lrn@chromium.org303ada72010-10-27 09:33:13 +000011343template MaybeObject* Dictionary<StringDictionaryShape, String*>::
11344 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011345
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011346template MaybeObject* Dictionary<SeededNumberDictionaryShape, uint32_t>::
11347 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
11348
11349template MaybeObject* Dictionary<UnseededNumberDictionaryShape, uint32_t>::
11350 AddEntry(uint32_t, Object*, PropertyDetails, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011351
lrn@chromium.org303ada72010-10-27 09:33:13 +000011352template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011353 String*, Object*, PropertyDetails, uint32_t);
11354
11355template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011356int Dictionary<SeededNumberDictionaryShape, uint32_t>::NumberOfEnumElements();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011357
11358template
11359int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011360
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011361template
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011362int HashTable<SeededNumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000011363
11364
ager@chromium.org5ec48922009-05-05 07:25:34 +000011365// Collates undefined and unexisting elements below limit from position
11366// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011367MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011368 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011369 // Must stay in dictionary mode, either because of requires_slow_elements,
11370 // or because we are not going to sort (and therefore compact) all of the
11371 // elements.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011372 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011373 HeapNumber* result_double = NULL;
11374 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11375 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011376 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011377 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011378 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11379 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011380 result_double = HeapNumber::cast(new_double);
11381 }
11382
lrn@chromium.org303ada72010-10-27 09:33:13 +000011383 Object* obj;
11384 { MaybeObject* maybe_obj =
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011385 SeededNumberDictionary::Allocate(dict->NumberOfElements());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011386 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11387 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011388 SeededNumberDictionary* new_dict = SeededNumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011389
11390 AssertNoAllocation no_alloc;
11391
ager@chromium.org5ec48922009-05-05 07:25:34 +000011392 uint32_t pos = 0;
11393 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011394 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011395 for (int i = 0; i < capacity; i++) {
11396 Object* k = dict->KeyAt(i);
11397 if (dict->IsKey(k)) {
11398 ASSERT(k->IsNumber());
11399 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
11400 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
11401 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
11402 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011403 PropertyDetails details = dict->DetailsAt(i);
11404 if (details.type() == CALLBACKS) {
11405 // Bail out and do the sorting of undefineds and array holes in JS.
11406 return Smi::FromInt(-1);
11407 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011408 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011409 // In the following we assert that adding the entry to the new dictionary
11410 // does not cause GC. This is the case because we made sure to allocate
11411 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000011412 if (key < limit) {
11413 if (value->IsUndefined()) {
11414 undefs++;
11415 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011416 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11417 // Adding an entry with the key beyond smi-range requires
11418 // allocation. Bailout.
11419 return Smi::FromInt(-1);
11420 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011421 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011422 pos++;
11423 }
11424 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011425 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
11426 // Adding an entry with the key beyond smi-range requires
11427 // allocation. Bailout.
11428 return Smi::FromInt(-1);
11429 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000011430 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011431 }
11432 }
11433 }
11434
11435 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011436 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011437 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011438 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011439 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
11440 // Adding an entry with the key beyond smi-range requires
11441 // allocation. Bailout.
11442 return Smi::FromInt(-1);
11443 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011444 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000011445 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011446 pos++;
11447 undefs--;
11448 }
11449
11450 set_elements(new_dict);
11451
11452 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11453 return Smi::FromInt(static_cast<int>(result));
11454 }
11455
11456 ASSERT_NE(NULL, result_double);
11457 result_double->set_value(static_cast<double>(result));
11458 return result_double;
11459}
11460
11461
11462// Collects all defined (non-hole) and non-undefined (array) elements at
11463// the start of the elements array.
11464// If the object is in dictionary mode, it is converted to fast elements
11465// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011466MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011467 Heap* heap = GetHeap();
11468
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011469 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000011470 // Convert to fast elements containing only the existing properties.
11471 // Ordering is irrelevant, since we are going to sort anyway.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011472 SeededNumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000011473 if (IsJSArray() || dict->requires_slow_elements() ||
11474 dict->max_number_key() >= limit) {
11475 return PrepareSlowElementsForSort(limit);
11476 }
11477 // Convert to fast elements.
11478
lrn@chromium.org303ada72010-10-27 09:33:13 +000011479 Object* obj;
danno@chromium.orgfa458e42012-02-01 10:48:36 +000011480 { MaybeObject* maybe_obj = GetElementsTransitionMap(GetIsolate(),
11481 FAST_ELEMENTS);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011482 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11483 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011484 Map* new_map = Map::cast(obj);
11485
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011486 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000011487 Object* new_array;
11488 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011489 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011490 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
11491 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011492 FixedArray* fast_elements = FixedArray::cast(new_array);
11493 dict->CopyValuesTo(fast_elements);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000011494
11495 set_map(new_map);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011496 set_elements(fast_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011497 } else if (HasExternalArrayElements()) {
11498 // External arrays cannot have holes or undefined elements.
11499 return Smi::FromInt(ExternalArray::cast(elements())->length());
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011500 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011501 Object* obj;
11502 { MaybeObject* maybe_obj = EnsureWritableFastElements();
11503 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11504 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011505 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011506 ASSERT(HasFastTypeElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011507
11508 // Collect holes at the end, undefined before that and the rest at the
11509 // start, and return the number of non-hole, non-undefined values.
11510
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011511 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
11512 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000011513 if (limit > elements_length) {
11514 limit = elements_length ;
11515 }
11516 if (limit == 0) {
11517 return Smi::FromInt(0);
11518 }
11519
11520 HeapNumber* result_double = NULL;
11521 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
11522 // Pessimistically allocate space for return value before
11523 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011524 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011525 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011526 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
11527 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011528 result_double = HeapNumber::cast(new_double);
11529 }
11530
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011531 uint32_t result = 0;
11532 if (elements_base->map() == heap->fixed_double_array_map()) {
11533 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
11534 // Split elements into defined and the_hole, in that order.
11535 unsigned int holes = limit;
11536 // Assume most arrays contain no holes and undefined values, so minimize the
11537 // number of stores of non-undefined, non-the-hole values.
11538 for (unsigned int i = 0; i < holes; i++) {
11539 if (elements->is_the_hole(i)) {
11540 holes--;
11541 } else {
11542 continue;
11543 }
11544 // Position i needs to be filled.
11545 while (holes > i) {
11546 if (elements->is_the_hole(holes)) {
11547 holes--;
11548 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011549 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011550 break;
11551 }
11552 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011553 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011554 result = holes;
11555 while (holes < limit) {
11556 elements->set_the_hole(holes);
11557 holes++;
11558 }
11559 } else {
11560 FixedArray* elements = FixedArray::cast(elements_base);
11561 AssertNoAllocation no_alloc;
11562
11563 // Split elements into defined, undefined and the_hole, in that order. Only
11564 // count locations for undefined and the hole, and fill them afterwards.
11565 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
11566 unsigned int undefs = limit;
11567 unsigned int holes = limit;
11568 // Assume most arrays contain no holes and undefined values, so minimize the
11569 // number of stores of non-undefined, non-the-hole values.
11570 for (unsigned int i = 0; i < undefs; i++) {
11571 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000011572 if (current->IsTheHole()) {
11573 holes--;
11574 undefs--;
11575 } else if (current->IsUndefined()) {
11576 undefs--;
11577 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011578 continue;
11579 }
11580 // Position i needs to be filled.
11581 while (undefs > i) {
11582 current = elements->get(undefs);
11583 if (current->IsTheHole()) {
11584 holes--;
11585 undefs--;
11586 } else if (current->IsUndefined()) {
11587 undefs--;
11588 } else {
11589 elements->set(i, current, write_barrier);
11590 break;
11591 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011592 }
11593 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000011594 result = undefs;
11595 while (undefs < holes) {
11596 elements->set_undefined(undefs);
11597 undefs++;
11598 }
11599 while (holes < limit) {
11600 elements->set_the_hole(holes);
11601 holes++;
11602 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000011603 }
11604
11605 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
11606 return Smi::FromInt(static_cast<int>(result));
11607 }
11608 ASSERT_NE(NULL, result_double);
11609 result_double->set_value(static_cast<double>(result));
11610 return result_double;
11611}
11612
11613
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011614Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000011615 uint8_t clamped_value = 0;
11616 if (index < static_cast<uint32_t>(length())) {
11617 if (value->IsSmi()) {
11618 int int_value = Smi::cast(value)->value();
11619 if (int_value < 0) {
11620 clamped_value = 0;
11621 } else if (int_value > 255) {
11622 clamped_value = 255;
11623 } else {
11624 clamped_value = static_cast<uint8_t>(int_value);
11625 }
11626 } else if (value->IsHeapNumber()) {
11627 double double_value = HeapNumber::cast(value)->value();
11628 if (!(double_value > 0)) {
11629 // NaN and less than zero clamp to zero.
11630 clamped_value = 0;
11631 } else if (double_value > 255) {
11632 // Greater than 255 clamp to 255.
11633 clamped_value = 255;
11634 } else {
11635 // Other doubles are rounded to the nearest integer.
11636 clamped_value = static_cast<uint8_t>(double_value + 0.5);
11637 }
11638 } else {
11639 // Clamp undefined to zero (default). All other types have been
11640 // converted to a number type further up in the call chain.
11641 ASSERT(value->IsUndefined());
11642 }
11643 set(index, clamped_value);
11644 }
11645 return Smi::FromInt(clamped_value);
11646}
11647
11648
ager@chromium.org3811b432009-10-28 14:53:37 +000011649template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650static MaybeObject* ExternalArrayIntSetter(Heap* heap,
11651 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000011652 uint32_t index,
11653 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011654 ValueType cast_value = 0;
11655 if (index < static_cast<uint32_t>(receiver->length())) {
11656 if (value->IsSmi()) {
11657 int int_value = Smi::cast(value)->value();
11658 cast_value = static_cast<ValueType>(int_value);
11659 } else if (value->IsHeapNumber()) {
11660 double double_value = HeapNumber::cast(value)->value();
11661 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
11662 } else {
11663 // Clamp undefined to zero (default). All other types have been
11664 // converted to a number type further up in the call chain.
11665 ASSERT(value->IsUndefined());
11666 }
11667 receiver->set(index, cast_value);
11668 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011670}
11671
11672
lrn@chromium.org303ada72010-10-27 09:33:13 +000011673MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011674 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011675 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011676}
11677
11678
lrn@chromium.org303ada72010-10-27 09:33:13 +000011679MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
11680 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011681 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011682 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011683}
11684
11685
lrn@chromium.org303ada72010-10-27 09:33:13 +000011686MaybeObject* ExternalShortArray::SetValue(uint32_t index,
11687 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011688 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011690}
11691
11692
lrn@chromium.org303ada72010-10-27 09:33:13 +000011693MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
11694 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011695 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011696 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011697}
11698
11699
lrn@chromium.org303ada72010-10-27 09:33:13 +000011700MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011701 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011702 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011703}
11704
11705
lrn@chromium.org303ada72010-10-27 09:33:13 +000011706MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011707 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011709 if (index < static_cast<uint32_t>(length())) {
11710 if (value->IsSmi()) {
11711 int int_value = Smi::cast(value)->value();
11712 cast_value = static_cast<uint32_t>(int_value);
11713 } else if (value->IsHeapNumber()) {
11714 double double_value = HeapNumber::cast(value)->value();
11715 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
11716 } else {
11717 // Clamp undefined to zero (default). All other types have been
11718 // converted to a number type further up in the call chain.
11719 ASSERT(value->IsUndefined());
11720 }
11721 set(index, cast_value);
11722 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011723 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011724}
11725
11726
lrn@chromium.org303ada72010-10-27 09:33:13 +000011727MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000011728 float cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000011730 if (index < static_cast<uint32_t>(length())) {
11731 if (value->IsSmi()) {
11732 int int_value = Smi::cast(value)->value();
11733 cast_value = static_cast<float>(int_value);
11734 } else if (value->IsHeapNumber()) {
11735 double double_value = HeapNumber::cast(value)->value();
11736 cast_value = static_cast<float>(double_value);
11737 } else {
11738 // Clamp undefined to zero (default). All other types have been
11739 // converted to a number type further up in the call chain.
11740 ASSERT(value->IsUndefined());
11741 }
11742 set(index, cast_value);
11743 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000011745}
11746
11747
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000011748MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
11749 double double_value = 0;
11750 Heap* heap = GetHeap();
11751 if (index < static_cast<uint32_t>(length())) {
11752 if (value->IsSmi()) {
11753 int int_value = Smi::cast(value)->value();
11754 double_value = static_cast<double>(int_value);
11755 } else if (value->IsHeapNumber()) {
11756 double_value = HeapNumber::cast(value)->value();
11757 } else {
11758 // Clamp undefined to zero (default). All other types have been
11759 // converted to a number type further up in the call chain.
11760 ASSERT(value->IsUndefined());
11761 }
11762 set(index, double_value);
11763 }
11764 return heap->AllocateHeapNumber(double_value);
11765}
11766
11767
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011768JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011769 ASSERT(!HasFastProperties());
11770 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011771 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011772}
11773
11774
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011775Handle<JSGlobalPropertyCell> GlobalObject::EnsurePropertyCell(
11776 Handle<GlobalObject> global,
11777 Handle<String> name) {
11778 Isolate* isolate = global->GetIsolate();
11779 CALL_HEAP_FUNCTION(isolate,
11780 global->EnsurePropertyCell(*name),
11781 JSGlobalPropertyCell);
11782}
11783
11784
lrn@chromium.org303ada72010-10-27 09:33:13 +000011785MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011786 ASSERT(!HasFastProperties());
11787 int entry = property_dictionary()->FindEntry(name);
11788 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011789 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000011790 Object* cell;
11791 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011792 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011793 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
11794 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011795 PropertyDetails details(NONE, NORMAL);
11796 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000011797 Object* dictionary;
11798 { MaybeObject* maybe_dictionary =
11799 property_dictionary()->Add(name, cell, details);
11800 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
11801 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011802 set_properties(StringDictionary::cast(dictionary));
11803 return cell;
11804 } else {
11805 Object* value = property_dictionary()->ValueAt(entry);
11806 ASSERT(value->IsJSGlobalPropertyCell());
11807 return value;
11808 }
11809}
11810
11811
lrn@chromium.org303ada72010-10-27 09:33:13 +000011812MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011813 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814 return LookupKey(&key, s);
11815}
11816
11817
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011818// This class is used for looking up two character strings in the symbol table.
11819// If we don't have a hit we don't want to waste much time so we unroll the
11820// string hash calculation loop here for speed. Doesn't work if the two
11821// characters form a decimal integer, since such strings have a different hash
11822// algorithm.
11823class TwoCharHashTableKey : public HashTableKey {
11824 public:
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011825 TwoCharHashTableKey(uint32_t c1, uint32_t c2, uint32_t seed)
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011826 : c1_(c1), c2_(c2) {
11827 // Char 1.
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011828 uint32_t hash = seed;
11829 hash += c1;
11830 hash += hash << 10;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011831 hash ^= hash >> 6;
11832 // Char 2.
11833 hash += c2;
11834 hash += hash << 10;
11835 hash ^= hash >> 6;
11836 // GetHash.
11837 hash += hash << 3;
11838 hash ^= hash >> 11;
11839 hash += hash << 15;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011840 if ((hash & String::kHashBitMask) == 0) hash = String::kZeroHash;
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011841#ifdef DEBUG
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011842 StringHasher hasher(2, seed);
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011843 hasher.AddCharacter(c1);
11844 hasher.AddCharacter(c2);
11845 // If this assert fails then we failed to reproduce the two-character
11846 // version of the string hashing algorithm above. One reason could be
11847 // that we were passed two digits as characters, since the hash
11848 // algorithm is different in that case.
11849 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
11850#endif
11851 hash_ = hash;
11852 }
11853
11854 bool IsMatch(Object* o) {
11855 if (!o->IsString()) return false;
11856 String* other = String::cast(o);
11857 if (other->length() != 2) return false;
11858 if (other->Get(0) != c1_) return false;
11859 return other->Get(1) == c2_;
11860 }
11861
11862 uint32_t Hash() { return hash_; }
11863 uint32_t HashForObject(Object* key) {
11864 if (!key->IsString()) return 0;
11865 return String::cast(key)->Hash();
11866 }
11867
11868 Object* AsObject() {
11869 // The TwoCharHashTableKey is only used for looking in the symbol
11870 // table, not for adding to it.
11871 UNREACHABLE();
11872 return NULL;
11873 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000011874
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011875 private:
11876 uint32_t c1_;
11877 uint32_t c2_;
11878 uint32_t hash_;
11879};
11880
11881
ager@chromium.org7c537e22008-10-16 08:43:32 +000011882bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
11883 SymbolKey key(string);
11884 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011885 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011886 return false;
11887 } else {
11888 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +000011889 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +000011890 *symbol = result;
11891 return true;
11892 }
11893}
11894
11895
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011896bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
11897 uint32_t c2,
11898 String** symbol) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011899 TwoCharHashTableKey key(c1, c2, GetHeap()->HashSeed());
ager@chromium.org6141cbe2009-11-20 12:14:52 +000011900 int entry = FindEntry(&key);
11901 if (entry == kNotFound) {
11902 return false;
11903 } else {
11904 String* result = String::cast(KeyAt(entry));
11905 ASSERT(StringShape(result).IsSymbol());
11906 *symbol = result;
11907 return true;
11908 }
11909}
11910
11911
rossberg@chromium.orgfab14982012-01-05 15:02:15 +000011912MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str,
11913 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011914 Utf8SymbolKey key(str, GetHeap()->HashSeed());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915 return LookupKey(&key, s);
11916}
11917
11918
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011919MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
11920 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011921 AsciiSymbolKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011922 return LookupKey(&key, s);
11923}
11924
11925
danno@chromium.org40cb8782011-05-25 07:58:50 +000011926MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
11927 int from,
11928 int length,
11929 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011930 SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
danno@chromium.org40cb8782011-05-25 07:58:50 +000011931 return LookupKey(&key, s);
11932}
11933
11934
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011935MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
11936 Object** s) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000011937 TwoByteSymbolKey key(str, GetHeap()->HashSeed());
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000011938 return LookupKey(&key, s);
11939}
11940
lrn@chromium.org303ada72010-10-27 09:33:13 +000011941MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 int entry = FindEntry(key);
11943
11944 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011945 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946 *s = KeyAt(entry);
11947 return this;
11948 }
11949
11950 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011951 Object* obj;
11952 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11953 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011955
11956 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011957 Object* symbol;
11958 { MaybeObject* maybe_symbol = key->AsObject();
11959 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
11960 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011961
11962 // If the symbol table grew as part of EnsureCapacity, obj is not
11963 // the current symbol table and therefore we cannot use
11964 // SymbolTable::cast here.
11965 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
11966
11967 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011968 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 table->set(EntryToIndex(entry), symbol);
11970 table->ElementAdded();
11971 *s = symbol;
11972 return table;
11973}
11974
11975
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000011976Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011977 StringKey key(src);
11978 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011979 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011980 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000011981}
11982
11983
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011984Object* CompilationCacheTable::LookupEval(String* src,
11985 Context* context,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011986 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011987 int scope_position) {
11988 StringSharedKey key(src,
11989 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011990 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000011991 scope_position);
ager@chromium.org381abbb2009-02-25 13:23:22 +000011992 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011993 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000011994 return get(EntryToIndex(entry) + 1);
11995}
11996
11997
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011998Object* CompilationCacheTable::LookupRegExp(String* src,
11999 JSRegExp::Flags flags) {
12000 RegExpKey key(src, flags);
12001 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012002 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012003 return get(EntryToIndex(entry) + 1);
12004}
12005
12006
lrn@chromium.org303ada72010-10-27 09:33:13 +000012007MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000012008 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012009 Object* obj;
12010 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12011 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12012 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000012013
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000012014 CompilationCacheTable* cache =
12015 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012016 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000012017 cache->set(EntryToIndex(entry), src);
12018 cache->set(EntryToIndex(entry) + 1, value);
12019 cache->ElementAdded();
12020 return cache;
12021}
12022
12023
lrn@chromium.org303ada72010-10-27 09:33:13 +000012024MaybeObject* CompilationCacheTable::PutEval(String* src,
12025 Context* context,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012026 SharedFunctionInfo* value,
12027 int scope_position) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012028 StringSharedKey key(src,
12029 context->closure()->shared(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012030 value->language_mode(),
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012031 scope_position);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012032 Object* obj;
12033 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12034 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12035 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012036
12037 CompilationCacheTable* cache =
12038 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012039 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000012040
lrn@chromium.org303ada72010-10-27 09:33:13 +000012041 Object* k;
12042 { MaybeObject* maybe_k = key.AsObject();
12043 if (!maybe_k->ToObject(&k)) return maybe_k;
12044 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000012045
12046 cache->set(EntryToIndex(entry), k);
12047 cache->set(EntryToIndex(entry) + 1, value);
12048 cache->ElementAdded();
12049 return cache;
12050}
12051
12052
lrn@chromium.org303ada72010-10-27 09:33:13 +000012053MaybeObject* CompilationCacheTable::PutRegExp(String* src,
12054 JSRegExp::Flags flags,
12055 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012056 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012057 Object* obj;
12058 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12059 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12060 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012061
12062 CompilationCacheTable* cache =
12063 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012064 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000012065 // We store the value in the key slot, and compare the search key
12066 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012067 cache->set(EntryToIndex(entry), value);
12068 cache->set(EntryToIndex(entry) + 1, value);
12069 cache->ElementAdded();
12070 return cache;
12071}
12072
12073
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012074void CompilationCacheTable::Remove(Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012075 Object* the_hole_value = GetHeap()->the_hole_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012076 for (int entry = 0, size = Capacity(); entry < size; entry++) {
12077 int entry_index = EntryToIndex(entry);
12078 int value_index = entry_index + 1;
12079 if (get(value_index) == value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012080 NoWriteBarrierSet(this, entry_index, the_hole_value);
12081 NoWriteBarrierSet(this, value_index, the_hole_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012082 ElementRemoved();
12083 }
12084 }
12085 return;
12086}
12087
12088
ager@chromium.org236ad962008-09-25 09:45:57 +000012089// SymbolsKey used for HashTable where key is array of symbols.
12090class SymbolsKey : public HashTableKey {
12091 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012092 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000012093
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012094 bool IsMatch(Object* symbols) {
12095 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +000012096 int len = symbols_->length();
12097 if (o->length() != len) return false;
12098 for (int i = 0; i < len; i++) {
12099 if (o->get(i) != symbols_->get(i)) return false;
12100 }
12101 return true;
12102 }
12103
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012104 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000012105
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012106 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012107 FixedArray* symbols = FixedArray::cast(obj);
12108 int len = symbols->length();
12109 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000012110 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012111 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000012112 }
12113 return hash;
12114 }
12115
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012116 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000012117
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012118 private:
ager@chromium.org236ad962008-09-25 09:45:57 +000012119 FixedArray* symbols_;
12120};
12121
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012122
ager@chromium.org236ad962008-09-25 09:45:57 +000012123Object* MapCache::Lookup(FixedArray* array) {
12124 SymbolsKey key(array);
12125 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012126 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012127 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000012128}
12129
12130
lrn@chromium.org303ada72010-10-27 09:33:13 +000012131MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +000012132 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012133 Object* obj;
12134 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
12135 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12136 }
ager@chromium.org236ad962008-09-25 09:45:57 +000012137
12138 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012139 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000012140 cache->set(EntryToIndex(entry), array);
12141 cache->set(EntryToIndex(entry) + 1, value);
12142 cache->ElementAdded();
12143 return cache;
12144}
12145
12146
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012147template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012148MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
12149 Object* obj;
12150 { MaybeObject* maybe_obj =
12151 HashTable<Shape, Key>::Allocate(at_least_space_for);
12152 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000012154 // Initialize the next enumeration index.
12155 Dictionary<Shape, Key>::cast(obj)->
12156 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012157 return obj;
12158}
12159
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012160
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012161template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012162MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012163 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012164 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012165
12166 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012167 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012169 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12170 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012172 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012173 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175
12176 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012177 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012178 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012180 FixedArray* enumeration_order = FixedArray::cast(obj);
12181
12182 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012183 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012184 int pos = 0;
12185 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012186 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012187 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188 }
12189 }
12190
12191 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012192 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012193
12194 // Overwrite the enumeration_order with the enumeration indices.
12195 for (int i = 0; i < length; i++) {
12196 int index = Smi::cast(iteration_order->get(i))->value();
12197 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012198 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012199 }
12200
12201 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012202 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203 pos = 0;
12204 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012205 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012206 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
12207 PropertyDetails details = DetailsAt(i);
12208 PropertyDetails new_details =
12209 PropertyDetails(details.attributes(), details.type(), enum_index);
12210 DetailsAtPut(i, new_details);
12211 }
12212 }
12213
12214 // Set the next enumeration index.
12215 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
12216 return this;
12217}
12218
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012219template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012220MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012221 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012222 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012223 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
12224 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012225 Object* result;
12226 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12227 if (!maybe_result->ToObject(&result)) return maybe_result;
12228 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012229 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012230 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231}
12232
12233
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012234template<typename Shape, typename Key>
12235Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012236 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000012239 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012240 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012241 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000012242 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012243 SetEntry(entry, heap->the_hole_value(), heap->the_hole_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012244 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012245 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012246}
12247
12248
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012249template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000012250MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
12251 return HashTable<Shape, Key>::Shrink(key);
12252}
12253
12254
12255template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012256MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012257 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258
12259 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012260 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012261 ValueAtPut(entry, value);
12262 return this;
12263 }
12264
12265 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012266 Object* obj;
12267 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12268 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12269 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012270
lrn@chromium.org303ada72010-10-27 09:33:13 +000012271 Object* k;
12272 { MaybeObject* maybe_k = Shape::AsObject(key);
12273 if (!maybe_k->ToObject(&k)) return maybe_k;
12274 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012275 PropertyDetails details = PropertyDetails(NONE, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012276
12277 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12278 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012279}
12280
12281
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012282template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012283MaybeObject* Dictionary<Shape, Key>::Add(Key key,
12284 Object* value,
12285 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012286 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012287 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012288 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012289 Object* obj;
12290 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12291 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12292 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012293
12294 return Dictionary<Shape, Key>::cast(obj)->AddEntry(key, value, details,
12295 Dictionary<Shape, Key>::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012296}
12297
12298
12299// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012300template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000012301MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
12302 Object* value,
12303 PropertyDetails details,
12304 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012305 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012306 Object* k;
12307 { MaybeObject* maybe_k = Shape::AsObject(key);
12308 if (!maybe_k->ToObject(&k)) return maybe_k;
12309 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012310
12311 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012312 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012313 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012314 // Assign an enumeration index to the property and update
12315 // SetNextEnumerationIndex.
12316 int index = NextEnumerationIndex();
12317 details = PropertyDetails(details.attributes(), details.type(), index);
12318 SetNextEnumerationIndex(index + 1);
12319 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012320 SetEntry(entry, k, value, details);
12321 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
12322 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
12323 HashTable<Shape, Key>::ElementAdded();
12324 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012325}
12326
12327
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012328void SeededNumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012329 // If the dictionary requires slow elements an element has already
12330 // been added at a high index.
12331 if (requires_slow_elements()) return;
12332 // Check if this index is high enough that we should require slow
12333 // elements.
12334 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012335 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012336 return;
12337 }
12338 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000012339 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012340 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012341 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012342 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012343 }
12344}
12345
12346
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012347MaybeObject* SeededNumberDictionary::AddNumberEntry(uint32_t key,
12348 Object* value,
12349 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012350 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000012351 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012352 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012353}
12354
12355
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012356MaybeObject* UnseededNumberDictionary::AddNumberEntry(uint32_t key,
12357 Object* value) {
12358 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
12359 return Add(key, value, PropertyDetails(NONE, NORMAL));
12360}
12361
12362
12363MaybeObject* SeededNumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012364 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012365 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012366}
12367
12368
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012369MaybeObject* UnseededNumberDictionary::AtNumberPut(uint32_t key,
12370 Object* value) {
12371 return AtPut(key, value);
12372}
12373
12374
12375Handle<SeededNumberDictionary> SeededNumberDictionary::Set(
12376 Handle<SeededNumberDictionary> dictionary,
12377 uint32_t index,
12378 Handle<Object> value,
12379 PropertyDetails details) {
12380 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12381 dictionary->Set(index, *value, details),
12382 SeededNumberDictionary);
12383}
12384
12385
12386Handle<UnseededNumberDictionary> UnseededNumberDictionary::Set(
12387 Handle<UnseededNumberDictionary> dictionary,
12388 uint32_t index,
12389 Handle<Object> value) {
12390 CALL_HEAP_FUNCTION(dictionary->GetIsolate(),
12391 dictionary->Set(index, *value),
12392 UnseededNumberDictionary);
12393}
12394
12395
12396MaybeObject* SeededNumberDictionary::Set(uint32_t key,
12397 Object* value,
12398 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012399 int entry = FindEntry(key);
12400 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012401 // Preserve enumeration index.
12402 details = PropertyDetails(details.attributes(),
12403 details.type(),
12404 DetailsAt(entry).index());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012405 MaybeObject* maybe_object_key = SeededNumberDictionaryShape::AsObject(key);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012406 Object* object_key;
12407 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000012408 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012409 return this;
12410}
12411
12412
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000012413MaybeObject* UnseededNumberDictionary::Set(uint32_t key,
12414 Object* value) {
12415 int entry = FindEntry(key);
12416 if (entry == kNotFound) return AddNumberEntry(key, value);
12417 MaybeObject* maybe_object_key = UnseededNumberDictionaryShape::AsObject(key);
12418 Object* object_key;
12419 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
12420 SetEntry(entry, object_key, value);
12421 return this;
12422}
12423
12424
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000012425
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012426template<typename Shape, typename Key>
12427int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
12428 PropertyAttributes filter) {
12429 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012430 int result = 0;
12431 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012432 Object* k = HashTable<Shape, Key>::KeyAt(i);
12433 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012434 PropertyDetails details = DetailsAt(i);
12435 if (details.IsDeleted()) continue;
12436 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012437 if ((attr & filter) == 0) result++;
12438 }
12439 }
12440 return result;
12441}
12442
12443
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012444template<typename Shape, typename Key>
12445int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012446 return NumberOfElementsFilterAttributes(
12447 static_cast<PropertyAttributes>(DONT_ENUM));
12448}
12449
12450
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012451template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012452void Dictionary<Shape, Key>::CopyKeysTo(
12453 FixedArray* storage,
12454 PropertyAttributes filter,
12455 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012456 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012457 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012458 int index = 0;
12459 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012460 Object* k = HashTable<Shape, Key>::KeyAt(i);
12461 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012462 PropertyDetails details = DetailsAt(i);
12463 if (details.IsDeleted()) continue;
12464 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012465 if ((attr & filter) == 0) storage->set(index++, k);
12466 }
12467 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012468 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12469 storage->SortPairs(storage, index);
12470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012471 ASSERT(storage->length() >= index);
12472}
12473
12474
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012475void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
12476 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012477 ASSERT(storage->length() >= NumberOfEnumElements());
12478 int capacity = Capacity();
12479 int index = 0;
12480 for (int i = 0; i < capacity; i++) {
12481 Object* k = KeyAt(i);
12482 if (IsKey(k)) {
12483 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012484 if (details.IsDeleted() || details.IsDontEnum()) continue;
12485 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012486 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012487 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012488 }
12489 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012490 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012491 ASSERT(storage->length() >= index);
12492}
12493
12494
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012495template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012496void Dictionary<Shape, Key>::CopyKeysTo(
12497 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012498 int index,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012499 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012500 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
12501 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012502 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012503 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012504 Object* k = HashTable<Shape, Key>::KeyAt(i);
12505 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012506 PropertyDetails details = DetailsAt(i);
12507 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012508 storage->set(index++, k);
12509 }
12510 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000012511 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
12512 storage->SortPairs(storage, index);
12513 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012514 ASSERT(storage->length() >= index);
12515}
12516
12517
12518// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012519template<typename Shape, typename Key>
12520Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
12521 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012522 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012523 Object* k = HashTable<Shape, Key>::KeyAt(i);
12524 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012525 Object* e = ValueAt(i);
12526 if (e->IsJSGlobalPropertyCell()) {
12527 e = JSGlobalPropertyCell::cast(e)->value();
12528 }
12529 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012530 }
12531 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012532 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012533 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012534}
12535
12536
lrn@chromium.org303ada72010-10-27 09:33:13 +000012537MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012538 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012539 // Make sure we preserve dictionary representation if there are too many
12540 // descriptors.
12541 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
12542
12543 // Figure out if it is necessary to generate new enumeration indices.
12544 int max_enumeration_index =
12545 NextEnumerationIndex() +
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012546 (DescriptorArray::kMaxNumberOfDescriptors -
12547 NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012548 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012549 Object* result;
12550 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
12551 if (!maybe_result->ToObject(&result)) return maybe_result;
12552 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012553 }
12554
12555 int instance_descriptor_length = 0;
12556 int number_of_fields = 0;
12557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012558 Heap* heap = GetHeap();
12559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012560 // Compute the length of the instance descriptor.
12561 int capacity = Capacity();
12562 for (int i = 0; i < capacity; i++) {
12563 Object* k = KeyAt(i);
12564 if (IsKey(k)) {
12565 Object* value = ValueAt(i);
12566 PropertyType type = DetailsAt(i).type();
12567 ASSERT(type != FIELD);
12568 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000012569 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012570 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000012571 number_of_fields += 1;
12572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012573 }
12574 }
12575
12576 // Allocate the instance descriptor.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012577 DescriptorArray* descriptors;
12578 { MaybeObject* maybe_descriptors =
lrn@chromium.org303ada72010-10-27 09:33:13 +000012579 DescriptorArray::Allocate(instance_descriptor_length);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012580 if (!maybe_descriptors->To<DescriptorArray>(&descriptors)) {
12581 return maybe_descriptors;
lrn@chromium.org303ada72010-10-27 09:33:13 +000012582 }
12583 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012584
12585 DescriptorArray::WhitenessWitness witness(descriptors);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012586
ager@chromium.org32912102009-01-16 10:38:43 +000012587 int inobject_props = obj->map()->inobject_properties();
12588 int number_of_allocated_fields =
12589 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000012590 if (number_of_allocated_fields < 0) {
12591 // There is enough inobject space for all fields (including unused).
12592 number_of_allocated_fields = 0;
12593 unused_property_fields = inobject_props - number_of_fields;
12594 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012595
12596 // Allocate the fixed array for the fields.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012597 Object* fields;
12598 { MaybeObject* maybe_fields =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012599 heap->AllocateFixedArray(number_of_allocated_fields);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012600 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
12601 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012602
12603 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000012604 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012605 int current_offset = 0;
12606 for (int i = 0; i < capacity; i++) {
12607 Object* k = KeyAt(i);
12608 if (IsKey(k)) {
12609 Object* value = ValueAt(i);
12610 // Ensure the key is a symbol before writing into the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012611 Object* key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012612 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012613 if (!maybe_key->ToObject(&key)) return maybe_key;
12614 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012615 PropertyDetails details = DetailsAt(i);
12616 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000012617
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012618 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012619 ConstantFunctionDescriptor d(String::cast(key),
12620 JSFunction::cast(value),
12621 details.attributes(),
12622 details.index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012623 descriptors->Set(next_descriptor++, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012624 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000012625 if (current_offset < inobject_props) {
12626 obj->InObjectPropertyAtPut(current_offset,
12627 value,
12628 UPDATE_WRITE_BARRIER);
12629 } else {
12630 int offset = current_offset - inobject_props;
12631 FixedArray::cast(fields)->set(offset, value);
12632 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012633 FieldDescriptor d(String::cast(key),
12634 current_offset++,
12635 details.attributes(),
12636 details.index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012637 descriptors->Set(next_descriptor++, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012638 } else if (type == CALLBACKS) {
12639 CallbacksDescriptor d(String::cast(key),
12640 value,
12641 details.attributes(),
12642 details.index());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012643 descriptors->Set(next_descriptor++, &d, witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012644 } else {
12645 UNREACHABLE();
12646 }
12647 }
12648 }
12649 ASSERT(current_offset == number_of_fields);
12650
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012651 descriptors->Sort(witness);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012652 // Allocate new map.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012653 Object* new_map;
12654 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
12655 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
12656 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012657
12658 // Transform the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012659 obj->set_map(Map::cast(new_map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012660 obj->map()->set_instance_descriptors(descriptors);
12661 obj->map()->set_unused_property_fields(unused_property_fields);
12662
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012663 obj->set_properties(FixedArray::cast(fields));
12664 ASSERT(obj->IsJSObject());
12665
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000012666 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
ager@chromium.org32912102009-01-16 10:38:43 +000012667 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012668 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000012669
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012670 return obj;
12671}
12672
12673
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012674bool ObjectHashSet::Contains(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012675 ASSERT(IsKey(key));
12676
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012677 // 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 +000012678 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12679 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return false;
12680 }
12681 return (FindEntry(key) != kNotFound);
12682}
12683
12684
12685MaybeObject* ObjectHashSet::Add(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012686 ASSERT(IsKey(key));
12687
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012688 // Make sure the key object has an identity hash code.
12689 int hash;
12690 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
12691 if (maybe_hash->IsFailure()) return maybe_hash;
12692 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12693 }
12694 int entry = FindEntry(key);
12695
12696 // Check whether key is already present.
12697 if (entry != kNotFound) return this;
12698
12699 // Check whether the hash set should be extended and add entry.
12700 Object* obj;
12701 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12702 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12703 }
12704 ObjectHashSet* table = ObjectHashSet::cast(obj);
12705 entry = table->FindInsertionEntry(hash);
12706 table->set(EntryToIndex(entry), key);
12707 table->ElementAdded();
12708 return table;
12709}
12710
12711
12712MaybeObject* ObjectHashSet::Remove(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012713 ASSERT(IsKey(key));
12714
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012715 // If the object does not have an identity hash, it was never used as a key.
12716 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12717 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) return this;
12718 }
12719 int entry = FindEntry(key);
12720
12721 // Check whether key is actually present.
12722 if (entry == kNotFound) return this;
12723
12724 // Remove entry and try to shrink this hash set.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012725 set_the_hole(EntryToIndex(entry));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012726 ElementRemoved();
12727 return Shrink(key);
12728}
12729
12730
12731Object* ObjectHashTable::Lookup(Object* key) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012732 ASSERT(IsKey(key));
12733
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012734 // If the object does not have an identity hash, it was never used as a key.
12735 { MaybeObject* maybe_hash = key->GetHash(OMIT_CREATION);
12736 if (maybe_hash->ToObjectUnchecked()->IsUndefined()) {
12737 return GetHeap()->undefined_value();
12738 }
12739 }
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012740 int entry = FindEntry(key);
12741 if (entry == kNotFound) return GetHeap()->undefined_value();
12742 return get(EntryToIndex(entry) + 1);
12743}
12744
12745
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012746MaybeObject* ObjectHashTable::Put(Object* key, Object* value) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012747 ASSERT(IsKey(key));
12748
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012749 // Make sure the key object has an identity hash code.
12750 int hash;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012751 { MaybeObject* maybe_hash = key->GetHash(ALLOW_CREATION);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012752 if (maybe_hash->IsFailure()) return maybe_hash;
12753 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
12754 }
12755 int entry = FindEntry(key);
12756
12757 // Check whether to perform removal operation.
12758 if (value->IsUndefined()) {
12759 if (entry == kNotFound) return this;
12760 RemoveEntry(entry);
12761 return Shrink(key);
12762 }
12763
12764 // Key is already in table, just overwrite value.
12765 if (entry != kNotFound) {
12766 set(EntryToIndex(entry) + 1, value);
12767 return this;
12768 }
12769
12770 // Check whether the hash table should be extended.
12771 Object* obj;
12772 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
12773 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
12774 }
12775 ObjectHashTable* table = ObjectHashTable::cast(obj);
12776 table->AddEntry(table->FindInsertionEntry(hash), key, value);
12777 return table;
12778}
12779
12780
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012781void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012782 set(EntryToIndex(entry), key);
12783 set(EntryToIndex(entry) + 1, value);
12784 ElementAdded();
12785}
12786
12787
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012788void ObjectHashTable::RemoveEntry(int entry) {
12789 set_the_hole(EntryToIndex(entry));
12790 set_the_hole(EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000012791 ElementRemoved();
12792}
12793
12794
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012795#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012796// Check if there is a break point at this code position.
12797bool DebugInfo::HasBreakPoint(int code_position) {
12798 // Get the break point info object for this code position.
12799 Object* break_point_info = GetBreakPointInfo(code_position);
12800
12801 // If there is no break point info object or no break points in the break
12802 // point info object there is no break point at this code position.
12803 if (break_point_info->IsUndefined()) return false;
12804 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
12805}
12806
12807
12808// Get the break point info object for this code position.
12809Object* DebugInfo::GetBreakPointInfo(int code_position) {
12810 // Find the index of the break point info object for this code position.
12811 int index = GetBreakPointInfoIndex(code_position);
12812
12813 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012814 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012815 return BreakPointInfo::cast(break_points()->get(index));
12816}
12817
12818
12819// Clear a break point at the specified code position.
12820void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
12821 int code_position,
12822 Handle<Object> break_point_object) {
12823 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12824 if (break_point_info->IsUndefined()) return;
12825 BreakPointInfo::ClearBreakPoint(
12826 Handle<BreakPointInfo>::cast(break_point_info),
12827 break_point_object);
12828}
12829
12830
12831void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
12832 int code_position,
12833 int source_position,
12834 int statement_position,
12835 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012836 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012837 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
12838 if (!break_point_info->IsUndefined()) {
12839 BreakPointInfo::SetBreakPoint(
12840 Handle<BreakPointInfo>::cast(break_point_info),
12841 break_point_object);
12842 return;
12843 }
12844
12845 // Adding a new break point for a code position which did not have any
12846 // break points before. Try to find a free slot.
12847 int index = kNoBreakPointInfo;
12848 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12849 if (debug_info->break_points()->get(i)->IsUndefined()) {
12850 index = i;
12851 break;
12852 }
12853 }
12854 if (index == kNoBreakPointInfo) {
12855 // No free slot - extend break point info array.
12856 Handle<FixedArray> old_break_points =
12857 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012858 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012859 isolate->factory()->NewFixedArray(
12860 old_break_points->length() +
12861 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000012862
12863 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012864 for (int i = 0; i < old_break_points->length(); i++) {
12865 new_break_points->set(i, old_break_points->get(i));
12866 }
12867 index = old_break_points->length();
12868 }
12869 ASSERT(index != kNoBreakPointInfo);
12870
12871 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012872 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
12873 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012874 new_break_point_info->set_code_position(Smi::FromInt(code_position));
12875 new_break_point_info->set_source_position(Smi::FromInt(source_position));
12876 new_break_point_info->
12877 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012878 new_break_point_info->set_break_point_objects(
12879 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012880 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
12881 debug_info->break_points()->set(index, *new_break_point_info);
12882}
12883
12884
12885// Get the break point objects for a code position.
12886Object* DebugInfo::GetBreakPointObjects(int code_position) {
12887 Object* break_point_info = GetBreakPointInfo(code_position);
12888 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012889 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012890 }
12891 return BreakPointInfo::cast(break_point_info)->break_point_objects();
12892}
12893
12894
12895// Get the total number of break points.
12896int DebugInfo::GetBreakPointCount() {
12897 if (break_points()->IsUndefined()) return 0;
12898 int count = 0;
12899 for (int i = 0; i < break_points()->length(); i++) {
12900 if (!break_points()->get(i)->IsUndefined()) {
12901 BreakPointInfo* break_point_info =
12902 BreakPointInfo::cast(break_points()->get(i));
12903 count += break_point_info->GetBreakPointCount();
12904 }
12905 }
12906 return count;
12907}
12908
12909
12910Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
12911 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012912 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012913 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012914 for (int i = 0; i < debug_info->break_points()->length(); i++) {
12915 if (!debug_info->break_points()->get(i)->IsUndefined()) {
12916 Handle<BreakPointInfo> break_point_info =
12917 Handle<BreakPointInfo>(BreakPointInfo::cast(
12918 debug_info->break_points()->get(i)));
12919 if (BreakPointInfo::HasBreakPointObject(break_point_info,
12920 break_point_object)) {
12921 return *break_point_info;
12922 }
12923 }
12924 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012925 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012926}
12927
12928
12929// Find the index of the break point info object for the specified code
12930// position.
12931int DebugInfo::GetBreakPointInfoIndex(int code_position) {
12932 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
12933 for (int i = 0; i < break_points()->length(); i++) {
12934 if (!break_points()->get(i)->IsUndefined()) {
12935 BreakPointInfo* break_point_info =
12936 BreakPointInfo::cast(break_points()->get(i));
12937 if (break_point_info->code_position()->value() == code_position) {
12938 return i;
12939 }
12940 }
12941 }
12942 return kNoBreakPointInfo;
12943}
12944
12945
12946// Remove the specified break point object.
12947void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
12948 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012950 // If there are no break points just ignore.
12951 if (break_point_info->break_point_objects()->IsUndefined()) return;
12952 // If there is a single break point clear it if it is the same.
12953 if (!break_point_info->break_point_objects()->IsFixedArray()) {
12954 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012955 break_point_info->set_break_point_objects(
12956 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012957 }
12958 return;
12959 }
12960 // If there are multiple break points shrink the array
12961 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
12962 Handle<FixedArray> old_array =
12963 Handle<FixedArray>(
12964 FixedArray::cast(break_point_info->break_point_objects()));
12965 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012966 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012967 int found_count = 0;
12968 for (int i = 0; i < old_array->length(); i++) {
12969 if (old_array->get(i) == *break_point_object) {
12970 ASSERT(found_count == 0);
12971 found_count++;
12972 } else {
12973 new_array->set(i - found_count, old_array->get(i));
12974 }
12975 }
12976 // If the break point was found in the list change it.
12977 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
12978}
12979
12980
12981// Add the specified break point object.
12982void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
12983 Handle<Object> break_point_object) {
12984 // If there was no break point objects before just set it.
12985 if (break_point_info->break_point_objects()->IsUndefined()) {
12986 break_point_info->set_break_point_objects(*break_point_object);
12987 return;
12988 }
12989 // If the break point object is the same as before just ignore.
12990 if (break_point_info->break_point_objects() == *break_point_object) return;
12991 // If there was one break point object before replace with array.
12992 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012993 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012994 array->set(0, break_point_info->break_point_objects());
12995 array->set(1, *break_point_object);
12996 break_point_info->set_break_point_objects(*array);
12997 return;
12998 }
12999 // If there was more than one break point before extend array.
13000 Handle<FixedArray> old_array =
13001 Handle<FixedArray>(
13002 FixedArray::cast(break_point_info->break_point_objects()));
13003 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013004 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013005 for (int i = 0; i < old_array->length(); i++) {
13006 // If the break point was there before just ignore.
13007 if (old_array->get(i) == *break_point_object) return;
13008 new_array->set(i, old_array->get(i));
13009 }
13010 // Add the new break point.
13011 new_array->set(old_array->length(), *break_point_object);
13012 break_point_info->set_break_point_objects(*new_array);
13013}
13014
13015
13016bool BreakPointInfo::HasBreakPointObject(
13017 Handle<BreakPointInfo> break_point_info,
13018 Handle<Object> break_point_object) {
13019 // No break point.
13020 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013021 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013022 if (!break_point_info->break_point_objects()->IsFixedArray()) {
13023 return break_point_info->break_point_objects() == *break_point_object;
13024 }
13025 // Multiple break points.
13026 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
13027 for (int i = 0; i < array->length(); i++) {
13028 if (array->get(i) == *break_point_object) {
13029 return true;
13030 }
13031 }
13032 return false;
13033}
13034
13035
13036// Get the number of break points.
13037int BreakPointInfo::GetBreakPointCount() {
13038 // No break point.
13039 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000013040 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013041 if (!break_point_objects()->IsFixedArray()) return 1;
13042 // Multiple break points.
13043 return FixedArray::cast(break_point_objects())->length();
13044}
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013045#endif // ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013046
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013047
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013048} } // namespace v8::internal