blob: 640865cacfd3b48ca8ef64ba4baa6ebdb1c66c1d [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "macro-assembler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000043#include "safepoint-table.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000044#include "scanner-base.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000045#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000046#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000047#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048
mads.s.ager31e71382008-08-13 09:32:07 +000049#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000050#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000051#include "disassembler.h"
52#endif
53
kasperl@chromium.org71affb52009-05-26 05:44:31 +000054namespace v8 {
55namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057// Getters and setters are stored in a fixed array property. These are
58// constants for their indices.
59const int kGetterIndex = 0;
60const int kSetterIndex = 1;
61
lrn@chromium.org303ada72010-10-27 09:33:13 +000062MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
63 Object* value) {
64 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 { MaybeObject* maybe_result =
66 constructor->GetHeap()->AllocateJSObject(constructor);
lrn@chromium.org303ada72010-10-27 09:33:13 +000067 if (!maybe_result->ToObject(&result)) return maybe_result;
68 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000069 JSValue::cast(result)->set_value(value);
70 return result;
71}
72
73
lrn@chromium.org303ada72010-10-27 09:33:13 +000074MaybeObject* Object::ToObject(Context* global_context) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000075 if (IsNumber()) {
76 return CreateJSValue(global_context->number_function(), this);
77 } else if (IsBoolean()) {
78 return CreateJSValue(global_context->boolean_function(), this);
79 } else if (IsString()) {
80 return CreateJSValue(global_context->string_function(), this);
81 }
82 ASSERT(IsJSObject());
83 return this;
84}
85
86
lrn@chromium.org303ada72010-10-27 09:33:13 +000087MaybeObject* Object::ToObject() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000088 if (IsJSObject()) {
89 return this;
90 } else if (IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000091 Isolate* isolate = Isolate::Current();
92 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000093 return CreateJSValue(global_context->number_function(), this);
94 } else if (IsBoolean()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
96 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000097 return CreateJSValue(global_context->boolean_function(), this);
98 } else if (IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
100 Context* global_context = isolate->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 return CreateJSValue(global_context->string_function(), this);
102 }
103
104 // Throw a type error.
105 return Failure::InternalError();
106}
107
108
109Object* Object::ToBoolean() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 if (IsTrue()) return this;
111 if (IsFalse()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000112 if (IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000115 HeapObject* heap_object = HeapObject::cast(this);
116 if (heap_object->IsUndefined() || heap_object->IsNull()) {
117 return heap_object->GetHeap()->false_value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000118 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000119 // Undetectable object is false
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000120 if (heap_object->IsUndetectableObject()) {
121 return heap_object->GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000123 if (heap_object->IsString()) {
124 return heap_object->GetHeap()->ToBoolean(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000125 String::cast(this)->length() != 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000126 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000127 if (heap_object->IsHeapNumber()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128 return HeapNumber::cast(this)->HeapNumberToBoolean();
129 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000130 return heap_object->GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131}
132
133
134void Object::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000135 Object* holder = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000136 if (IsSmi()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000137 Context* global_context = Isolate::Current()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000138 holder = global_context->number_function()->instance_prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000139 } else {
140 HeapObject* heap_object = HeapObject::cast(this);
141 if (heap_object->IsJSObject()) {
142 return JSObject::cast(this)->Lookup(name, result);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000143 } else if (heap_object->IsJSProxy()) {
144 return result->HandlerResult();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000145 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000146 Context* global_context = Isolate::Current()->context()->global_context();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000147 if (heap_object->IsString()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000148 holder = global_context->string_function()->instance_prototype();
149 } else if (heap_object->IsHeapNumber()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000150 holder = global_context->number_function()->instance_prototype();
151 } else if (heap_object->IsBoolean()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000152 holder = global_context->boolean_function()->instance_prototype();
153 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000154 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000155 ASSERT(holder != NULL); // Cannot handle null or undefined.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 JSObject::cast(holder)->Lookup(name, result);
157}
158
159
lrn@chromium.org303ada72010-10-27 09:33:13 +0000160MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
161 String* name,
162 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000163 LookupResult result;
164 Lookup(name, &result);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000165 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000166 ASSERT(*attributes <= ABSENT);
167 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000168}
169
170
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
172 Object* structure,
173 String* name,
174 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 Isolate* isolate = name->GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000176 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000177 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000178 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000179 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000180 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000181 reinterpret_cast<AccessorDescriptor*>(
182 Foreign::cast(structure)->address());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000183 MaybeObject* value = (callback->getter)(receiver, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000185 return value;
186 }
187
188 // api style callbacks.
189 if (structure->IsAccessorInfo()) {
190 AccessorInfo* data = AccessorInfo::cast(structure);
191 Object* fun_obj = data->getter();
192 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000193 HandleScope scope(isolate);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000194 JSObject* self = JSObject::cast(receiver);
195 JSObject* holder_handle = JSObject::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000197 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
198 CustomArguments args(isolate, data->data(), self, holder_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +0000199 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000200 v8::Handle<v8::Value> result;
201 {
202 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000203 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000204 result = call_fun(v8::Utils::ToLocal(key), info);
205 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000206 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
207 if (result.IsEmpty()) {
208 return isolate->heap()->undefined_value();
209 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000210 return *v8::Utils::OpenHandle(*result);
211 }
212
213 // __defineGetter__ callback
214 if (structure->IsFixedArray()) {
215 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
216 if (getter->IsJSFunction()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000217 return Object::GetPropertyWithDefinedGetter(receiver,
218 JSFunction::cast(getter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000219 }
220 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000221 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 }
223
224 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000225 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000226}
227
228
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000229MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
230 String* name_raw,
231 Object* handler_raw) {
232 Isolate* isolate = name_raw->GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000233 HandleScope scope(isolate);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000234 Handle<Object> receiver(receiver_raw);
235 Handle<Object> name(name_raw);
236 Handle<Object> handler(handler_raw);
237
238 // Extract trap function.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000239 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
240 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
241 if (trap->IsUndefined()) {
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000242 // Get the derived `get' property.
ager@chromium.orgea91cc52011-05-23 06:06:11 +0000243 trap = isolate->derived_get_trap();
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000244 }
245
246 // Call trap function.
247 Object** args[] = { receiver.location(), name.location() };
248 bool has_exception;
249 Handle<Object> result =
250 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
251 if (has_exception) return Failure::Exception();
252
253 return *result;
254}
255
256
lrn@chromium.org303ada72010-10-27 09:33:13 +0000257MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
258 JSFunction* getter) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000259 HandleScope scope;
260 Handle<JSFunction> fun(JSFunction::cast(getter));
261 Handle<Object> self(receiver);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000262#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000263 Debug* debug = fun->GetHeap()->isolate()->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000264 // Handle stepping into a getter if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000265 if (debug->StepInActive()) {
266 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000267 }
268#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000269 bool has_pending_exception;
270 Handle<Object> result =
271 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
272 // Check for pending exception and return the result.
273 if (has_pending_exception) return Failure::Exception();
274 return *result;
275}
276
277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000278// Only deal with CALLBACKS and INTERCEPTOR
lrn@chromium.org303ada72010-10-27 09:33:13 +0000279MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
ager@chromium.org8bb60582008-12-11 12:02:20 +0000280 Object* receiver,
281 LookupResult* result,
282 String* name,
283 PropertyAttributes* attributes) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000284 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285 switch (result->type()) {
286 case CALLBACKS: {
287 // Only allow API accessors.
288 Object* obj = result->GetCallbackObject();
289 if (obj->IsAccessorInfo()) {
290 AccessorInfo* info = AccessorInfo::cast(obj);
291 if (info->all_can_read()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000292 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000293 return GetPropertyWithCallback(receiver,
294 result->GetCallbackObject(),
295 name,
296 result->holder());
297 }
298 }
299 break;
300 }
301 case NORMAL:
302 case FIELD:
303 case CONSTANT_FUNCTION: {
304 // Search ALL_CAN_READ accessors in prototype chain.
305 LookupResult r;
306 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000307 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000308 return GetPropertyWithFailedAccessCheck(receiver,
309 &r,
310 name,
311 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312 }
313 break;
314 }
315 case INTERCEPTOR: {
316 // If the object has an interceptor, try real named properties.
317 // No access check in GetPropertyAttributeWithInterceptor.
318 LookupResult r;
319 result->holder()->LookupRealNamedProperty(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000320 if (r.IsProperty()) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000321 return GetPropertyWithFailedAccessCheck(receiver,
322 &r,
323 name,
324 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000325 }
ager@chromium.org9ed6c322010-02-19 12:24:05 +0000326 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000328 default:
329 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000330 }
331 }
332
ager@chromium.org8bb60582008-12-11 12:02:20 +0000333 // No accessible property found.
334 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000335 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000336 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
337 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000338}
339
340
ager@chromium.org870a0b62008-11-04 11:43:05 +0000341PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
342 Object* receiver,
343 LookupResult* result,
344 String* name,
345 bool continue_search) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000346 if (result->IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000347 switch (result->type()) {
348 case CALLBACKS: {
349 // Only allow API accessors.
350 Object* obj = result->GetCallbackObject();
351 if (obj->IsAccessorInfo()) {
352 AccessorInfo* info = AccessorInfo::cast(obj);
353 if (info->all_can_read()) {
354 return result->GetAttributes();
355 }
356 }
357 break;
358 }
359
360 case NORMAL:
361 case FIELD:
362 case CONSTANT_FUNCTION: {
363 if (!continue_search) break;
364 // Search ALL_CAN_READ accessors in prototype chain.
365 LookupResult r;
366 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
ager@chromium.org5c838252010-02-19 08:53:10 +0000367 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000368 return GetPropertyAttributeWithFailedAccessCheck(receiver,
369 &r,
370 name,
371 continue_search);
372 }
373 break;
374 }
375
376 case INTERCEPTOR: {
377 // If the object has an interceptor, try real named properties.
378 // No access check in GetPropertyAttributeWithInterceptor.
379 LookupResult r;
380 if (continue_search) {
381 result->holder()->LookupRealNamedProperty(name, &r);
382 } else {
383 result->holder()->LocalLookupRealNamedProperty(name, &r);
384 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000385 if (r.IsProperty()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000386 return GetPropertyAttributeWithFailedAccessCheck(receiver,
387 &r,
388 name,
389 continue_search);
390 }
391 break;
392 }
393
ager@chromium.org5c838252010-02-19 08:53:10 +0000394 default:
395 UNREACHABLE();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000396 }
397 }
398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000399 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000400 return ABSENT;
401}
402
403
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000404Object* JSObject::GetNormalizedProperty(LookupResult* result) {
405 ASSERT(!HasFastProperties());
406 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
407 if (IsGlobalObject()) {
408 value = JSGlobalPropertyCell::cast(value)->value();
409 }
410 ASSERT(!value->IsJSGlobalPropertyCell());
411 return value;
412}
413
414
415Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
416 ASSERT(!HasFastProperties());
417 if (IsGlobalObject()) {
418 JSGlobalPropertyCell* cell =
419 JSGlobalPropertyCell::cast(
420 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
421 cell->set_value(value);
422 } else {
423 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
424 }
425 return value;
426}
427
428
lrn@chromium.org303ada72010-10-27 09:33:13 +0000429MaybeObject* JSObject::SetNormalizedProperty(String* name,
430 Object* value,
431 PropertyDetails details) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000432 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000433 int entry = property_dictionary()->FindEntry(name);
434 if (entry == StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000435 Object* store_value = value;
436 if (IsGlobalObject()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000437 Heap* heap = name->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 MaybeObject* maybe_store_value =
439 heap->AllocateJSGlobalPropertyCell(value);
440 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000441 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000442 Object* dict;
443 { MaybeObject* maybe_dict =
444 property_dictionary()->Add(name, store_value, details);
445 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
446 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000447 set_properties(StringDictionary::cast(dict));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000448 return value;
449 }
450 // Preserve enumeration index.
451 details = PropertyDetails(details.attributes(),
452 details.type(),
453 property_dictionary()->DetailsAt(entry).index());
454 if (IsGlobalObject()) {
455 JSGlobalPropertyCell* cell =
456 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
457 cell->set_value(value);
458 // Please note we have to update the property details.
459 property_dictionary()->DetailsAtPut(entry, details);
460 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000461 property_dictionary()->SetEntry(entry, name, value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000462 }
463 return value;
464}
465
466
lrn@chromium.org303ada72010-10-27 09:33:13 +0000467MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000468 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +0000469 StringDictionary* dictionary = property_dictionary();
470 int entry = dictionary->FindEntry(name);
471 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000472 // If we have a global object set the cell to the hole.
473 if (IsGlobalObject()) {
474 PropertyDetails details = dictionary->DetailsAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000475 if (details.IsDontDelete()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000476 if (mode != FORCE_DELETION) return GetHeap()->false_value();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000477 // When forced to delete global properties, we have to make a
478 // map change to invalidate any ICs that think they can load
479 // from the DontDelete cell without checking if it contains
480 // the hole value.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000481 Object* new_map;
482 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
483 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
484 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +0000485 set_map(Map::cast(new_map));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000486 }
487 JSGlobalPropertyCell* cell =
488 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489 cell->set_value(cell->heap()->the_hole_value());
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000490 dictionary->DetailsAtPut(entry, details.AsDeleted());
491 } else {
ager@chromium.org04921a82011-06-27 13:21:41 +0000492 Object* deleted = dictionary->DeleteProperty(entry, mode);
493 if (deleted == GetHeap()->true_value()) {
494 FixedArray* new_properties = NULL;
495 MaybeObject* maybe_properties = dictionary->Shrink(name);
496 if (!maybe_properties->To(&new_properties)) {
497 return maybe_properties;
498 }
499 set_properties(new_properties);
500 }
501 return deleted;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000502 }
503 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000504 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000505}
506
507
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000508bool JSObject::IsDirty() {
509 Object* cons_obj = map()->constructor();
510 if (!cons_obj->IsJSFunction())
511 return true;
512 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000514 return true;
515 // If the object is fully fast case and has the same map it was
516 // created with then no changes can have been made to it.
517 return map() != fun->initial_map()
518 || !HasFastElements()
519 || !HasFastProperties();
520}
521
522
lrn@chromium.org303ada72010-10-27 09:33:13 +0000523MaybeObject* Object::GetProperty(Object* receiver,
524 LookupResult* result,
525 String* name,
526 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 // Make sure that the top context does not change when doing
528 // callbacks or interceptor calls.
529 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 Heap* heap = name->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531
532 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000533 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534 // objects more than once in case of interceptors, because the
535 // holder will always be the interceptor holder and the search may
536 // only continue with a current object just after the interceptor
537 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000538 // Proxy handlers do not use the proxy's prototype, so we can skip this.
539 if (!result->IsHandler()) {
540 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
541 ASSERT(this != this->GetPrototype());
542 for (Object* current = this; true; current = current->GetPrototype()) {
543 if (current->IsAccessCheckNeeded()) {
544 // Check if we're allowed to read from the current object. Note
545 // that even though we may not actually end up loading the named
546 // property from the current object, we still check that we have
547 // access to it.
548 JSObject* checked = JSObject::cast(current);
549 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
550 return checked->GetPropertyWithFailedAccessCheck(receiver,
551 result,
552 name,
553 attributes);
554 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000556 // Stop traversing the chain once we reach the last object in the
557 // chain; either the holder of the result or null in case of an
558 // absent property.
559 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000561 }
562
kasper.lund44510672008-07-25 07:37:58 +0000563 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 }
567 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 Object* value;
569 JSObject* holder = result->holder();
570 switch (result->type()) {
571 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000572 value = holder->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000573 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +0000576 value = holder->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579 case CONSTANT_FUNCTION:
580 return result->GetConstantFunction();
581 case CALLBACKS:
582 return GetPropertyWithCallback(receiver,
583 result->GetCallbackObject(),
584 name,
585 holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000586 case HANDLER: {
587 JSProxy* proxy = JSProxy::cast(this);
588 return GetPropertyWithHandler(receiver, name, proxy->handler());
589 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000590 case INTERCEPTOR: {
591 JSObject* recvr = JSObject::cast(receiver);
592 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
593 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000594 case MAP_TRANSITION:
595 case EXTERNAL_ARRAY_TRANSITION:
596 case CONSTANT_TRANSITION:
597 case NULL_DESCRIPTOR:
598 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000600 UNREACHABLE();
601 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000602}
603
604
lrn@chromium.org303ada72010-10-27 09:33:13 +0000605MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000606 Heap* heap = IsSmi()
607 ? Isolate::Current()->heap()
608 : HeapObject::cast(this)->GetHeap();
609 Object* holder = this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000610
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000611 // Iterate up the prototype chain until an element is found or the null
612 // prototype is encountered.
613 for (holder = this;
614 holder != heap->null_value();
615 holder = holder->GetPrototype()) {
616 if (holder->IsSmi()) {
617 Context* global_context = Isolate::Current()->context()->global_context();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618 holder = global_context->number_function()->instance_prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000620 HeapObject* heap_object = HeapObject::cast(holder);
621 if (!heap_object->IsJSObject()) {
622 Isolate* isolate = heap->isolate();
623 Context* global_context = isolate->context()->global_context();
624 if (heap_object->IsString()) {
625 holder = global_context->string_function()->instance_prototype();
626 } else if (heap_object->IsHeapNumber()) {
627 holder = global_context->number_function()->instance_prototype();
628 } else if (heap_object->IsBoolean()) {
629 holder = global_context->boolean_function()->instance_prototype();
630 } else if (heap_object->IsJSProxy()) {
631 return heap->undefined_value(); // For now...
632 } else {
633 // Undefined and null have no indexed properties.
634 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
635 return heap->undefined_value();
636 }
637 }
638 }
639
640 // Inline the case for JSObjects. Doing so significantly improves the
641 // performance of fetching elements where checking the prototype chain is
642 // necessary.
643 JSObject* js_object = JSObject::cast(holder);
644
645 // Check access rights if needed.
646 if (js_object->IsAccessCheckNeeded()) {
647 Isolate* isolate = heap->isolate();
648 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
649 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
650 return heap->undefined_value();
651 }
652 }
653
654 if (js_object->HasIndexedInterceptor()) {
655 return js_object->GetElementWithInterceptor(receiver, index);
656 }
657
658 if (js_object->elements() != heap->empty_fixed_array()) {
659 MaybeObject* result = js_object->GetElementsAccessor()->GetWithReceiver(
660 js_object,
661 receiver,
662 index);
663 if (result != heap->the_hole_value()) return result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000664 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000665 }
666
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000667 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000668}
669
670
671Object* Object::GetPrototype() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000672 if (IsSmi()) {
673 Heap* heap = Isolate::Current()->heap();
674 Context* context = heap->isolate()->context()->global_context();
675 return context->number_function()->instance_prototype();
676 }
677
678 HeapObject* heap_object = HeapObject::cast(this);
679
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000680 // The object is either a number, a string, a boolean,
681 // a real JS object, or a Harmony proxy.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000682 if (heap_object->IsJSReceiver()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000683 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000684 }
685 Heap* heap = heap_object->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000686 Context* context = heap->isolate()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000688 if (heap_object->IsHeapNumber()) {
689 return context->number_function()->instance_prototype();
690 }
691 if (heap_object->IsString()) {
692 return context->string_function()->instance_prototype();
693 }
694 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695 return context->boolean_function()->instance_prototype();
696 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000697 return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 }
699}
700
701
whesse@chromium.org023421e2010-12-21 12:19:12 +0000702void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703 HeapStringAllocator allocator;
704 StringStream accumulator(&allocator);
705 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000706 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000707}
708
709
710void Object::ShortPrint(StringStream* accumulator) {
711 if (IsSmi()) {
712 Smi::cast(this)->SmiPrint(accumulator);
713 } else if (IsFailure()) {
714 Failure::cast(this)->FailurePrint(accumulator);
715 } else {
716 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
717 }
718}
719
720
whesse@chromium.org023421e2010-12-21 12:19:12 +0000721void Smi::SmiPrint(FILE* out) {
722 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723}
724
725
726void Smi::SmiPrint(StringStream* accumulator) {
727 accumulator->Add("%d", value());
728}
729
730
731void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000732 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000733}
734
735
whesse@chromium.org023421e2010-12-21 12:19:12 +0000736void Failure::FailurePrint(FILE* out) {
737 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000738}
739
740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741// Should a word be prefixed by 'a' or 'an' in order to read naturally in
742// English? Returns false for non-ASCII or words that don't start with
743// a capital letter. The a/an rule follows pronunciation in English.
744// We don't use the BBC's overcorrect "an historic occasion" though if
745// you speak a dialect you may well say "an 'istoric occasion".
746static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000747 if (str->length() == 0) return false; // A nothing.
748 int c0 = str->Get(0);
749 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000750 if (c0 == 'U') {
751 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000752 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000753 }
754 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000755 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
757 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
758 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000759 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 }
761 return false;
762}
763
764
lrn@chromium.org303ada72010-10-27 09:33:13 +0000765MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766#ifdef DEBUG
767 // Do not attempt to flatten in debug mode when allocation is not
768 // allowed. This is to avoid an assertion failure when allocating.
769 // Flattening strings is the only case where we always allow
770 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772#endif
773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000774 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000775 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776 case kConsStringTag: {
777 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000778 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000779 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 }
781 // There's little point in putting the flat string in new space if the
782 // cons string is in old space. It can never get GCed until there is
783 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000784 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000785 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000786 Object* object;
787 String* result;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000788 if (IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000789 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000790 if (!maybe_object->ToObject(&object)) return maybe_object;
791 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000792 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000793 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000794 int first_length = first->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000795 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000796 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000797 String* second = cs->second();
798 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000799 dest + first_length,
800 0,
801 len - first_length);
802 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000803 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000804 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000805 if (!maybe_object->ToObject(&object)) return maybe_object;
806 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000807 result = String::cast(object);
808 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000809 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000810 int first_length = first->length();
811 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000812 String* second = cs->second();
813 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000814 dest + first_length,
815 0,
816 len - first_length);
817 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000818 cs->set_first(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000819 cs->set_second(heap->empty_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000820 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000821 }
822 default:
823 return this;
824 }
825}
826
827
ager@chromium.org6f10e412009-02-13 10:11:16 +0000828bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000829 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000830 // prohibited by the API.
831 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000832#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000833 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000834 // Assert that the resource and the string are equivalent.
835 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000836 ScopedVector<uc16> smart_chars(this->length());
837 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
838 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000839 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000840 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000841 }
842#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000843 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000844 int size = this->Size(); // Byte size of the original string.
845 if (size < ExternalString::kSize) {
846 // The string is too small to fit an external String in its place. This can
847 // only happen for zero length strings.
848 return false;
849 }
850 ASSERT(size >= ExternalString::kSize);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000851 bool is_ascii = this->IsAsciiRepresentation();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000852 bool is_symbol = this->IsSymbol();
853 int length = this->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000854 int hash_field = this->hash_field();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000855
856 // Morph the object to an external string by adjusting the map and
857 // reinitializing the fields.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000858 this->set_map(is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 heap->external_string_with_ascii_data_map() :
860 heap->external_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000861 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
862 self->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000863 self->set_hash_field(hash_field);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000864 self->set_resource(resource);
865 // Additionally make the object into an external symbol if the original string
866 // was a symbol to start with.
867 if (is_symbol) {
868 self->Hash(); // Force regeneration of the hash value.
869 // Now morph this external string into a external symbol.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000870 this->set_map(is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000871 heap->external_symbol_with_ascii_data_map() :
872 heap->external_symbol_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000873 }
874
875 // Fill the remainder of the string with dead wood.
876 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000877 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000878 return true;
879}
880
881
882bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
883#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000884 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000885 // Assert that the resource and the string are equivalent.
886 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000887 ScopedVector<char> smart_chars(this->length());
888 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
889 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000890 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000891 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000892 }
893#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000895 int size = this->Size(); // Byte size of the original string.
896 if (size < ExternalString::kSize) {
897 // The string is too small to fit an external String in its place. This can
898 // only happen for zero length strings.
899 return false;
900 }
901 ASSERT(size >= ExternalString::kSize);
902 bool is_symbol = this->IsSymbol();
903 int length = this->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000904 int hash_field = this->hash_field();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000905
906 // Morph the object to an external string by adjusting the map and
907 // reinitializing the fields.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000908 this->set_map(heap->external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000909 ExternalAsciiString* self = ExternalAsciiString::cast(this);
910 self->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000911 self->set_hash_field(hash_field);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000912 self->set_resource(resource);
913 // Additionally make the object into an external symbol if the original string
914 // was a symbol to start with.
915 if (is_symbol) {
916 self->Hash(); // Force regeneration of the hash value.
917 // Now morph this external string into a external symbol.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 this->set_map(heap->external_ascii_symbol_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000919 }
920
921 // Fill the remainder of the string with dead wood.
922 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000924 return true;
925}
926
927
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000929 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000930 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000931 accumulator->Add("<Very long string[%u]>", len);
932 return;
933 }
934
935 if (!LooksValid()) {
936 accumulator->Add("<Invalid String>");
937 return;
938 }
939
940 StringInputBuffer buf(this);
941
942 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +0000943 if (len > kMaxShortPrintLength) {
944 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000945 truncated = true;
946 }
947 bool ascii = true;
948 for (int i = 0; i < len; i++) {
949 int c = buf.GetNext();
950
951 if (c < 32 || c >= 127) {
952 ascii = false;
953 }
954 }
955 buf.Reset(this);
956 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000957 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958 for (int i = 0; i < len; i++) {
959 accumulator->Put(buf.GetNext());
960 }
961 accumulator->Put('>');
962 } else {
963 // Backslash indicates that the string contains control
964 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000965 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966 for (int i = 0; i < len; i++) {
967 int c = buf.GetNext();
968 if (c == '\n') {
969 accumulator->Add("\\n");
970 } else if (c == '\r') {
971 accumulator->Add("\\r");
972 } else if (c == '\\') {
973 accumulator->Add("\\\\");
974 } else if (c < 32 || c > 126) {
975 accumulator->Add("\\x%02x", c);
976 } else {
977 accumulator->Put(c);
978 }
979 }
980 if (truncated) {
981 accumulator->Put('.');
982 accumulator->Put('.');
983 accumulator->Put('.');
984 }
985 accumulator->Put('>');
986 }
987 return;
988}
989
990
991void JSObject::JSObjectShortPrint(StringStream* accumulator) {
992 switch (map()->instance_type()) {
993 case JS_ARRAY_TYPE: {
994 double length = JSArray::cast(this)->length()->Number();
995 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
996 break;
997 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000998 case JS_WEAK_MAP_TYPE: {
999 int elements = JSWeakMap::cast(this)->table()->NumberOfElements();
1000 accumulator->Add("<JS WeakMap[%d]>", elements);
1001 break;
1002 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001003 case JS_REGEXP_TYPE: {
1004 accumulator->Add("<JS RegExp>");
1005 break;
1006 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 case JS_FUNCTION_TYPE: {
1008 Object* fun_name = JSFunction::cast(this)->shared()->name();
1009 bool printed = false;
1010 if (fun_name->IsString()) {
1011 String* str = String::cast(fun_name);
1012 if (str->length() > 0) {
1013 accumulator->Add("<JS Function ");
1014 accumulator->Put(str);
1015 accumulator->Put('>');
1016 printed = true;
1017 }
1018 }
1019 if (!printed) {
1020 accumulator->Add("<JS Function>");
1021 }
1022 break;
1023 }
1024 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001025 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001026 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001027 Map* map_of_this = map();
1028 Heap* heap = map_of_this->heap();
1029 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001030 bool printed = false;
1031 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1034 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001035 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001037 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1039 } else {
1040 Object* constructor_name =
1041 JSFunction::cast(constructor)->shared()->name();
1042 if (constructor_name->IsString()) {
1043 String* str = String::cast(constructor_name);
1044 if (str->length() > 0) {
1045 bool vowel = AnWord(str);
1046 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001047 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 vowel ? "n" : "");
1049 accumulator->Put(str);
1050 accumulator->Put('>');
1051 printed = true;
1052 }
1053 }
1054 }
1055 }
1056 if (!printed) {
1057 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1058 }
1059 }
1060 if (IsJSValue()) {
1061 accumulator->Add(" value = ");
1062 JSValue::cast(this)->value()->ShortPrint(accumulator);
1063 }
1064 accumulator->Put('>');
1065 break;
1066 }
1067 }
1068}
1069
1070
1071void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1073 Heap* heap = GetHeap();
1074 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 accumulator->Add("!!!INVALID POINTER!!!");
1076 return;
1077 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001078 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079 accumulator->Add("!!!INVALID MAP!!!");
1080 return;
1081 }
1082
1083 accumulator->Add("%p ", this);
1084
1085 if (IsString()) {
1086 String::cast(this)->StringShortPrint(accumulator);
1087 return;
1088 }
1089 if (IsJSObject()) {
1090 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1091 return;
1092 }
1093 switch (map()->instance_type()) {
1094 case MAP_TYPE:
1095 accumulator->Add("<Map>");
1096 break;
1097 case FIXED_ARRAY_TYPE:
1098 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1099 break;
1100 case BYTE_ARRAY_TYPE:
1101 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1102 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001103 case EXTERNAL_PIXEL_ARRAY_TYPE:
1104 accumulator->Add("<ExternalPixelArray[%u]>",
1105 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001106 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001107 case EXTERNAL_BYTE_ARRAY_TYPE:
1108 accumulator->Add("<ExternalByteArray[%u]>",
1109 ExternalByteArray::cast(this)->length());
1110 break;
1111 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1112 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1113 ExternalUnsignedByteArray::cast(this)->length());
1114 break;
1115 case EXTERNAL_SHORT_ARRAY_TYPE:
1116 accumulator->Add("<ExternalShortArray[%u]>",
1117 ExternalShortArray::cast(this)->length());
1118 break;
1119 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1120 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1121 ExternalUnsignedShortArray::cast(this)->length());
1122 break;
1123 case EXTERNAL_INT_ARRAY_TYPE:
1124 accumulator->Add("<ExternalIntArray[%u]>",
1125 ExternalIntArray::cast(this)->length());
1126 break;
1127 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1128 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1129 ExternalUnsignedIntArray::cast(this)->length());
1130 break;
1131 case EXTERNAL_FLOAT_ARRAY_TYPE:
1132 accumulator->Add("<ExternalFloatArray[%u]>",
1133 ExternalFloatArray::cast(this)->length());
1134 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001135 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1136 accumulator->Add("<ExternalDoubleArray[%u]>",
1137 ExternalDoubleArray::cast(this)->length());
1138 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001139 case SHARED_FUNCTION_INFO_TYPE:
1140 accumulator->Add("<SharedFunctionInfo>");
1141 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001142 case JS_MESSAGE_OBJECT_TYPE:
1143 accumulator->Add("<JSMessageObject>");
1144 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001145#define MAKE_STRUCT_CASE(NAME, Name, name) \
1146 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001147 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001149 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 break;
1151 STRUCT_LIST(MAKE_STRUCT_CASE)
1152#undef MAKE_STRUCT_CASE
1153 case CODE_TYPE:
1154 accumulator->Add("<Code>");
1155 break;
1156 case ODDBALL_TYPE: {
1157 if (IsUndefined())
1158 accumulator->Add("<undefined>");
1159 else if (IsTheHole())
1160 accumulator->Add("<the hole>");
1161 else if (IsNull())
1162 accumulator->Add("<null>");
1163 else if (IsTrue())
1164 accumulator->Add("<true>");
1165 else if (IsFalse())
1166 accumulator->Add("<false>");
1167 else
1168 accumulator->Add("<Odd Oddball>");
1169 break;
1170 }
1171 case HEAP_NUMBER_TYPE:
1172 accumulator->Add("<Number: ");
1173 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1174 accumulator->Put('>');
1175 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001176 case FOREIGN_TYPE:
1177 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001179 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1180 accumulator->Add("Cell for ");
1181 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1182 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 default:
1184 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1185 break;
1186 }
1187}
1188
1189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190void HeapObject::Iterate(ObjectVisitor* v) {
1191 // Handle header
1192 IteratePointer(v, kMapOffset);
1193 // Handle object body
1194 Map* m = map();
1195 IterateBody(m->instance_type(), SizeFromMap(m), v);
1196}
1197
1198
1199void HeapObject::IterateBody(InstanceType type, int object_size,
1200 ObjectVisitor* v) {
1201 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1202 // During GC, the map pointer field is encoded.
1203 if (type < FIRST_NONSTRING_TYPE) {
1204 switch (type & kStringRepresentationMask) {
1205 case kSeqStringTag:
1206 break;
1207 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001208 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001209 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001210 case kExternalStringTag:
1211 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1212 reinterpret_cast<ExternalAsciiString*>(this)->
1213 ExternalAsciiStringIterateBody(v);
1214 } else {
1215 reinterpret_cast<ExternalTwoByteString*>(this)->
1216 ExternalTwoByteStringIterateBody(v);
1217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218 break;
1219 }
1220 return;
1221 }
1222
1223 switch (type) {
1224 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001225 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001227 case FIXED_DOUBLE_ARRAY_TYPE:
1228 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001230 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231 case JS_VALUE_TYPE:
1232 case JS_ARRAY_TYPE:
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001233 case JS_WEAK_MAP_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001234 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001235 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001237 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001238 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001239 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001241 case JS_FUNCTION_TYPE:
1242 reinterpret_cast<JSFunction*>(this)
1243 ->JSFunctionIterateBody(object_size, v);
1244 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001246 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001248 case JS_PROXY_TYPE:
1249 JSProxy::BodyDescriptor::IterateBody(this, v);
1250 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001251 case FOREIGN_TYPE:
1252 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001253 break;
1254 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001255 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 break;
1257 case CODE_TYPE:
1258 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1259 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001260 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001261 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001262 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 case HEAP_NUMBER_TYPE:
1264 case FILLER_TYPE:
1265 case BYTE_ARRAY_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001266 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001267 case EXTERNAL_BYTE_ARRAY_TYPE:
1268 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1269 case EXTERNAL_SHORT_ARRAY_TYPE:
1270 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1271 case EXTERNAL_INT_ARRAY_TYPE:
1272 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1273 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001274 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001276 case SHARED_FUNCTION_INFO_TYPE:
1277 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001279
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001280#define MAKE_STRUCT_CASE(NAME, Name, name) \
1281 case NAME##_TYPE:
1282 STRUCT_LIST(MAKE_STRUCT_CASE)
1283#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001284 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 break;
1286 default:
1287 PrintF("Unknown type: %d\n", type);
1288 UNREACHABLE();
1289 }
1290}
1291
1292
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001293Object* HeapNumber::HeapNumberToBoolean() {
1294 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001295#if __BYTE_ORDER == __LITTLE_ENDIAN
1296 union IeeeDoubleLittleEndianArchType u;
1297#elif __BYTE_ORDER == __BIG_ENDIAN
1298 union IeeeDoubleBigEndianArchType u;
1299#endif
1300 u.d = value();
1301 if (u.bits.exp == 2047) {
1302 // Detect NaN for IEEE double precision floating point.
1303 if ((u.bits.man_low | u.bits.man_high) != 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001304 return GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001306 if (u.bits.exp == 0) {
1307 // Detect +0, and -0 for IEEE double precision floating point.
1308 if ((u.bits.man_low | u.bits.man_high) == 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 return GetHeap()->false_value();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001310 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312}
1313
1314
whesse@chromium.org023421e2010-12-21 12:19:12 +00001315void HeapNumber::HeapNumberPrint(FILE* out) {
1316 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001317}
1318
1319
1320void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1321 // The Windows version of vsnprintf can allocate when printing a %g string
1322 // into a buffer that may not be big enough. We don't want random memory
1323 // allocation when producing post-crash stack traces, so we print into a
1324 // buffer that is plenty big enough for any floating point number, then
1325 // print that using vsnprintf (which may truncate but never allocate if
1326 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001327 EmbeddedVector<char, 100> buffer;
1328 OS::SNPrintF(buffer, "%.16g", Number());
1329 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330}
1331
1332
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001333String* JSReceiver::class_name() {
1334 if (IsJSFunction() && IsJSFunctionProxy()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001335 return GetHeap()->function_class_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001336 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337 if (map()->constructor()->IsJSFunction()) {
1338 JSFunction* constructor = JSFunction::cast(map()->constructor());
1339 return String::cast(constructor->shared()->instance_class_name());
1340 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001341 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001342 return GetHeap()->Object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343}
1344
1345
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001346String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001347 if (map()->constructor()->IsJSFunction()) {
1348 JSFunction* constructor = JSFunction::cast(map()->constructor());
1349 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001350 if (name->length() > 0) return name;
1351 String* inferred_name = constructor->shared()->inferred_name();
1352 if (inferred_name->length() > 0) return inferred_name;
1353 Object* proto = GetPrototype();
1354 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001355 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001356 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001357 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001358 return GetHeap()->Object_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001359}
1360
1361
lrn@chromium.org303ada72010-10-27 09:33:13 +00001362MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1363 String* name,
1364 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 int index = new_map->PropertyIndexFor(name);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001366 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001367 ASSERT(map()->unused_property_fields() == 0);
1368 int new_unused = new_map->unused_property_fields();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001369 Object* values;
1370 { MaybeObject* maybe_values =
1371 properties()->CopySize(properties()->length() + new_unused + 1);
1372 if (!maybe_values->ToObject(&values)) return maybe_values;
1373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001374 set_properties(FixedArray::cast(values));
1375 }
1376 set_map(new_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001378}
1379
1380
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001381static bool IsIdentifier(UnicodeCache* cache,
1382 unibrow::CharacterStream* buffer) {
1383 // Checks whether the buffer contains an identifier (no escape).
1384 if (!buffer->has_more()) return false;
1385 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1386 return false;
1387 }
1388 while (buffer->has_more()) {
1389 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1390 return false;
1391 }
1392 }
1393 return true;
1394}
1395
1396
lrn@chromium.org303ada72010-10-27 09:33:13 +00001397MaybeObject* JSObject::AddFastProperty(String* name,
1398 Object* value,
1399 PropertyAttributes attributes) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001400 ASSERT(!IsJSGlobalProxy());
1401
ager@chromium.org8c51fc92009-04-22 11:54:55 +00001402 // Normalize the object if the name is an actual string (not the
1403 // hidden symbols) and is not a real identifier.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001404 Isolate* isolate = GetHeap()->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 StringInputBuffer buffer(name);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001406 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001407 && name != isolate->heap()->hidden_symbol()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001408 Object* obj;
1409 { MaybeObject* maybe_obj =
1410 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1411 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1412 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413 return AddSlowProperty(name, value, attributes);
1414 }
1415
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001416 DescriptorArray* old_descriptors = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417 // Compute the new index for new field.
1418 int index = map()->NextFreePropertyIndex();
1419
1420 // Allocate new instance descriptors with (name, index) added
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001421 FieldDescriptor new_field(name, index, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001422 Object* new_descriptors;
1423 { MaybeObject* maybe_new_descriptors =
1424 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1425 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1426 return maybe_new_descriptors;
1427 }
1428 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001430 // Only allow map transition if the object isn't the global object and there
1431 // is not a transition for the name, or there's a transition for the name but
1432 // it's unrelated to properties.
1433 int descriptor_index = old_descriptors->Search(name);
1434
1435 // External array transitions are stored in the descriptor for property "",
1436 // which is not a identifier and should have forced a switch to slow
1437 // properties above.
1438 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1439 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1440 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1441 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442 bool allow_map_transition =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001443 can_insert_transition &&
1444 (isolate->context()->global_context()->object_function()->map() != map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445
ager@chromium.org7c537e22008-10-16 08:43:32 +00001446 ASSERT(index < map()->inobject_properties() ||
1447 (index - map()->inobject_properties()) < properties()->length() ||
1448 map()->unused_property_fields() == 0);
1449 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001450 Object* r;
1451 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1452 if (!maybe_r->ToObject(&r)) return maybe_r;
1453 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001454 Map* new_map = Map::cast(r);
1455 if (allow_map_transition) {
1456 // Allocate new instance descriptors for the old map with map transition.
1457 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001458 Object* r;
1459 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1460 if (!maybe_r->ToObject(&r)) return maybe_r;
1461 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001462 old_descriptors = DescriptorArray::cast(r);
1463 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464
ager@chromium.org7c537e22008-10-16 08:43:32 +00001465 if (map()->unused_property_fields() == 0) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001466 if (properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001467 Object* obj;
1468 { MaybeObject* maybe_obj =
1469 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1470 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1471 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 return AddSlowProperty(name, value, attributes);
1473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474 // Make room for the new value
lrn@chromium.org303ada72010-10-27 09:33:13 +00001475 Object* values;
1476 { MaybeObject* maybe_values =
1477 properties()->CopySize(properties()->length() + kFieldsAdded);
1478 if (!maybe_values->ToObject(&values)) return maybe_values;
1479 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 set_properties(FixedArray::cast(values));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001481 new_map->set_unused_property_fields(kFieldsAdded - 1);
1482 } else {
1483 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001484 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001485 // We have now allocated all the necessary objects.
1486 // All the changes can be applied at once, so they are atomic.
1487 map()->set_instance_descriptors(old_descriptors);
1488 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1489 set_map(new_map);
1490 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001491}
1492
1493
lrn@chromium.org303ada72010-10-27 09:33:13 +00001494MaybeObject* JSObject::AddConstantFunctionProperty(
1495 String* name,
1496 JSFunction* function,
1497 PropertyAttributes attributes) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001498 ASSERT(!GetHeap()->InNewSpace(function));
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001499
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 // Allocate new instance descriptors with (name, function) added
1501 ConstantFunctionDescriptor d(name, function, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001502 Object* new_descriptors;
1503 { MaybeObject* maybe_new_descriptors =
1504 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1505 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1506 return maybe_new_descriptors;
1507 }
1508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509
1510 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001511 Object* new_map;
1512 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1513 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1514 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515
1516 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1517 Map::cast(new_map)->set_instance_descriptors(descriptors);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001518 Map* old_map = map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001519 set_map(Map::cast(new_map));
1520
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001521 // If the old map is the global object map (from new Object()),
1522 // then transitions are not added to it, so we are done.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001523 Heap* heap = old_map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001524 if (old_map == heap->isolate()->context()->global_context()->
1525 object_function()->map()) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001526 return function;
1527 }
1528
1529 // Do not add CONSTANT_TRANSITIONS to global objects
1530 if (IsGlobalObject()) {
1531 return function;
1532 }
1533
1534 // Add a CONSTANT_TRANSITION descriptor to the old map,
1535 // so future assignments to this property on other objects
1536 // of the same type will create a normal field, not a constant function.
1537 // Don't do this for special properties, with non-trival attributes.
1538 if (attributes != NONE) {
1539 return function;
1540 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001541 ConstTransitionDescriptor mark(name, Map::cast(new_map));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001542 { MaybeObject* maybe_new_descriptors =
1543 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1544 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1545 // We have accomplished the main goal, so return success.
1546 return function;
1547 }
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001548 }
1549 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001551 return function;
1552}
1553
1554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555// Add property in slow mode
lrn@chromium.org303ada72010-10-27 09:33:13 +00001556MaybeObject* JSObject::AddSlowProperty(String* name,
1557 Object* value,
1558 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001559 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001560 StringDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001561 Object* store_value = value;
1562 if (IsGlobalObject()) {
1563 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001564 int entry = dict->FindEntry(name);
1565 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001566 store_value = dict->ValueAt(entry);
1567 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001568 // Assign an enumeration index to the property and update
1569 // SetNextEnumerationIndex.
1570 int index = dict->NextEnumerationIndex();
1571 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1572 dict->SetNextEnumerationIndex(index + 1);
1573 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001574 return value;
1575 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001576 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001577 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001578 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001579 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1580 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001581 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001583 PropertyDetails details = PropertyDetails(attributes, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001584 Object* result;
1585 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1586 if (!maybe_result->ToObject(&result)) return maybe_result;
1587 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001588 if (dict != result) set_properties(StringDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 return value;
1590}
1591
1592
lrn@chromium.org303ada72010-10-27 09:33:13 +00001593MaybeObject* JSObject::AddProperty(String* name,
1594 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001595 PropertyAttributes attributes,
1596 StrictModeFlag strict_mode) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001597 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001598 Map* map_of_this = map();
1599 Heap* heap = map_of_this->heap();
1600 if (!map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001601 if (strict_mode == kNonStrictMode) {
1602 return heap->undefined_value();
1603 } else {
1604 Handle<Object> args[1] = {Handle<String>(name)};
1605 return heap->isolate()->Throw(
1606 *FACTORY->NewTypeError("object_not_extensible",
1607 HandleVector(args, 1)));
1608 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001610 if (HasFastProperties()) {
1611 // Ensure the descriptor array does not get too big.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001612 if (map_of_this->instance_descriptors()->number_of_descriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 DescriptorArray::kMaxNumberOfDescriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001614 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001615 return AddConstantFunctionProperty(name,
1616 JSFunction::cast(value),
1617 attributes);
1618 } else {
1619 return AddFastProperty(name, value, attributes);
1620 }
1621 } else {
1622 // Normalize the object to prevent very large instance descriptors.
1623 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001624 Object* obj;
1625 { MaybeObject* maybe_obj =
1626 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1627 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1628 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 }
1630 }
1631 return AddSlowProperty(name, value, attributes);
1632}
1633
1634
lrn@chromium.org303ada72010-10-27 09:33:13 +00001635MaybeObject* JSObject::SetPropertyPostInterceptor(
1636 String* name,
1637 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001638 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001639 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 // Check local property, ignore interceptor.
1641 LookupResult result;
1642 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001643 if (result.IsFound()) {
1644 // An existing property, a map transition or a null descriptor was
1645 // found. Use set property to handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001646 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001647 }
1648 // Add a new real property.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001649 return AddProperty(name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650}
1651
1652
lrn@chromium.org303ada72010-10-27 09:33:13 +00001653MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1654 Object* value,
1655 PropertyAttributes attributes) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001656 StringDictionary* dictionary = property_dictionary();
1657 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001658 int new_enumeration_index = 0; // 0 means "Use the next available index."
1659 if (old_index != -1) {
1660 // All calls to ReplaceSlowProperty have had all transitions removed.
1661 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1662 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1663 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001664
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001665 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001666 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001667}
1668
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001669
lrn@chromium.org303ada72010-10-27 09:33:13 +00001670MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
ager@chromium.org7c537e22008-10-16 08:43:32 +00001671 String* name,
1672 Object* new_value,
1673 PropertyAttributes attributes) {
1674 Map* old_map = map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001675 Object* result;
1676 { MaybeObject* maybe_result =
1677 ConvertDescriptorToField(name, new_value, attributes);
1678 if (!maybe_result->ToObject(&result)) return maybe_result;
1679 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001680 // If we get to this point we have succeeded - do not return failure
1681 // after this point. Later stuff is optional.
1682 if (!HasFastProperties()) {
1683 return result;
1684 }
1685 // Do not add transitions to the map of "new Object()".
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001686 if (map() == old_map->heap()->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001687 object_function()->map()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001688 return result;
1689 }
1690
1691 MapTransitionDescriptor transition(name,
1692 map(),
1693 attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001694 Object* new_descriptors;
1695 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1696 CopyInsert(&transition, KEEP_TRANSITIONS);
1697 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1698 return result; // Yes, return _result_.
1699 }
1700 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001701 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1702 return result;
1703}
1704
1705
lrn@chromium.org303ada72010-10-27 09:33:13 +00001706MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1707 Object* new_value,
1708 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001709 if (map()->unused_property_fields() == 0 &&
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001710 properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001711 Object* obj;
1712 { MaybeObject* maybe_obj =
1713 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1714 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1715 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001716 return ReplaceSlowProperty(name, new_value, attributes);
1717 }
1718
1719 int index = map()->NextFreePropertyIndex();
1720 FieldDescriptor new_field(name, index, attributes);
1721 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001722 Object* descriptors_unchecked;
1723 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1724 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1725 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1726 return maybe_descriptors_unchecked;
1727 }
1728 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001729 DescriptorArray* new_descriptors =
1730 DescriptorArray::cast(descriptors_unchecked);
1731
1732 // Make a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001733 Object* new_map_unchecked;
1734 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1735 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1736 return maybe_new_map_unchecked;
1737 }
1738 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001739 Map* new_map = Map::cast(new_map_unchecked);
1740 new_map->set_instance_descriptors(new_descriptors);
1741
1742 // Make new properties array if necessary.
1743 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1744 int new_unused_property_fields = map()->unused_property_fields() - 1;
1745 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001746 new_unused_property_fields = kFieldsAdded - 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 Object* new_properties_object;
1748 { MaybeObject* maybe_new_properties_object =
1749 properties()->CopySize(properties()->length() + kFieldsAdded);
1750 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1751 return maybe_new_properties_object;
1752 }
1753 }
1754 new_properties = FixedArray::cast(new_properties_object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001755 }
1756
1757 // Update pointers to commit changes.
1758 // Object points to the new map.
1759 new_map->set_unused_property_fields(new_unused_property_fields);
1760 set_map(new_map);
1761 if (new_properties) {
1762 set_properties(FixedArray::cast(new_properties));
1763 }
1764 return FastPropertyAtPut(index, new_value);
1765}
1766
1767
1768
lrn@chromium.org303ada72010-10-27 09:33:13 +00001769MaybeObject* JSObject::SetPropertyWithInterceptor(
1770 String* name,
1771 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001772 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001773 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001774 Isolate* isolate = GetIsolate();
1775 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001776 Handle<JSObject> this_handle(this);
1777 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001778 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1780 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001781 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1782 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001783 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 v8::NamedPropertySetter setter =
1785 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1786 v8::Handle<v8::Value> result;
1787 {
1788 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001789 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001790 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 isolate->heap()->undefined_value() :
1792 value,
1793 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001794 result = setter(v8::Utils::ToLocal(name_handle),
1795 v8::Utils::ToLocal(value_unhole),
1796 info);
1797 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001799 if (!result.IsEmpty()) return *value_handle;
1800 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 MaybeObject* raw_result =
1802 this_handle->SetPropertyPostInterceptor(*name_handle,
1803 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001804 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001805 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 return raw_result;
1808}
1809
1810
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001811MaybeObject* JSReceiver::SetProperty(String* name,
1812 Object* value,
1813 PropertyAttributes attributes,
1814 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 LookupResult result;
1816 LocalLookup(name, &result);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001817 return SetProperty(&result, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818}
1819
1820
lrn@chromium.org303ada72010-10-27 09:33:13 +00001821MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1822 String* name,
1823 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001824 JSObject* holder,
1825 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 Isolate* isolate = GetIsolate();
1827 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828
1829 // We should never get here to initialize a const with the hole
1830 // value since a const declaration would conflict with the setter.
1831 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833
1834 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001835 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001837 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001839 reinterpret_cast<AccessorDescriptor*>(
1840 Foreign::cast(structure)->address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001841 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001842 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001843 if (obj->IsFailure()) return obj;
1844 return *value_handle;
1845 }
1846
1847 if (structure->IsAccessorInfo()) {
1848 // api style callbacks
1849 AccessorInfo* data = AccessorInfo::cast(structure);
1850 Object* call_obj = data->setter();
1851 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1852 if (call_fun == NULL) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001854 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1855 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001856 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001857 {
1858 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001860 call_fun(v8::Utils::ToLocal(key),
1861 v8::Utils::ToLocal(value_handle),
1862 info);
1863 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001864 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865 return *value_handle;
1866 }
1867
1868 if (structure->IsFixedArray()) {
1869 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1870 if (setter->IsJSFunction()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001871 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001873 if (strict_mode == kNonStrictMode) {
1874 return value;
1875 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001877 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001878 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001879 return isolate->Throw(
1880 *isolate->factory()->NewTypeError("no_setter_in_callback",
1881 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001882 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001883 }
1884
1885 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001886 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001887}
1888
1889
lrn@chromium.org303ada72010-10-27 09:33:13 +00001890MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1891 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001892 Isolate* isolate = GetIsolate();
1893 Handle<Object> value_handle(value, isolate);
1894 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1895 Handle<JSObject> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001896#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001897 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001898 // Handle stepping into a setter if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001899 if (debug->StepInActive()) {
1900 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001901 }
1902#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001903 bool has_pending_exception;
1904 Object** argv[] = { value_handle.location() };
1905 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1906 // Check for pending exception and return the result.
1907 if (has_pending_exception) return Failure::Exception();
1908 return *value_handle;
1909}
1910
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001912void JSObject::LookupCallbackSetterInPrototypes(String* name,
1913 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001914 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001916 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001917 pt = pt->GetPrototype()) {
1918 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001919 if (result->IsProperty()) {
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001920 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
1921 // Found non-callback or read-only callback, stop looking.
1922 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001923 }
1924 }
1925 result->NotFound();
1926}
1927
1928
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001929MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1930 uint32_t index,
1931 Object* value,
1932 bool* found,
1933 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001935 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001936 pt != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001937 pt = pt->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001938 if (!JSObject::cast(pt)->HasDictionaryElements()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001939 continue;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001940 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001941 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1942 int entry = dictionary->FindEntry(index);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001943 if (entry != NumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001944 PropertyDetails details = dictionary->DetailsAt(entry);
1945 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001946 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001947 return SetElementWithCallback(dictionary->ValueAt(entry),
1948 index,
1949 value,
1950 JSObject::cast(pt),
1951 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001952 }
1953 }
1954 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001955 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001956 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001957}
1958
1959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1961 DescriptorArray* descriptors = map()->instance_descriptors();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001962 int number = descriptors->SearchWithCache(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963 if (number != DescriptorArray::kNotFound) {
1964 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1965 } else {
1966 result->NotFound();
1967 }
1968}
1969
1970
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001971void Map::LookupInDescriptors(JSObject* holder,
1972 String* name,
1973 LookupResult* result) {
1974 DescriptorArray* descriptors = instance_descriptors();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001975 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1976 int number = cache->Lookup(descriptors, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001977 if (number == DescriptorLookupCache::kAbsent) {
1978 number = descriptors->Search(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 cache->Update(descriptors, name, number);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001980 }
1981 if (number != DescriptorArray::kNotFound) {
1982 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1983 } else {
1984 result->NotFound();
1985 }
1986}
1987
1988
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00001989static JSObject::ElementsKind GetElementsKindFromExternalArrayType(
1990 ExternalArrayType array_type) {
1991 switch (array_type) {
1992 case kExternalByteArray:
1993 return JSObject::EXTERNAL_BYTE_ELEMENTS;
1994 break;
1995 case kExternalUnsignedByteArray:
1996 return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
1997 break;
1998 case kExternalShortArray:
1999 return JSObject::EXTERNAL_SHORT_ELEMENTS;
2000 break;
2001 case kExternalUnsignedShortArray:
2002 return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
2003 break;
2004 case kExternalIntArray:
2005 return JSObject::EXTERNAL_INT_ELEMENTS;
2006 break;
2007 case kExternalUnsignedIntArray:
2008 return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS;
2009 break;
2010 case kExternalFloatArray:
2011 return JSObject::EXTERNAL_FLOAT_ELEMENTS;
2012 break;
2013 case kExternalDoubleArray:
2014 return JSObject::EXTERNAL_DOUBLE_ELEMENTS;
2015 break;
2016 case kExternalPixelArray:
2017 return JSObject::EXTERNAL_PIXEL_ELEMENTS;
2018 break;
2019 }
2020 UNREACHABLE();
2021 return JSObject::DICTIONARY_ELEMENTS;
2022}
2023
2024
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002025MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
2026 bool safe_to_add_transition) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002027 Heap* current_heap = heap();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002028 DescriptorArray* descriptors = instance_descriptors();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002029 String* external_array_sentinel_name = current_heap->empty_symbol();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002030
2031 if (safe_to_add_transition) {
2032 // It's only safe to manipulate the descriptor array if it would be
2033 // safe to add a transition.
2034
2035 ASSERT(!is_shared()); // no transitions can be added to shared maps.
2036 // Check if the external array transition already exists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002037 DescriptorLookupCache* cache =
2038 current_heap->isolate()->descriptor_lookup_cache();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002039 int index = cache->Lookup(descriptors, external_array_sentinel_name);
2040 if (index == DescriptorLookupCache::kAbsent) {
2041 index = descriptors->Search(external_array_sentinel_name);
2042 cache->Update(descriptors,
2043 external_array_sentinel_name,
2044 index);
2045 }
2046
2047 // If the transition already exists, check the type. If there is a match,
2048 // return it.
2049 if (index != DescriptorArray::kNotFound) {
2050 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
2051 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
2052 details.array_type() == array_type) {
2053 return descriptors->GetValue(index);
2054 } else {
2055 safe_to_add_transition = false;
2056 }
2057 }
2058 }
2059
2060 // No transition to an existing external array map. Make a new one.
2061 Object* obj;
2062 { MaybeObject* maybe_map = CopyDropTransitions();
2063 if (!maybe_map->ToObject(&obj)) return maybe_map;
2064 }
2065 Map* new_map = Map::cast(obj);
2066
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00002067 new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002068 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
2069
2070 // Only remember the map transition if the object's map is NOT equal to the
2071 // global object_function's map and there is not an already existing
2072 // non-matching external array transition.
2073 bool allow_map_transition =
2074 safe_to_add_transition &&
2075 (GetIsolate()->context()->global_context()->object_function()->map() !=
2076 map());
2077 if (allow_map_transition) {
2078 // Allocate new instance descriptors for the old map with map transition.
2079 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
2080 Map::cast(new_map),
2081 array_type);
2082 Object* new_descriptors;
2083 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2084 &desc,
2085 KEEP_TRANSITIONS);
2086 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2087 return maybe_new_descriptors;
2088 }
2089 descriptors = DescriptorArray::cast(new_descriptors);
2090 set_instance_descriptors(descriptors);
2091 }
2092
2093 return new_map;
2094}
2095
2096
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002097void JSObject::LocalLookupRealNamedProperty(String* name,
2098 LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002099 if (IsJSGlobalProxy()) {
2100 Object* proto = GetPrototype();
2101 if (proto->IsNull()) return result->NotFound();
2102 ASSERT(proto->IsJSGlobalObject());
2103 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2104 }
2105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002106 if (HasFastProperties()) {
2107 LookupInDescriptor(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002108 if (result->IsFound()) {
2109 // A property, a map transition or a null descriptor was found.
2110 // We return all of these result types because
2111 // LocalLookupRealNamedProperty is used when setting properties
2112 // where map transitions and null descriptors are handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002113 ASSERT(result->holder() == this && result->type() != NORMAL);
2114 // Disallow caching for uninitialized constants. These can only
2115 // occur as fields.
2116 if (result->IsReadOnly() && result->type() == FIELD &&
ager@chromium.org7c537e22008-10-16 08:43:32 +00002117 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002118 result->DisallowCaching();
2119 }
2120 return;
2121 }
2122 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002123 int entry = property_dictionary()->FindEntry(name);
2124 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002125 Object* value = property_dictionary()->ValueAt(entry);
2126 if (IsGlobalObject()) {
2127 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2128 if (d.IsDeleted()) {
2129 result->NotFound();
2130 return;
2131 }
2132 value = JSGlobalPropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002133 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002134 // Make sure to disallow caching for uninitialized constants
2135 // found in the dictionary-mode objects.
2136 if (value->IsTheHole()) result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 result->DictionaryResult(this, entry);
2138 return;
2139 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002140 }
2141 result->NotFound();
2142}
2143
2144
2145void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2146 LocalLookupRealNamedProperty(name, result);
2147 if (result->IsProperty()) return;
2148
2149 LookupRealNamedPropertyInPrototypes(name, result);
2150}
2151
2152
2153void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2154 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002155 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002157 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 pt = JSObject::cast(pt)->GetPrototype()) {
2159 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002160 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002161 }
2162 result->NotFound();
2163}
2164
2165
2166// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002167MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2168 LookupResult* result,
2169 String* name,
2170 Object* value,
2171 bool check_prototype,
2172 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002173 if (check_prototype && !result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002174 LookupCallbackSetterInPrototypes(name, result);
2175 }
2176
2177 if (result->IsProperty()) {
2178 if (!result->IsReadOnly()) {
2179 switch (result->type()) {
2180 case CALLBACKS: {
2181 Object* obj = result->GetCallbackObject();
2182 if (obj->IsAccessorInfo()) {
2183 AccessorInfo* info = AccessorInfo::cast(obj);
2184 if (info->all_can_write()) {
2185 return SetPropertyWithCallback(result->GetCallbackObject(),
2186 name,
2187 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002188 result->holder(),
2189 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 }
2191 }
2192 break;
2193 }
2194 case INTERCEPTOR: {
2195 // Try lookup real named properties. Note that only property can be
2196 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2197 LookupResult r;
2198 LookupRealNamedProperty(name, &r);
2199 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002200 return SetPropertyWithFailedAccessCheck(&r,
2201 name,
2202 value,
2203 check_prototype,
2204 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002205 }
2206 break;
2207 }
2208 default: {
2209 break;
2210 }
2211 }
2212 }
2213 }
2214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002215 Heap* heap = GetHeap();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002216 HandleScope scope(heap->isolate());
2217 Handle<Object> value_handle(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002218 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002219 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002220}
2221
2222
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002223MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2224 String* key,
2225 Object* value,
2226 PropertyAttributes attributes,
2227 StrictModeFlag strict_mode) {
2228 if (result->IsFound() && result->type() == HANDLER) {
2229 return JSProxy::cast(this)->SetPropertyWithHandler(
2230 key, value, attributes, strict_mode);
2231 } else {
2232 return JSObject::cast(this)->SetPropertyForResult(
2233 result, key, value, attributes, strict_mode);
2234 }
2235}
2236
2237
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002238bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2239 Isolate* isolate = GetIsolate();
2240 HandleScope scope(isolate);
2241 Handle<Object> receiver(this);
2242 Handle<Object> name(name_raw);
2243 Handle<Object> handler(this->handler());
2244
2245 // Extract trap function.
2246 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
2247 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2248 if (trap->IsUndefined()) {
2249 trap = isolate->derived_has_trap();
2250 }
2251
2252 // Call trap function.
2253 Object** args[] = { name.location() };
2254 bool has_exception;
2255 Handle<Object> result =
2256 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2257 if (has_exception) return Failure::Exception();
2258
2259 return result->ToBoolean()->IsTrue();
2260}
2261
2262
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002263MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2264 String* name_raw,
2265 Object* value_raw,
2266 PropertyAttributes attributes,
2267 StrictModeFlag strict_mode) {
2268 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002269 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002270 Handle<Object> receiver(this);
2271 Handle<Object> name(name_raw);
2272 Handle<Object> value(value_raw);
2273 Handle<Object> handler(this->handler());
2274
2275 // Extract trap function.
2276 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2277 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2278 if (trap->IsUndefined()) {
2279 trap = isolate->derived_set_trap();
2280 }
2281
2282 // Call trap function.
2283 Object** args[] = {
2284 receiver.location(), name.location(), value.location()
2285 };
2286 bool has_exception;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002287 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002288 if (has_exception) return Failure::Exception();
2289
ager@chromium.org04921a82011-06-27 13:21:41 +00002290 return *value;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002291}
2292
2293
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002294MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2295 String* name_raw, DeleteMode mode) {
2296 Isolate* isolate = GetIsolate();
2297 HandleScope scope(isolate);
2298 Handle<Object> receiver(this);
2299 Handle<Object> name(name_raw);
2300 Handle<Object> handler(this->handler());
2301
2302 // Extract trap function.
2303 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2304 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2305 if (trap->IsUndefined()) {
2306 Handle<Object> args[] = { handler, trap_name };
2307 Handle<Object> error = isolate->factory()->NewTypeError(
2308 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2309 isolate->Throw(*error);
2310 return Failure::Exception();
2311 }
2312
2313 // Call trap function.
2314 Object** args[] = { name.location() };
2315 bool has_exception;
2316 Handle<Object> result =
2317 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2318 if (has_exception) return Failure::Exception();
2319
2320 Object* bool_result = result->ToBoolean();
2321 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2322 Handle<Object> args[] = { handler, trap_name };
2323 Handle<Object> error = isolate->factory()->NewTypeError(
2324 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2325 isolate->Throw(*error);
2326 return Failure::Exception();
2327 }
2328 return bool_result;
2329}
2330
2331
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002332MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2333 JSReceiver* receiver_raw,
2334 String* name_raw,
2335 bool* has_exception) {
2336 Isolate* isolate = GetIsolate();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002337 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002338 Handle<JSReceiver> receiver(receiver_raw);
2339 Handle<Object> name(name_raw);
2340 Handle<Object> handler(this->handler());
2341
2342 // Extract trap function.
2343 Handle<String> trap_name =
2344 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2345 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2346 if (trap->IsUndefined()) {
2347 Handle<Object> args[] = { handler, trap_name };
2348 Handle<Object> error = isolate->factory()->NewTypeError(
2349 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2350 isolate->Throw(*error);
2351 *has_exception = true;
2352 return NONE;
2353 }
2354
2355 // Call trap function.
2356 Object** args[] = { name.location() };
2357 Handle<Object> result =
2358 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2359 if (has_exception) return NONE;
2360
2361 // TODO(rossberg): convert result to PropertyAttributes
2362 USE(result);
2363 return NONE;
2364}
2365
2366
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002367void JSProxy::Fix() {
2368 Isolate* isolate = GetIsolate();
2369 HandleScope scope(isolate);
2370 Handle<JSProxy> self(this);
2371
2372 isolate->factory()->BecomeJSObject(self);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002373 ASSERT(self->IsJSObject());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00002374 // TODO(rossberg): recognize function proxies.
2375}
2376
2377
2378
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002379MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002380 String* name,
2381 Object* value,
2382 PropertyAttributes attributes,
2383 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002384 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002385 // Make sure that the top context does not change when doing callbacks or
2386 // interceptor calls.
2387 AssertNoContextChange ncc;
2388
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002389 // Optimization for 2-byte strings often used as keys in a decompression
2390 // dictionary. We make these short keys into symbols to avoid constantly
2391 // reallocating them.
2392 if (!name->IsSymbol() && name->length() <= 2) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002393 Object* symbol_version;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002394 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002395 if (maybe_symbol_version->ToObject(&symbol_version)) {
2396 name = String::cast(symbol_version);
2397 }
2398 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002399 }
2400
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002401 // Check access rights if needed.
2402 if (IsAccessCheckNeeded()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002403 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002404 return SetPropertyWithFailedAccessCheck(result,
2405 name,
2406 value,
2407 true,
2408 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002409 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002410
2411 if (IsJSGlobalProxy()) {
2412 Object* proto = GetPrototype();
2413 if (proto->IsNull()) return value;
2414 ASSERT(proto->IsJSGlobalObject());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002415 return JSObject::cast(proto)->SetProperty(
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002416 result, name, value, attributes, strict_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002417 }
2418
ager@chromium.org32912102009-01-16 10:38:43 +00002419 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002420 // We could not find a local property so let's check whether there is an
2421 // accessor that wants to handle the property.
2422 LookupResult accessor_result;
2423 LookupCallbackSetterInPrototypes(name, &accessor_result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002424 if (accessor_result.IsProperty()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002425 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2426 name,
2427 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002428 accessor_result.holder(),
2429 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002430 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002431 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002432 if (!result->IsFound()) {
2433 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002434 return AddProperty(name, value, attributes, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002435 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002436 if (result->IsReadOnly() && result->IsProperty()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002437 if (strict_mode == kStrictMode) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002438 HandleScope scope(heap->isolate());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002439 Handle<String> key(name);
2440 Handle<Object> holder(this);
2441 Handle<Object> args[2] = { key, holder };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002442 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2443 "strict_read_only_property", HandleVector(args, 2)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002444 } else {
2445 return value;
2446 }
2447 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002448 // This is a real property that is not read-only, or it is a
2449 // transition or null descriptor and there are no setters in the prototypes.
2450 switch (result->type()) {
2451 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002452 return SetNormalizedProperty(result, value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002453 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002454 return FastPropertyAtPut(result->GetFieldIndex(), value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002455 case MAP_TRANSITION:
2456 if (attributes == result->GetAttributes()) {
2457 // Only use map transition if the attributes match.
2458 return AddFastPropertyUsingMap(result->GetTransitionMap(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002459 name,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002460 value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002461 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002462 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002463 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002464 // Only replace the function if necessary.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002465 if (value == result->GetConstantFunction()) return value;
2466 // Preserve the attributes of this existing property.
2467 attributes = result->GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002468 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002469 case CALLBACKS:
2470 return SetPropertyWithCallback(result->GetCallbackObject(),
2471 name,
2472 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002473 result->holder(),
2474 strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002475 case INTERCEPTOR:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002476 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002477 case CONSTANT_TRANSITION: {
2478 // If the same constant function is being added we can simply
2479 // transition to the target map.
2480 Map* target_map = result->GetTransitionMap();
2481 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2482 int number = target_descriptors->SearchWithCache(name);
2483 ASSERT(number != DescriptorArray::kNotFound);
2484 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2485 JSFunction* function =
2486 JSFunction::cast(target_descriptors->GetValue(number));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002487 ASSERT(!HEAP->InNewSpace(function));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002488 if (value == function) {
2489 set_map(target_map);
2490 return value;
2491 }
2492 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2493 // FIELD, even if the value is a constant function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002494 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002495 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002496 case NULL_DESCRIPTOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002497 case EXTERNAL_ARRAY_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002498 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002499 default:
2500 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002501 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002502 UNREACHABLE();
2503 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504}
2505
2506
2507// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002508// present, add it with attributes NONE. This code is an exact clone of
2509// SetProperty, with the check for IsReadOnly and the check for a
2510// callback setter removed. The two lines looking up the LookupResult
2511// result are also added. If one of the functions is changed, the other
2512// should be.
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002513// Note that this method cannot be used to set the prototype of a function
2514// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
2515// doesn't handle function prototypes correctly.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002516MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002517 String* name,
2518 Object* value,
2519 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002520
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002521 // Make sure that the top context does not change when doing callbacks or
2522 // interceptor calls.
2523 AssertNoContextChange ncc;
ager@chromium.org5c838252010-02-19 08:53:10 +00002524 LookupResult result;
2525 LocalLookup(name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002526 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002527 if (IsAccessCheckNeeded()) {
2528 Heap* heap = GetHeap();
2529 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002530 return SetPropertyWithFailedAccessCheck(&result,
2531 name,
2532 value,
2533 false,
2534 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002536 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002537
2538 if (IsJSGlobalProxy()) {
2539 Object* proto = GetPrototype();
2540 if (proto->IsNull()) return value;
2541 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002542 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002543 name,
2544 value,
2545 attributes);
2546 }
2547
ager@chromium.org7c537e22008-10-16 08:43:32 +00002548 // Check for accessor in prototype chain removed here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002549 if (!result.IsFound()) {
2550 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002551 return AddProperty(name, value, attributes, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002553
ager@chromium.org5c838252010-02-19 08:53:10 +00002554 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2555
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002556 // Check of IsReadOnly removed from here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002557 switch (result.type()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002558 case NORMAL:
ager@chromium.org5c838252010-02-19 08:53:10 +00002559 return SetNormalizedProperty(name, value, details);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002560 case FIELD:
ager@chromium.org5c838252010-02-19 08:53:10 +00002561 return FastPropertyAtPut(result.GetFieldIndex(), value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002562 case MAP_TRANSITION:
ager@chromium.org5c838252010-02-19 08:53:10 +00002563 if (attributes == result.GetAttributes()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002564 // Only use map transition if the attributes match.
ager@chromium.org5c838252010-02-19 08:53:10 +00002565 return AddFastPropertyUsingMap(result.GetTransitionMap(),
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002566 name,
2567 value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002568 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002569 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002570 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002571 // Only replace the function if necessary.
ager@chromium.org5c838252010-02-19 08:53:10 +00002572 if (value == result.GetConstantFunction()) return value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002573 // Preserve the attributes of this existing property.
ager@chromium.org5c838252010-02-19 08:53:10 +00002574 attributes = result.GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002575 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002576 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002577 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002578 // Override callback in clone
2579 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002580 case CONSTANT_TRANSITION:
2581 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2582 // if the value is a function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002583 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002584 case NULL_DESCRIPTOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002585 case EXTERNAL_ARRAY_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002586 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002587 default:
2588 UNREACHABLE();
2589 }
2590 UNREACHABLE();
2591 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002592}
2593
2594
2595PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2596 JSObject* receiver,
2597 String* name,
2598 bool continue_search) {
2599 // Check local property, ignore interceptor.
2600 LookupResult result;
2601 LocalLookupRealNamedProperty(name, &result);
kasper.lund44510672008-07-25 07:37:58 +00002602 if (result.IsProperty()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002603
2604 if (continue_search) {
2605 // Continue searching via the prototype chain.
2606 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002607 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 return JSObject::cast(pt)->
2609 GetPropertyAttributeWithReceiver(receiver, name);
2610 }
2611 }
2612 return ABSENT;
2613}
2614
2615
2616PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2617 JSObject* receiver,
2618 String* name,
2619 bool continue_search) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002620 Isolate* isolate = GetIsolate();
2621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002622 // Make sure that the top context does not change when doing
2623 // callbacks or interceptor calls.
2624 AssertNoContextChange ncc;
2625
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002626 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002627 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2628 Handle<JSObject> receiver_handle(receiver);
2629 Handle<JSObject> holder_handle(this);
2630 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002631 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002632 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002633 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002634 v8::NamedPropertyQuery query =
2635 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002636 LOG(isolate,
2637 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002638 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002639 {
2640 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002641 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002642 result = query(v8::Utils::ToLocal(name_handle), info);
2643 }
2644 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002645 ASSERT(result->IsInt32());
2646 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002647 }
2648 } else if (!interceptor->getter()->IsUndefined()) {
2649 v8::NamedPropertyGetter getter =
2650 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002651 LOG(isolate,
2652 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653 v8::Handle<v8::Value> result;
2654 {
2655 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002656 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002657 result = getter(v8::Utils::ToLocal(name_handle), info);
2658 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002659 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660 }
2661 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2662 *name_handle,
2663 continue_search);
2664}
2665
2666
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002667PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2668 JSReceiver* receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002669 String* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002670 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002671 if (IsJSObject() && key->AsArrayIndex(&index)) {
2672 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2673 return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002674 return ABSENT;
2675 }
2676 // Named property.
2677 LookupResult result;
2678 Lookup(key, &result);
2679 return GetPropertyAttribute(receiver, &result, key, true);
2680}
2681
2682
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002683PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2684 LookupResult* result,
2685 String* name,
2686 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002687 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002688 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002689 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002690 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002691 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2692 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2693 receiver, result, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002695 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002696 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 switch (result->type()) {
2698 case NORMAL: // fall through
2699 case FIELD:
2700 case CONSTANT_FUNCTION:
2701 case CALLBACKS:
2702 return result->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002703 case HANDLER: {
2704 // TODO(rossberg): propagate exceptions properly.
2705 bool has_exception = false;
2706 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2707 receiver, name, &has_exception);
2708 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002709 case INTERCEPTOR:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002710 return result->holder()->GetPropertyAttributeWithInterceptor(
2711 JSObject::cast(receiver), name, continue_search);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002713 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714 }
2715 }
2716 return ABSENT;
2717}
2718
2719
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002720PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002722 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002723 if (IsJSObject() && name->AsArrayIndex(&index)) {
2724 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002725 return ABSENT;
2726 }
2727 // Named property.
2728 LookupResult result;
2729 LocalLookup(name, &result);
2730 return GetPropertyAttribute(this, &result, name, false);
2731}
2732
2733
lrn@chromium.org303ada72010-10-27 09:33:13 +00002734MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2735 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002736 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002737 Map* fast = obj->map();
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002738 int index = fast->Hash() % kEntries;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002739 Object* result = get(index);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002740 if (result->IsMap() &&
2741 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002742#ifdef DEBUG
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002743 Map::cast(result)->SharedMapVerify();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002744 if (FLAG_enable_slow_asserts) {
2745 // The cached map should match newly created normalized map bit-by-bit.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002746 Object* fresh;
2747 { MaybeObject* maybe_fresh =
2748 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2749 if (maybe_fresh->ToObject(&fresh)) {
2750 ASSERT(memcmp(Map::cast(fresh)->address(),
2751 Map::cast(result)->address(),
2752 Map::kSize) == 0);
2753 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002754 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002755 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002756#endif
2757 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002758 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002759
lrn@chromium.org303ada72010-10-27 09:33:13 +00002760 { MaybeObject* maybe_result =
2761 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2762 if (!maybe_result->ToObject(&result)) return maybe_result;
2763 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002764 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002765 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002766
2767 return result;
2768}
2769
2770
ricow@chromium.org65fae842010-08-25 15:26:24 +00002771void NormalizedMapCache::Clear() {
2772 int entries = length();
2773 for (int i = 0; i != entries; i++) {
2774 set_undefined(i);
2775 }
2776}
2777
2778
lrn@chromium.org303ada72010-10-27 09:33:13 +00002779MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002780 if (map()->is_shared()) {
2781 // Fast case maps are never marked as shared.
2782 ASSERT(!HasFastProperties());
2783 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002784 Object* obj;
2785 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2786 UNIQUE_NORMALIZED_MAP);
2787 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2788 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002789 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002790
2791 set_map(Map::cast(obj));
2792 }
2793 return map()->UpdateCodeCache(name, code);
2794}
2795
2796
lrn@chromium.org303ada72010-10-27 09:33:13 +00002797MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2798 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002799 if (!HasFastProperties()) return this;
2800
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002801 // The global object is always normalized.
2802 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002803 // JSGlobalProxy must never be normalized
2804 ASSERT(!IsJSGlobalProxy());
2805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002806 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002807
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002808 // Allocate new content.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002809 int property_count = map_of_this->NumberOfDescribedProperties();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002810 if (expected_additional_properties > 0) {
2811 property_count += expected_additional_properties;
2812 } else {
2813 property_count += 2; // Make space for two more properties.
2814 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002815 Object* obj;
2816 { MaybeObject* maybe_obj =
2817 StringDictionary::Allocate(property_count);
2818 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2819 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002820 StringDictionary* dictionary = StringDictionary::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002821
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002822 DescriptorArray* descs = map_of_this->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002823 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002824 PropertyDetails details(descs->GetDetails(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002825 switch (details.type()) {
2826 case CONSTANT_FUNCTION: {
2827 PropertyDetails d =
2828 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002829 Object* value = descs->GetConstantFunction(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002830 Object* result;
2831 { MaybeObject* maybe_result =
2832 dictionary->Add(descs->GetKey(i), value, d);
2833 if (!maybe_result->ToObject(&result)) return maybe_result;
2834 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002835 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002836 break;
2837 }
2838 case FIELD: {
2839 PropertyDetails d =
2840 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002841 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
lrn@chromium.org303ada72010-10-27 09:33:13 +00002842 Object* result;
2843 { MaybeObject* maybe_result =
2844 dictionary->Add(descs->GetKey(i), value, d);
2845 if (!maybe_result->ToObject(&result)) return maybe_result;
2846 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002847 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002848 break;
2849 }
2850 case CALLBACKS: {
2851 PropertyDetails d =
2852 PropertyDetails(details.attributes(), CALLBACKS, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002853 Object* value = descs->GetCallbacksObject(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002854 Object* result;
2855 { MaybeObject* maybe_result =
2856 dictionary->Add(descs->GetKey(i), value, d);
2857 if (!maybe_result->ToObject(&result)) return maybe_result;
2858 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002859 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002860 break;
2861 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002862 case MAP_TRANSITION:
2863 case CONSTANT_TRANSITION:
2864 case NULL_DESCRIPTOR:
2865 case INTERCEPTOR:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002866 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002867 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002868 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002869 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002870 }
2871 }
2872
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002873 Heap* current_heap = map_of_this->heap();
2874
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002875 // Copy the next enumeration index from instance descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002876 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002877 dictionary->SetNextEnumerationIndex(index);
2878
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002879 { MaybeObject* maybe_obj =
2880 current_heap->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002881 normalized_map_cache()->Get(this, mode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002882 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2883 }
ager@chromium.org32912102009-01-16 10:38:43 +00002884 Map* new_map = Map::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002885
ager@chromium.org32912102009-01-16 10:38:43 +00002886 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002887 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002888
2889 // Resize the object in the heap if necessary.
2890 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002891 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002892 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002893 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2894 instance_size_delta);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002895
ager@chromium.org32912102009-01-16 10:38:43 +00002896 set_map(new_map);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002897 new_map->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002899 set_properties(dictionary);
2900
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002901 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002902
2903#ifdef DEBUG
2904 if (FLAG_trace_normalization) {
2905 PrintF("Object properties have been normalized:\n");
2906 Print();
2907 }
2908#endif
2909 return this;
2910}
2911
2912
lrn@chromium.org303ada72010-10-27 09:33:13 +00002913MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002914 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002915 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002916 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002917 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002918}
2919
2920
lrn@chromium.org303ada72010-10-27 09:33:13 +00002921MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002922 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002923
whesse@chromium.org7b260152011-06-20 15:33:18 +00002924 // Find the backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002925 FixedArrayBase* array = FixedArrayBase::cast(elements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002926 Map* old_map = array->map();
2927 bool is_arguments =
2928 (old_map == old_map->heap()->non_strict_arguments_elements_map());
2929 if (is_arguments) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002930 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
lrn@chromium.org303ada72010-10-27 09:33:13 +00002931 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00002932 if (array->IsDictionary()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002934 ASSERT(HasFastElements() ||
2935 HasFastDoubleElements() ||
2936 HasFastArgumentsElements());
whesse@chromium.org7b260152011-06-20 15:33:18 +00002937 // Compute the effective length and allocate a new backing store.
2938 int length = IsJSArray()
2939 ? Smi::cast(JSArray::cast(this)->length())->value()
2940 : array->length();
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002941 int old_capacity = 0;
2942 int used_elements = 0;
2943 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002944 NumberDictionary* dictionary = NULL;
2945 { Object* object;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002946 MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00002947 if (!maybe->ToObject(&object)) return maybe;
2948 dictionary = NumberDictionary::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002949 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00002950
2951 // Copy the elements to the new backing store.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002952 bool has_double_elements = array->IsFixedDoubleArray();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002953 for (int i = 0; i < length; i++) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002954 Object* value = NULL;
2955 if (has_double_elements) {
2956 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
2957 if (double_array->is_the_hole(i)) {
2958 value = GetIsolate()->heap()->the_hole_value();
2959 } else {
2960 // Objects must be allocated in the old object space, since the
2961 // overall number of HeapNumbers needed for the conversion might
2962 // exceed the capacity of new space, and we would fail repeatedly
2963 // trying to convert the FixedDoubleArray.
2964 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002965 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002966 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00002967 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002968 } else {
2969 ASSERT(old_map->has_fast_elements());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00002970 value = FixedArray::cast(array)->get(i);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002971 }
2972 PropertyDetails details = PropertyDetails(NONE, NORMAL);
2973 if (!value->IsTheHole()) {
2974 Object* result;
2975 MaybeObject* maybe_result =
2976 dictionary->AddNumberEntry(i, value, details);
2977 if (!maybe_result->ToObject(&result)) return maybe_result;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002978 dictionary = NumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002979 }
2980 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002981
whesse@chromium.org7b260152011-06-20 15:33:18 +00002982 // Switch to using the dictionary as the backing storage for elements.
2983 if (is_arguments) {
2984 FixedArray::cast(elements())->set(1, dictionary);
2985 } else {
2986 // Set the new map first to satify the elements type assert in
2987 // set_elements().
2988 Object* new_map;
2989 MaybeObject* maybe = map()->GetSlowElementsMap();
2990 if (!maybe->ToObject(&new_map)) return maybe;
2991 set_map(Map::cast(new_map));
2992 set_elements(dictionary);
2993 }
2994
2995 old_map->isolate()->counters()->elements_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002996
2997#ifdef DEBUG
2998 if (FLAG_trace_normalization) {
2999 PrintF("Object elements have been normalized:\n");
3000 Print();
3001 }
3002#endif
3003
whesse@chromium.org7b260152011-06-20 15:33:18 +00003004 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3005 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003006}
3007
3008
vegorov@chromium.org7943d462011-08-01 11:41:52 +00003009MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
3010 Isolate* isolate = GetIsolate();
3011 Heap* heap = isolate->heap();
3012 Object* holder = BypassGlobalProxy();
3013 if (holder->IsUndefined()) return heap->undefined_value();
3014 JSObject* obj = JSObject::cast(holder);
3015 if (obj->HasFastProperties()) {
3016 // If the object has fast properties, check whether the first slot
3017 // in the descriptor array matches the hidden symbol. Since the
3018 // hidden symbols hash code is zero (and no other string has hash
3019 // code zero) it will always occupy the first entry if present.
3020 DescriptorArray* descriptors = obj->map()->instance_descriptors();
3021 if ((descriptors->number_of_descriptors() > 0) &&
3022 (descriptors->GetKey(0) == heap->hidden_symbol()) &&
3023 descriptors->IsProperty(0)) {
3024 ASSERT(descriptors->GetType(0) == FIELD);
3025 return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
3026 }
3027 }
3028
3029 // Only attempt to find the hidden properties in the local object and not
3030 // in the prototype chain.
3031 if (!obj->HasHiddenPropertiesObject()) {
3032 // Hidden properties object not found. Allocate a new hidden properties
3033 // object if requested. Otherwise return the undefined value.
3034 if (flag == ALLOW_CREATION) {
3035 Object* hidden_obj;
3036 { MaybeObject* maybe_obj = heap->AllocateJSObject(
3037 isolate->context()->global_context()->object_function());
3038 if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
3039 }
3040 return obj->SetHiddenPropertiesObject(hidden_obj);
3041 } else {
3042 return heap->undefined_value();
3043 }
3044 }
3045 return obj->GetHiddenPropertiesObject();
3046}
3047
3048
3049MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) {
3050 Isolate* isolate = GetIsolate();
3051 Object* hidden_props_obj;
3052 { MaybeObject* maybe_obj = GetHiddenProperties(flag);
3053 if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
3054 }
3055 if (!hidden_props_obj->IsJSObject()) {
3056 // We failed to create hidden properties. That's a detached
3057 // global proxy.
3058 ASSERT(hidden_props_obj->IsUndefined());
3059 return Smi::FromInt(0);
3060 }
3061 JSObject* hidden_props = JSObject::cast(hidden_props_obj);
3062 String* hash_symbol = isolate->heap()->identity_hash_symbol();
3063 {
3064 // Note that HasLocalProperty() can cause a GC in the general case in the
3065 // presence of interceptors.
3066 AssertNoAllocation no_alloc;
3067 if (hidden_props->HasLocalProperty(hash_symbol)) {
3068 MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
3069 return Smi::cast(hash->ToObjectChecked());
3070 }
3071 }
3072
3073 int hash_value;
3074 int attempts = 0;
3075 do {
3076 // Generate a random 32-bit hash value but limit range to fit
3077 // within a smi.
3078 hash_value = V8::Random(isolate) & Smi::kMaxValue;
3079 attempts++;
3080 } while (hash_value == 0 && attempts < 30);
3081 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3082
3083 Smi* hash = Smi::FromInt(hash_value);
3084 { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
3085 hash_symbol,
3086 hash,
3087 static_cast<PropertyAttributes>(None));
3088 if (result->IsFailure()) return result;
3089 }
3090 return hash;
3091}
3092
3093
lrn@chromium.org303ada72010-10-27 09:33:13 +00003094MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3095 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003096 // Check local property, ignore interceptor.
3097 LookupResult result;
3098 LocalLookupRealNamedProperty(name, &result);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003099 if (!result.IsProperty()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100
3101 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003102 Object* obj;
3103 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3104 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3105 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003106
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003107 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003108}
3109
3110
lrn@chromium.org303ada72010-10-27 09:33:13 +00003111MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003112 Isolate* isolate = GetIsolate();
3113 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3115 Handle<String> name_handle(name);
3116 Handle<JSObject> this_handle(this);
3117 if (!interceptor->deleter()->IsUndefined()) {
3118 v8::NamedPropertyDeleter deleter =
3119 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 LOG(isolate,
3121 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3122 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003123 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003124 v8::Handle<v8::Boolean> result;
3125 {
3126 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003127 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003128 result = deleter(v8::Utils::ToLocal(name_handle), info);
3129 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003130 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003131 if (!result.IsEmpty()) {
3132 ASSERT(result->IsBoolean());
3133 return *v8::Utils::OpenHandle(*result);
3134 }
3135 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003136 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00003137 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003139 return raw_result;
3140}
3141
3142
lrn@chromium.org303ada72010-10-27 09:33:13 +00003143MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003144 Isolate* isolate = GetIsolate();
3145 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003146 // Make sure that the top context does not change when doing
3147 // callbacks or interceptor calls.
3148 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003149 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003150 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003151 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003152 v8::IndexedPropertyDeleter deleter =
3153 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3154 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003155 LOG(isolate,
3156 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3157 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003158 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003159 v8::Handle<v8::Boolean> result;
3160 {
3161 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003162 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003163 result = deleter(index, info);
3164 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003165 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003166 if (!result.IsEmpty()) {
3167 ASSERT(result->IsBoolean());
3168 return *v8::Utils::OpenHandle(*result);
3169 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003170 MaybeObject* raw_result = GetElementsAccessor()->Delete(*this_handle,
3171 index,
3172 NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003174 return raw_result;
3175}
3176
3177
lrn@chromium.org303ada72010-10-27 09:33:13 +00003178MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003179 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003180 // Check access rights if needed.
3181 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003182 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3183 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3184 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003185 }
3186
3187 if (IsJSGlobalProxy()) {
3188 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003189 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003190 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003191 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003192 }
3193
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003194 if (HasIndexedInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003195 // Skip interceptor if forcing deletion.
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003196 if (mode != FORCE_DELETION) {
3197 return DeleteElementWithInterceptor(index);
3198 }
3199 mode = JSReceiver::FORCE_DELETION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003200 }
3201
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00003202 return GetElementsAccessor()->Delete(this, index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003203}
3204
3205
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00003206MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3207 if (IsJSProxy()) {
3208 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3209 } else {
3210 return JSObject::cast(this)->DeleteProperty(name, mode);
3211 }
3212}
3213
3214
lrn@chromium.org303ada72010-10-27 09:33:13 +00003215MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003216 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003217 // ECMA-262, 3rd, 8.6.2.5
3218 ASSERT(name->IsString());
3219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003220 // Check access rights if needed.
3221 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003222 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3223 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3224 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003225 }
3226
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003227 if (IsJSGlobalProxy()) {
3228 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003230 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003231 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003233
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003234 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003235 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003236 return DeleteElement(index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003237 } else {
3238 LookupResult result;
3239 LocalLookup(name, &result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003240 if (!result.IsProperty()) return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003241 // Ignore attributes if forcing a deletion.
3242 if (result.IsDontDelete() && mode != FORCE_DELETION) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003243 if (mode == STRICT_DELETION) {
3244 // Deleting a non-configurable property in strict mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003246 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003247 return isolate->Throw(*isolate->factory()->NewTypeError(
3248 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003249 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003250 return isolate->heap()->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003252 // Check for interceptor.
3253 if (result.type() == INTERCEPTOR) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003254 // Skip interceptor if forcing a deletion.
3255 if (mode == FORCE_DELETION) {
3256 return DeletePropertyPostInterceptor(name, mode);
3257 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258 return DeletePropertyWithInterceptor(name);
3259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003260 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003261 Object* obj;
3262 { MaybeObject* maybe_obj =
3263 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3264 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003266 // Make sure the properties are normalized before removing the entry.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003267 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268 }
3269}
3270
3271
whesse@chromium.org7b260152011-06-20 15:33:18 +00003272bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3273 ElementsKind kind,
3274 Object* object) {
3275 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
3276 if (kind == FAST_ELEMENTS) {
3277 int length = IsJSArray()
3278 ? Smi::cast(JSArray::cast(this)->length())->value()
3279 : elements->length();
3280 for (int i = 0; i < length; ++i) {
3281 Object* element = elements->get(i);
3282 if (!element->IsTheHole() && element == object) return true;
3283 }
3284 } else {
3285 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
3286 if (!key->IsUndefined()) return true;
3287 }
3288 return false;
3289}
3290
3291
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003292// Check whether this object references another object.
3293bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003294 Map* map_of_this = map();
3295 Heap* heap = map_of_this->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003296 AssertNoAllocation no_alloc;
3297
3298 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003299 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003300 return true;
3301 }
3302
3303 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003304 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003305 return true;
3306 }
3307
3308 // Check if the object is among the named properties.
3309 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003310 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003311 return true;
3312 }
3313
3314 // Check if the object is among the indexed properties.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003315 ElementsKind kind = GetElementsKind();
3316 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003317 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003318 case EXTERNAL_BYTE_ELEMENTS:
3319 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3320 case EXTERNAL_SHORT_ELEMENTS:
3321 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3322 case EXTERNAL_INT_ELEMENTS:
3323 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3324 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003325 case EXTERNAL_DOUBLE_ELEMENTS:
whesse@chromium.org7b260152011-06-20 15:33:18 +00003326 case FAST_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003327 // Raw pixels and external arrays do not reference other
3328 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003329 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003330 case FAST_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003331 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003332 FixedArray* elements = FixedArray::cast(this->elements());
3333 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003334 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003335 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003336 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3337 FixedArray* parameter_map = FixedArray::cast(elements());
3338 // Check the mapped parameters.
3339 int length = parameter_map->length();
3340 for (int i = 2; i < length; ++i) {
3341 Object* value = parameter_map->get(i);
3342 if (!value->IsTheHole() && value == obj) return true;
3343 }
3344 // Check the arguments.
3345 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3346 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
3347 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003348 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003349 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350 }
3351
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003352 // For functions check the context.
3353 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003354 // Get the constructor function for arguments array.
3355 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003356 heap->isolate()->context()->global_context()->
3357 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358 JSFunction* arguments_function =
3359 JSFunction::cast(arguments_boilerplate->map()->constructor());
3360
3361 // Get the context and don't check if it is the global context.
3362 JSFunction* f = JSFunction::cast(this);
3363 Context* context = f->context();
3364 if (context->IsGlobalContext()) {
3365 return false;
3366 }
3367
3368 // Check the non-special context slots.
3369 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3370 // Only check JS objects.
3371 if (context->get(i)->IsJSObject()) {
3372 JSObject* ctxobj = JSObject::cast(context->get(i));
3373 // If it is an arguments array check the content.
3374 if (ctxobj->map()->constructor() == arguments_function) {
3375 if (ctxobj->ReferencesObject(obj)) {
3376 return true;
3377 }
3378 } else if (ctxobj == obj) {
3379 return true;
3380 }
3381 }
3382 }
3383
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003384 // Check the context extension (if any) if it can have references.
3385 if (context->has_extension() && !context->IsCatchContext()) {
3386 return JSObject::cast(context->extension())->ReferencesObject(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003387 }
3388 }
3389
3390 // No references to object.
3391 return false;
3392}
3393
3394
lrn@chromium.org303ada72010-10-27 09:33:13 +00003395MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003396 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003397 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003398 !isolate->MayNamedAccess(this,
3399 isolate->heap()->undefined_value(),
3400 v8::ACCESS_KEYS)) {
3401 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3402 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003403 }
3404
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003405 if (IsJSGlobalProxy()) {
3406 Object* proto = GetPrototype();
3407 if (proto->IsNull()) return this;
3408 ASSERT(proto->IsJSGlobalObject());
3409 return JSObject::cast(proto)->PreventExtensions();
3410 }
3411
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003412 // If there are fast elements we normalize.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003413 NumberDictionary* dictionary = NULL;
3414 { MaybeObject* maybe = NormalizeElements();
3415 if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003416 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003417 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003418 // Make sure that we never go back to fast case.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003419 dictionary->set_requires_slow_elements();
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003420
3421 // Do a map transition, other objects with this map may still
3422 // be extensible.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003423 Map* new_map;
3424 { MaybeObject* maybe = map()->CopyDropTransitions();
3425 if (!maybe->To<Map>(&new_map)) return maybe;
lrn@chromium.org303ada72010-10-27 09:33:13 +00003426 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00003427 new_map->set_is_extensible(false);
3428 set_map(new_map);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003429 ASSERT(!map()->is_extensible());
3430 return new_map;
3431}
3432
3433
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003434// Tests for the fast common case for property enumeration:
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003435// - This object and all prototypes has an enum cache (which means that it has
3436// no interceptors and needs no access checks).
3437// - This object has no elements.
3438// - No prototype has enumerable properties/elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439bool JSObject::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003440 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003442 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003443 o = JSObject::cast(o)->GetPrototype()) {
3444 JSObject* curr = JSObject::cast(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003446 ASSERT(!curr->HasNamedInterceptor());
3447 ASSERT(!curr->HasIndexedInterceptor());
3448 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003449 if (curr->NumberOfEnumElements() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450 if (curr != this) {
3451 FixedArray* curr_fixed_array =
3452 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003453 if (curr_fixed_array->length() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454 }
3455 }
3456 return true;
3457}
3458
3459
3460int Map::NumberOfDescribedProperties() {
3461 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003462 DescriptorArray* descs = instance_descriptors();
3463 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3464 if (descs->IsProperty(i)) result++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003465 }
3466 return result;
3467}
3468
3469
3470int Map::PropertyIndexFor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003471 DescriptorArray* descs = instance_descriptors();
3472 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3473 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3474 return descs->GetFieldIndex(i);
3475 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476 }
3477 return -1;
3478}
3479
3480
3481int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003482 int max_index = -1;
3483 DescriptorArray* descs = instance_descriptors();
3484 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3485 if (descs->GetType(i) == FIELD) {
3486 int current_index = descs->GetFieldIndex(i);
3487 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488 }
3489 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003490 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003491}
3492
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493
3494AccessorDescriptor* Map::FindAccessor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003495 DescriptorArray* descs = instance_descriptors();
3496 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3497 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3498 return descs->GetCallbacks(i);
3499 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500 }
3501 return NULL;
3502}
3503
3504
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003505void JSReceiver::LocalLookup(String* name, LookupResult* result) {
3506 if (IsJSProxy()) {
3507 result->HandlerResult();
3508 } else {
3509 JSObject::cast(this)->LocalLookup(name, result);
3510 }
3511}
3512
3513
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003514void JSObject::LocalLookup(String* name, LookupResult* result) {
3515 ASSERT(name->IsString());
3516
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003517 Heap* heap = GetHeap();
3518
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003519 if (IsJSGlobalProxy()) {
3520 Object* proto = GetPrototype();
3521 if (proto->IsNull()) return result->NotFound();
3522 ASSERT(proto->IsJSGlobalObject());
3523 return JSObject::cast(proto)->LocalLookup(name, result);
3524 }
3525
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003526 // Do not use inline caching if the object is a non-global object
3527 // that requires access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003528 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529 result->DisallowCaching();
3530 }
3531
3532 // Check __proto__ before interceptor.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003533 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003534 result->ConstantResult(this);
3535 return;
3536 }
3537
3538 // Check for lookup interceptor except when bootstrapping.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003539 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003540 result->InterceptorResult(this);
3541 return;
3542 }
3543
3544 LocalLookupRealNamedProperty(name, result);
3545}
3546
3547
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003548void JSReceiver::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003549 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003550 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003551 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003553 current = JSObject::cast(current)->GetPrototype()) {
3554 JSObject::cast(current)->LocalLookup(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003555 if (result->IsProperty()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00003556 }
3557 result->NotFound();
3558}
3559
3560
3561// Search object and it's prototype chain for callback properties.
3562void JSObject::LookupCallback(String* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003563 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003564 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 current != heap->null_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003566 current = JSObject::cast(current)->GetPrototype()) {
3567 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003568 if (result->IsProperty() && result->type() == CALLBACKS) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569 }
3570 result->NotFound();
3571}
3572
3573
whesse@chromium.org7b260152011-06-20 15:33:18 +00003574// Search for a getter or setter in an elements dictionary. Returns either
3575// undefined if the element is read-only, or the getter/setter pair (fixed
3576// array) if there is an existing one, or the hole value if the element does
3577// not exist or is a normal non-getter/setter data element.
3578static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary,
3579 uint32_t index,
3580 Heap* heap) {
3581 int entry = dictionary->FindEntry(index);
3582 if (entry != NumberDictionary::kNotFound) {
3583 Object* result = dictionary->ValueAt(entry);
3584 PropertyDetails details = dictionary->DetailsAt(entry);
3585 if (details.IsReadOnly()) return heap->undefined_value();
3586 if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
3587 }
3588 return heap->the_hole_value();
3589}
3590
3591
lrn@chromium.org303ada72010-10-27 09:33:13 +00003592MaybeObject* JSObject::DefineGetterSetter(String* name,
3593 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 // Make sure that the top context does not change when doing callbacks or
3596 // interceptor calls.
3597 AssertNoContextChange ncc;
3598
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003599 // Try to flatten before operating on the string.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003600 name->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003602 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003603 return heap->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003604 }
3605
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003606 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003607 bool is_element = name->AsArrayIndex(&index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003608
3609 if (is_element) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003610 switch (GetElementsKind()) {
3611 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003612 case FAST_DOUBLE_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003613 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003614 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003615 case EXTERNAL_BYTE_ELEMENTS:
3616 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3617 case EXTERNAL_SHORT_ELEMENTS:
3618 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3619 case EXTERNAL_INT_ELEMENTS:
3620 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3621 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003622 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003623 // Ignore getters and setters on pixel and external array
3624 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 return heap->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003626 case DICTIONARY_ELEMENTS: {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003627 Object* probe =
3628 FindGetterSetterInDictionary(element_dictionary(), index, heap);
3629 if (!probe->IsTheHole()) return probe;
3630 // Otherwise allow to override it.
3631 break;
3632 }
3633 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3634 // Ascertain whether we have read-only properties or an existing
3635 // getter/setter pair in an arguments elements dictionary backing
3636 // store.
3637 FixedArray* parameter_map = FixedArray::cast(elements());
3638 uint32_t length = parameter_map->length();
3639 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00003640 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003641 if (probe == NULL || probe->IsTheHole()) {
3642 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3643 if (arguments->IsDictionary()) {
3644 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
3645 probe = FindGetterSetterInDictionary(dictionary, index, heap);
3646 if (!probe->IsTheHole()) return probe;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003647 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003648 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003649 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003650 }
3651 }
3652 } else {
3653 // Lookup the name.
3654 LookupResult result;
3655 LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003656 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003658 if (result.type() == CALLBACKS) {
3659 Object* obj = result.GetCallbackObject();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003660 // Need to preserve old getters/setters.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003661 if (obj->IsFixedArray()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003662 // Use set to update attributes.
3663 return SetPropertyCallback(name, obj, attributes);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003664 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003665 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003666 }
3667 }
3668
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669 // Allocate the fixed array to hold getter and setter.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003670 Object* structure;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003671 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003672 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003675 if (is_element) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003676 return SetElementCallback(index, structure, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003677 } else {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003678 return SetPropertyCallback(name, structure, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003679 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003680}
3681
3682
3683bool JSObject::CanSetCallback(String* name) {
3684 ASSERT(!IsAccessCheckNeeded()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003686
3687 // Check if there is an API defined callback object which prohibits
3688 // callback overwriting in this object or it's prototype chain.
3689 // This mechanism is needed for instance in a browser setting, where
3690 // certain accessors such as window.location should not be allowed
3691 // to be overwritten because allowing overwriting could potentially
3692 // cause security problems.
3693 LookupResult callback_result;
3694 LookupCallback(name, &callback_result);
3695 if (callback_result.IsProperty()) {
3696 Object* obj = callback_result.GetCallbackObject();
3697 if (obj->IsAccessorInfo() &&
3698 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3699 return false;
3700 }
3701 }
3702
3703 return true;
3704}
3705
3706
lrn@chromium.org303ada72010-10-27 09:33:13 +00003707MaybeObject* JSObject::SetElementCallback(uint32_t index,
3708 Object* structure,
3709 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003710 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3711
3712 // Normalize elements to make this operation simple.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003713 NumberDictionary* dictionary = NULL;
3714 { Object* result;
3715 MaybeObject* maybe = NormalizeElements();
3716 if (!maybe->ToObject(&result)) return maybe;
3717 dictionary = NumberDictionary::cast(result);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003718 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00003719 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003720
3721 // Update the dictionary with the new CALLBACKS property.
whesse@chromium.org7b260152011-06-20 15:33:18 +00003722 { Object* result;
3723 MaybeObject* maybe = dictionary->Set(index, structure, details);
3724 if (!maybe->ToObject(&result)) return maybe;
3725 dictionary = NumberDictionary::cast(result);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003726 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003727
whesse@chromium.org7b260152011-06-20 15:33:18 +00003728 dictionary->set_requires_slow_elements();
3729 // Update the dictionary backing store on the object.
3730 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
3731 // Also delete any parameter alias.
3732 //
3733 // TODO(kmillikin): when deleting the last parameter alias we could
3734 // switch to a direct backing store without the parameter map. This
3735 // would allow GC of the context.
3736 FixedArray* parameter_map = FixedArray::cast(elements());
3737 uint32_t length = parameter_map->length();
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00003738 if (index < length - 2) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003739 parameter_map->set(index + 2, GetHeap()->the_hole_value());
3740 }
3741 parameter_map->set(1, dictionary);
3742 } else {
3743 set_elements(dictionary);
3744 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003745
3746 return structure;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747}
3748
3749
lrn@chromium.org303ada72010-10-27 09:33:13 +00003750MaybeObject* JSObject::SetPropertyCallback(String* name,
3751 Object* structure,
3752 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003753 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3754
3755 bool convert_back_to_fast = HasFastProperties() &&
3756 (map()->instance_descriptors()->number_of_descriptors()
3757 < DescriptorArray::kMaxNumberOfDescriptors);
3758
3759 // Normalize object to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003760 Object* ok;
3761 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3762 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3763 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003764
3765 // For the global object allocate a new map to invalidate the global inline
3766 // caches which have a global property cell reference directly in the code.
3767 if (IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003768 Object* new_map;
3769 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3770 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3771 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003772 set_map(Map::cast(new_map));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003773 // When running crankshaft, changing the map is not enough. We
3774 // need to deoptimize all functions that rely on this global
3775 // object.
3776 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003777 }
3778
3779 // Update the dictionary with the new CALLBACKS property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003780 Object* result;
3781 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3782 if (!maybe_result->ToObject(&result)) return maybe_result;
3783 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003784
3785 if (convert_back_to_fast) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003786 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3787 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3788 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003789 }
3790 return result;
3791}
3792
lrn@chromium.org303ada72010-10-27 09:33:13 +00003793MaybeObject* JSObject::DefineAccessor(String* name,
3794 bool is_getter,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003795 Object* fun,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003796 PropertyAttributes attributes) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003797 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003798 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003799 // Check access rights if needed.
3800 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3802 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3803 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003804 }
3805
3806 if (IsJSGlobalProxy()) {
3807 Object* proto = GetPrototype();
3808 if (proto->IsNull()) return this;
3809 ASSERT(proto->IsJSGlobalObject());
3810 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3811 fun, attributes);
3812 }
3813
lrn@chromium.org303ada72010-10-27 09:33:13 +00003814 Object* array;
3815 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3816 if (!maybe_array->ToObject(&array)) return maybe_array;
3817 }
3818 if (array->IsUndefined()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3820 return this;
3821}
3822
3823
lrn@chromium.org303ada72010-10-27 09:33:13 +00003824MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003825 Isolate* isolate = GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003826 String* name = String::cast(info->name());
3827 // Check access rights if needed.
3828 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003829 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3830 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3831 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003832 }
3833
3834 if (IsJSGlobalProxy()) {
3835 Object* proto = GetPrototype();
3836 if (proto->IsNull()) return this;
3837 ASSERT(proto->IsJSGlobalObject());
3838 return JSObject::cast(proto)->DefineAccessor(info);
3839 }
3840
3841 // Make sure that the top context does not change when doing callbacks or
3842 // interceptor calls.
3843 AssertNoContextChange ncc;
3844
3845 // Try to flatten before operating on the string.
3846 name->TryFlatten();
3847
3848 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003849 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003850 }
3851
3852 uint32_t index = 0;
3853 bool is_element = name->AsArrayIndex(&index);
3854
3855 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003856 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003857
3858 // Accessors overwrite previous callbacks (cf. with getters/setters).
3859 switch (GetElementsKind()) {
3860 case FAST_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00003861 case FAST_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003862 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003863 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003864 case EXTERNAL_BYTE_ELEMENTS:
3865 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3866 case EXTERNAL_SHORT_ELEMENTS:
3867 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3868 case EXTERNAL_INT_ELEMENTS:
3869 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3870 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003871 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003872 // Ignore getters and setters on pixel and external array
3873 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003875 case DICTIONARY_ELEMENTS:
3876 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003877 case NON_STRICT_ARGUMENTS_ELEMENTS:
3878 UNIMPLEMENTED();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003879 break;
3880 }
3881
lrn@chromium.org303ada72010-10-27 09:33:13 +00003882 Object* ok;
3883 { MaybeObject* maybe_ok =
3884 SetElementCallback(index, info, info->property_attributes());
3885 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3886 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003887 } else {
3888 // Lookup the name.
3889 LookupResult result;
3890 LocalLookup(name, &result);
3891 // ES5 forbids turning a property into an accessor if it's not
3892 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3893 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003894 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003895 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003896 Object* ok;
3897 { MaybeObject* maybe_ok =
3898 SetPropertyCallback(name, info, info->property_attributes());
3899 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3900 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003901 }
3902
3903 return this;
3904}
3905
3906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003907Object* JSObject::LookupAccessor(String* name, bool is_getter) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003908 Heap* heap = GetHeap();
3909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003910 // Make sure that the top context does not change when doing callbacks or
3911 // interceptor calls.
3912 AssertNoContextChange ncc;
3913
3914 // Check access rights if needed.
3915 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3917 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3918 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003919 }
3920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003921 // Make the lookup and include prototypes.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003922 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003923 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003924 if (name->AsArrayIndex(&index)) {
3925 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003926 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003927 obj = JSObject::cast(obj)->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003928 JSObject* js_object = JSObject::cast(obj);
3929 if (js_object->HasDictionaryElements()) {
3930 NumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003931 int entry = dictionary->FindEntry(index);
3932 if (entry != NumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003933 Object* element = dictionary->ValueAt(entry);
3934 PropertyDetails details = dictionary->DetailsAt(entry);
3935 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003936 if (element->IsFixedArray()) {
3937 return FixedArray::cast(element)->get(accessor_index);
3938 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003939 }
3940 }
3941 }
3942 }
3943 } else {
3944 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003945 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003946 obj = JSObject::cast(obj)->GetPrototype()) {
3947 LookupResult result;
3948 JSObject::cast(obj)->LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003949 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003950 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003951 if (result.type() == CALLBACKS) {
3952 Object* obj = result.GetCallbackObject();
3953 if (obj->IsFixedArray()) {
3954 return FixedArray::cast(obj)->get(accessor_index);
3955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003956 }
3957 }
3958 }
3959 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003960 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961}
3962
3963
3964Object* JSObject::SlowReverseLookup(Object* value) {
3965 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003966 DescriptorArray* descs = map()->instance_descriptors();
3967 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3968 if (descs->GetType(i) == FIELD) {
3969 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3970 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003972 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3973 if (descs->GetConstantFunction(i) == value) {
3974 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003975 }
3976 }
3977 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003978 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003979 } else {
3980 return property_dictionary()->SlowReverseLookup(value);
3981 }
3982}
3983
3984
lrn@chromium.org303ada72010-10-27 09:33:13 +00003985MaybeObject* Map::CopyDropDescriptors() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003986 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003987 Object* result;
3988 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 heap->AllocateMap(instance_type(), instance_size());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003990 if (!maybe_result->ToObject(&result)) return maybe_result;
3991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003992 Map::cast(result)->set_prototype(prototype());
3993 Map::cast(result)->set_constructor(constructor());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003994 // Don't copy descriptors, so map transitions always remain a forest.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003995 // If we retained the same descriptors we would have two maps
3996 // pointing to the same transition which is bad because the garbage
3997 // collector relies on being able to reverse pointers from transitions
3998 // to maps. If properties need to be retained use CopyDropTransitions.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003999 Map::cast(result)->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000 // Please note instance_type and instance_size are set when allocated.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004001 Map::cast(result)->set_inobject_properties(inobject_properties());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004002 Map::cast(result)->set_unused_property_fields(unused_property_fields());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004003
4004 // If the map has pre-allocated properties always start out with a descriptor
4005 // array describing these properties.
4006 if (pre_allocated_property_fields() > 0) {
4007 ASSERT(constructor()->IsJSFunction());
4008 JSFunction* ctor = JSFunction::cast(constructor());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004009 Object* descriptors;
4010 { MaybeObject* maybe_descriptors =
4011 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4012 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4013 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00004014 Map::cast(result)->set_instance_descriptors(
4015 DescriptorArray::cast(descriptors));
4016 Map::cast(result)->set_pre_allocated_property_fields(
4017 pre_allocated_property_fields());
4018 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 Map::cast(result)->set_bit_field(bit_field());
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004020 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004021 Map::cast(result)->set_bit_field3(bit_field3());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004022 Map::cast(result)->set_is_shared(false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004023 Map::cast(result)->ClearCodeCache(heap);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 return result;
4025}
4026
4027
lrn@chromium.org303ada72010-10-27 09:33:13 +00004028MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4029 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004030 int new_instance_size = instance_size();
4031 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4032 new_instance_size -= inobject_properties() * kPointerSize;
4033 }
4034
lrn@chromium.org303ada72010-10-27 09:33:13 +00004035 Object* result;
4036 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004037 GetHeap()->AllocateMap(instance_type(), new_instance_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004038 if (!maybe_result->ToObject(&result)) return maybe_result;
4039 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004040
4041 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4042 Map::cast(result)->set_inobject_properties(inobject_properties());
4043 }
4044
4045 Map::cast(result)->set_prototype(prototype());
4046 Map::cast(result)->set_constructor(constructor());
4047
4048 Map::cast(result)->set_bit_field(bit_field());
4049 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00004050 Map::cast(result)->set_bit_field3(bit_field3());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004051
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004052 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4053
ricow@chromium.org65fae842010-08-25 15:26:24 +00004054#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004055 if (Map::cast(result)->is_shared()) {
4056 Map::cast(result)->SharedMapVerify();
4057 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004058#endif
4059
4060 return result;
4061}
4062
4063
lrn@chromium.org303ada72010-10-27 09:33:13 +00004064MaybeObject* Map::CopyDropTransitions() {
4065 Object* new_map;
4066 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4067 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4068 }
4069 Object* descriptors;
4070 { MaybeObject* maybe_descriptors =
4071 instance_descriptors()->RemoveTransitions();
4072 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4073 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004074 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00004075 return new_map;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004076}
4077
4078
lrn@chromium.org303ada72010-10-27 09:33:13 +00004079MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004080 // Allocate the code cache if not present.
4081 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004082 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004083 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004084 if (!maybe_result->ToObject(&result)) return maybe_result;
4085 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004086 set_code_cache(result);
4087 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004089 // Update the code cache.
4090 return CodeCache::cast(code_cache())->Update(name, code);
4091}
4092
4093
4094Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4095 // Do a lookup if a code cache exists.
4096 if (!code_cache()->IsFixedArray()) {
4097 return CodeCache::cast(code_cache())->Lookup(name, flags);
4098 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004099 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004100 }
4101}
4102
4103
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004104int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004105 // Get the internal index if a code cache exists.
4106 if (!code_cache()->IsFixedArray()) {
4107 return CodeCache::cast(code_cache())->GetIndex(name, code);
4108 }
4109 return -1;
4110}
4111
4112
4113void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4114 // No GC is supposed to happen between a call to IndexInCodeCache and
4115 // RemoveFromCodeCache so the code cache must be there.
4116 ASSERT(!code_cache()->IsFixedArray());
4117 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4118}
4119
4120
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004121void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004122 // Traverse the transition tree without using a stack. We do this by
4123 // reversing the pointers in the maps and descriptor arrays.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004124 Map* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004125 Map* meta_map = heap()->meta_map();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004126 Object** map_or_index_field = NULL;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004127 while (current != meta_map) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004128 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00004129 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004130 if (!d->IsEmpty()) {
4131 FixedArray* contents = reinterpret_cast<FixedArray*>(
4132 d->get(DescriptorArray::kContentArrayIndex));
4133 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
4134 Object* map_or_index = *map_or_index_field;
4135 bool map_done = true; // Controls a nested continue statement.
4136 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
4137 i < contents->length();
4138 i += 2) {
4139 PropertyDetails details(Smi::cast(contents->get(i + 1)));
4140 if (details.IsTransition()) {
4141 // Found a map in the transition array. We record our progress in
4142 // the transition array by recording the current map in the map field
4143 // of the next map and recording the index in the transition array in
4144 // the map field of the array.
4145 Map* next = Map::cast(contents->get(i));
4146 next->set_map(current);
4147 *map_or_index_field = Smi::FromInt(i + 2);
4148 current = next;
4149 map_done = false;
4150 break;
4151 }
4152 }
4153 if (!map_done) continue;
whesse@chromium.org030d38e2011-07-13 13:23:34 +00004154 } else {
4155 map_or_index_field = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004156 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004157 // That was the regular transitions, now for the prototype transitions.
4158 FixedArray* prototype_transitions =
4159 current->unchecked_prototype_transitions();
4160 Object** proto_map_or_index_field =
4161 RawField(prototype_transitions, HeapObject::kMapOffset);
4162 Object* map_or_index = *proto_map_or_index_field;
4163 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
4164 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
4165 if (i < prototype_transitions->length()) {
4166 // Found a map in the prototype transition array. Record progress in
4167 // an analogous way to the regular transitions array above.
4168 Object* perhaps_map = prototype_transitions->get(i);
4169 if (perhaps_map->IsMap()) {
4170 Map* next = Map::cast(perhaps_map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004171 next->set_map(current);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004172 *proto_map_or_index_field =
4173 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004174 current = next;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004175 continue;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004176 }
4177 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00004178 *proto_map_or_index_field = heap()->fixed_array_map();
4179 if (map_or_index_field != NULL) {
4180 *map_or_index_field = heap()->fixed_array_map();
4181 }
4182
4183 // The callback expects a map to have a real map as its map, so we save
4184 // the map field, which is being used to track the traversal and put the
4185 // correct map (the meta_map) in place while we do the callback.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004186 Map* prev = current->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 current->set_map(meta_map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004188 callback(current, data);
4189 current = prev;
4190 }
4191}
4192
4193
lrn@chromium.org303ada72010-10-27 09:33:13 +00004194MaybeObject* CodeCache::Update(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004195 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4196 // a large number and therefore they need to go into a hash table. They are
4197 // used to load global properties from cells.
4198 if (code->type() == NORMAL) {
4199 // Make sure that a hash table is allocated for the normal load code cache.
4200 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004201 Object* result;
4202 { MaybeObject* maybe_result =
4203 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4204 if (!maybe_result->ToObject(&result)) return maybe_result;
4205 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004206 set_normal_type_cache(result);
4207 }
4208 return UpdateNormalTypeCache(name, code);
4209 } else {
4210 ASSERT(default_cache()->IsFixedArray());
4211 return UpdateDefaultCache(name, code);
4212 }
4213}
4214
4215
lrn@chromium.org303ada72010-10-27 09:33:13 +00004216MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004217 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 // flags. This allows call constant stubs to overwrite call field
4219 // stubs, etc.
4220 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4221
4222 // First check whether we can update existing code cache without
4223 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004224 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004225 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00004226 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004227 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00004229 if (key->IsNull()) {
4230 if (deleted_index < 0) deleted_index = i;
4231 continue;
4232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00004234 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004235 cache->set(i + kCodeCacheEntryNameOffset, name);
4236 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237 return this;
4238 }
4239 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004240 Code::Flags found =
4241 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004242 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004243 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244 return this;
4245 }
4246 }
4247 }
4248
ager@chromium.org236ad962008-09-25 09:45:57 +00004249 // Reached the end of the code cache. If there were deleted
4250 // elements, reuse the space for the first of them.
4251 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004252 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4253 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00004254 return this;
4255 }
4256
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004257 // Extend the code cache with some new entries (at least one). Must be a
4258 // multiple of the entry size.
4259 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4260 new_length = new_length - new_length % kCodeCacheEntrySize;
4261 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004262 Object* result;
4263 { MaybeObject* maybe_result = cache->CopySize(new_length);
4264 if (!maybe_result->ToObject(&result)) return maybe_result;
4265 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004266
4267 // Add the (name, code) pair to the new cache.
4268 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004269 cache->set(length + kCodeCacheEntryNameOffset, name);
4270 cache->set(length + kCodeCacheEntryCodeOffset, code);
4271 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272 return this;
4273}
4274
4275
lrn@chromium.org303ada72010-10-27 09:33:13 +00004276MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004277 // Adding a new entry can cause a new cache to be allocated.
4278 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004279 Object* new_cache;
4280 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4281 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4282 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004283 set_normal_type_cache(new_cache);
4284 return this;
4285}
4286
4287
4288Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4289 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4290 return LookupNormalTypeCache(name, flags);
4291 } else {
4292 return LookupDefaultCache(name, flags);
4293 }
4294}
4295
4296
4297Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4298 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004300 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4301 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00004302 // Skip deleted elements.
4303 if (key->IsNull()) continue;
4304 if (key->IsUndefined()) return key;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004305 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004306 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4307 if (code->flags() == flags) {
4308 return code;
4309 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004310 }
4311 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004312 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004313}
4314
4315
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004316Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4317 if (!normal_type_cache()->IsUndefined()) {
4318 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4319 return cache->Lookup(name, flags);
4320 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004321 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004322 }
4323}
4324
4325
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004326int CodeCache::GetIndex(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004327 if (code->type() == NORMAL) {
4328 if (normal_type_cache()->IsUndefined()) return -1;
4329 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004330 return cache->GetIndex(String::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004331 }
4332
4333 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004334 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004335 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4336 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004337 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004338 return -1;
4339}
4340
4341
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004342void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004343 if (code->type() == NORMAL) {
4344 ASSERT(!normal_type_cache()->IsUndefined());
4345 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004346 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004347 cache->RemoveByIndex(index);
4348 } else {
4349 FixedArray* array = default_cache();
4350 ASSERT(array->length() >= index && array->get(index)->IsCode());
4351 // Use null instead of undefined for deleted elements to distinguish
4352 // deleted elements from unused elements. This distinction is used
4353 // when looking up in the cache and when updating the cache.
4354 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4355 array->set_null(index - 1); // Name.
4356 array->set_null(index); // Code.
4357 }
4358}
4359
4360
4361// The key in the code cache hash table consists of the property name and the
4362// code object. The actual match is on the name and the code flags. If a key
4363// is created using the flags and not a code object it can only be used for
4364// lookup not to create a new entry.
4365class CodeCacheHashTableKey : public HashTableKey {
4366 public:
4367 CodeCacheHashTableKey(String* name, Code::Flags flags)
4368 : name_(name), flags_(flags), code_(NULL) { }
4369
4370 CodeCacheHashTableKey(String* name, Code* code)
4371 : name_(name),
4372 flags_(code->flags()),
4373 code_(code) { }
4374
4375
4376 bool IsMatch(Object* other) {
4377 if (!other->IsFixedArray()) return false;
4378 FixedArray* pair = FixedArray::cast(other);
4379 String* name = String::cast(pair->get(0));
4380 Code::Flags flags = Code::cast(pair->get(1))->flags();
4381 if (flags != flags_) {
4382 return false;
4383 }
4384 return name_->Equals(name);
4385 }
4386
4387 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4388 return name->Hash() ^ flags;
4389 }
4390
4391 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4392
4393 uint32_t HashForObject(Object* obj) {
4394 FixedArray* pair = FixedArray::cast(obj);
4395 String* name = String::cast(pair->get(0));
4396 Code* code = Code::cast(pair->get(1));
4397 return NameFlagsHashHelper(name, code->flags());
4398 }
4399
lrn@chromium.org303ada72010-10-27 09:33:13 +00004400 MUST_USE_RESULT MaybeObject* AsObject() {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004401 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004402 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004403 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004404 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4405 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004406 FixedArray* pair = FixedArray::cast(obj);
4407 pair->set(0, name_);
4408 pair->set(1, code_);
4409 return pair;
4410 }
4411
4412 private:
4413 String* name_;
4414 Code::Flags flags_;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004415 // TODO(jkummerow): We should be able to get by without this.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004416 Code* code_;
4417};
4418
4419
4420Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4421 CodeCacheHashTableKey key(name, flags);
4422 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004423 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004424 return get(EntryToIndex(entry) + 1);
4425}
4426
4427
lrn@chromium.org303ada72010-10-27 09:33:13 +00004428MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004429 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004430 Object* obj;
4431 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4432 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4433 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004434
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004435 // Don't use |this|, as the table might have grown.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004436 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4437
4438 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004439 Object* k;
4440 { MaybeObject* maybe_k = key.AsObject();
4441 if (!maybe_k->ToObject(&k)) return maybe_k;
4442 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004443
4444 cache->set(EntryToIndex(entry), k);
4445 cache->set(EntryToIndex(entry) + 1, code);
4446 cache->ElementAdded();
4447 return cache;
4448}
4449
4450
4451int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4452 CodeCacheHashTableKey key(name, flags);
4453 int entry = FindEntry(&key);
4454 return (entry == kNotFound) ? -1 : entry;
4455}
4456
4457
4458void CodeCacheHashTable::RemoveByIndex(int index) {
4459 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004460 Heap* heap = GetHeap();
4461 set(EntryToIndex(index), heap->null_value());
4462 set(EntryToIndex(index) + 1, heap->null_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004463 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004464}
4465
4466
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004467static bool HasKey(FixedArray* array, Object* key) {
4468 int len0 = array->length();
4469 for (int i = 0; i < len0; i++) {
4470 Object* element = array->get(i);
4471 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4472 if (element->IsString() &&
4473 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4474 return true;
4475 }
4476 }
4477 return false;
4478}
4479
4480
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004481MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4482 Code::Flags flags,
4483 Code* code) {
4484 // Initialize cache if necessary.
4485 if (cache()->IsUndefined()) {
4486 Object* result;
4487 { MaybeObject* maybe_result =
4488 PolymorphicCodeCacheHashTable::Allocate(
4489 PolymorphicCodeCacheHashTable::kInitialSize);
4490 if (!maybe_result->ToObject(&result)) return maybe_result;
4491 }
4492 set_cache(result);
4493 } else {
4494 // This entry shouldn't be contained in the cache yet.
4495 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4496 ->Lookup(maps, flags)->IsUndefined());
4497 }
4498 PolymorphicCodeCacheHashTable* hash_table =
4499 PolymorphicCodeCacheHashTable::cast(cache());
4500 Object* new_cache;
4501 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4502 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4503 }
4504 set_cache(new_cache);
4505 return this;
4506}
4507
4508
4509Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4510 if (!cache()->IsUndefined()) {
4511 PolymorphicCodeCacheHashTable* hash_table =
4512 PolymorphicCodeCacheHashTable::cast(cache());
4513 return hash_table->Lookup(maps, flags);
4514 } else {
4515 return GetHeap()->undefined_value();
4516 }
4517}
4518
4519
4520// Despite their name, object of this class are not stored in the actual
4521// hash table; instead they're temporarily used for lookups. It is therefore
4522// safe to have a weak (non-owning) pointer to a MapList as a member field.
4523class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4524 public:
4525 // Callers must ensure that |maps| outlives the newly constructed object.
4526 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4527 : maps_(maps),
4528 code_flags_(code_flags) {}
4529
4530 bool IsMatch(Object* other) {
4531 MapList other_maps(kDefaultListAllocationSize);
4532 int other_flags;
4533 FromObject(other, &other_flags, &other_maps);
4534 if (code_flags_ != other_flags) return false;
4535 if (maps_->length() != other_maps.length()) return false;
4536 // Compare just the hashes first because it's faster.
4537 int this_hash = MapsHashHelper(maps_, code_flags_);
4538 int other_hash = MapsHashHelper(&other_maps, other_flags);
4539 if (this_hash != other_hash) return false;
4540
4541 // Full comparison: for each map in maps_, look for an equivalent map in
4542 // other_maps. This implementation is slow, but probably good enough for
4543 // now because the lists are short (<= 4 elements currently).
4544 for (int i = 0; i < maps_->length(); ++i) {
4545 bool match_found = false;
4546 for (int j = 0; j < other_maps.length(); ++j) {
4547 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
4548 match_found = true;
4549 break;
4550 }
4551 }
4552 if (!match_found) return false;
4553 }
4554 return true;
4555 }
4556
4557 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4558 uint32_t hash = code_flags;
4559 for (int i = 0; i < maps->length(); ++i) {
4560 hash ^= maps->at(i)->Hash();
4561 }
4562 return hash;
4563 }
4564
4565 uint32_t Hash() {
4566 return MapsHashHelper(maps_, code_flags_);
4567 }
4568
4569 uint32_t HashForObject(Object* obj) {
4570 MapList other_maps(kDefaultListAllocationSize);
4571 int other_flags;
4572 FromObject(obj, &other_flags, &other_maps);
4573 return MapsHashHelper(&other_maps, other_flags);
4574 }
4575
4576 MUST_USE_RESULT MaybeObject* AsObject() {
4577 Object* obj;
4578 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4579 // both because the referenced MapList is short-lived, and because C++
4580 // objects can't be stored in the heap anyway.
4581 { MaybeObject* maybe_obj =
4582 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4583 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4584 }
4585 FixedArray* list = FixedArray::cast(obj);
4586 list->set(0, Smi::FromInt(code_flags_));
4587 for (int i = 0; i < maps_->length(); ++i) {
4588 list->set(i + 1, maps_->at(i));
4589 }
4590 return list;
4591 }
4592
4593 private:
4594 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4595 FixedArray* list = FixedArray::cast(obj);
4596 maps->Rewind(0);
4597 *code_flags = Smi::cast(list->get(0))->value();
4598 for (int i = 1; i < list->length(); ++i) {
4599 maps->Add(Map::cast(list->get(i)));
4600 }
4601 return maps;
4602 }
4603
4604 MapList* maps_; // weak.
4605 int code_flags_;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004606 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004607};
4608
4609
4610Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4611 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4612 int entry = FindEntry(&key);
4613 if (entry == kNotFound) return GetHeap()->undefined_value();
4614 return get(EntryToIndex(entry) + 1);
4615}
4616
4617
4618MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4619 int code_flags,
4620 Code* code) {
4621 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4622 Object* obj;
4623 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4624 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4625 }
4626 PolymorphicCodeCacheHashTable* cache =
4627 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4628 int entry = cache->FindInsertionEntry(key.Hash());
4629 { MaybeObject* maybe_obj = key.AsObject();
4630 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4631 }
4632 cache->set(EntryToIndex(entry), obj);
4633 cache->set(EntryToIndex(entry) + 1, code);
4634 cache->ElementAdded();
4635 return cache;
4636}
4637
4638
lrn@chromium.org303ada72010-10-27 09:33:13 +00004639MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004640 ElementsAccessor* accessor = array->GetElementsAccessor();
4641 MaybeObject* maybe_result =
4642 accessor->AddElementsToFixedArray(array->elements(), this);
4643 FixedArray* result;
4644 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
4645#ifdef DEBUG
4646 if (FLAG_enable_slow_asserts) {
4647 for (int i = 0; i < result->length(); i++) {
4648 Object* current = result->get(i);
4649 ASSERT(current->IsNumber() || current->IsString());
4650 }
4651 }
4652#endif
4653 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004654}
4655
4656
lrn@chromium.org303ada72010-10-27 09:33:13 +00004657MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004658 int len0 = length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004659#ifdef DEBUG
4660 if (FLAG_enable_slow_asserts) {
4661 for (int i = 0; i < len0; i++) {
4662 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4663 }
4664 }
4665#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666 int len1 = other->length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004667 // Optimize if 'other' is empty.
4668 // We cannot optimize if 'this' is empty, as other may have holes
4669 // or non keys.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004670 if (len1 == 0) return this;
4671
4672 // Compute how many elements are not in this.
4673 int extra = 0;
4674 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004675 Object* value = other->get(y);
4676 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 }
4678
ager@chromium.org5ec48922009-05-05 07:25:34 +00004679 if (extra == 0) return this;
4680
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 // Allocate the result
lrn@chromium.org303ada72010-10-27 09:33:13 +00004682 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004683 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004684 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4685 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004686 // Fill in the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004687 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004688 FixedArray* result = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004689 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 for (int i = 0; i < len0; i++) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004691 Object* e = get(i);
4692 ASSERT(e->IsString() || e->IsNumber());
4693 result->set(i, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004694 }
4695 // Fill in the extra keys.
4696 int index = 0;
4697 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004698 Object* value = other->get(y);
4699 if (!value->IsTheHole() && !HasKey(this, value)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004700 Object* e = other->get(y);
4701 ASSERT(e->IsString() || e->IsNumber());
4702 result->set(len0 + index, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703 index++;
4704 }
4705 }
4706 ASSERT(extra == index);
4707 return result;
4708}
4709
4710
lrn@chromium.org303ada72010-10-27 09:33:13 +00004711MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 Heap* heap = GetHeap();
4713 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004714 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004716 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004718 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004720 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004721 int len = length();
4722 if (new_length < len) len = new_length;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004723 result->set_map(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004724 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004725 for (int i = 0; i < len; i++) {
4726 result->set(i, get(i), mode);
4727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004728 return result;
4729}
4730
4731
4732void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004733 AssertNoAllocation no_gc;
4734 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004735 for (int index = 0; index < len; index++) {
4736 dest->set(dest_pos+index, get(pos+index), mode);
4737 }
4738}
4739
4740
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004741#ifdef DEBUG
4742bool FixedArray::IsEqualTo(FixedArray* other) {
4743 if (length() != other->length()) return false;
4744 for (int i = 0 ; i < length(); ++i) {
4745 if (get(i) != other->get(i)) return false;
4746 }
4747 return true;
4748}
4749#endif
4750
4751
lrn@chromium.org303ada72010-10-27 09:33:13 +00004752MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004753 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004754 if (number_of_descriptors == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 return heap->empty_descriptor_array();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004756 }
4757 // Allocate the array of keys.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004758 Object* array;
4759 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004760 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004761 if (!maybe_array->ToObject(&array)) return maybe_array;
4762 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004763 // Do not use DescriptorArray::cast on incomplete object.
4764 FixedArray* result = FixedArray::cast(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765
4766 // Allocate the content array and set it in the descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004767 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 heap->AllocateFixedArray(number_of_descriptors << 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004769 if (!maybe_array->ToObject(&array)) return maybe_array;
4770 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004771 result->set(kBitField3StorageIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 result->set(kContentArrayIndex, array);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004773 result->set(kEnumerationIndexIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004774 Smi::FromInt(PropertyDetails::kInitialIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775 return result;
4776}
4777
4778
4779void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4780 FixedArray* new_cache) {
4781 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4782 if (HasEnumCache()) {
4783 FixedArray::cast(get(kEnumerationIndexIndex))->
4784 set(kEnumCacheBridgeCacheIndex, new_cache);
4785 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004786 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004787 FixedArray::cast(bridge_storage)->
4788 set(kEnumCacheBridgeCacheIndex, new_cache);
4789 fast_set(FixedArray::cast(bridge_storage),
4790 kEnumCacheBridgeEnumIndex,
4791 get(kEnumerationIndexIndex));
4792 set(kEnumerationIndexIndex, bridge_storage);
4793 }
4794}
4795
4796
lrn@chromium.org303ada72010-10-27 09:33:13 +00004797MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4798 TransitionFlag transition_flag) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004799 // Transitions are only kept when inserting another transition.
4800 // This precondition is not required by this function's implementation, but
4801 // is currently required by the semantics of maps, so we check it.
4802 // Conversely, we filter after replacing, so replacing a transition and
4803 // removing all other transitions is not supported.
4804 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4805 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4806 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004807
4808 // Ensure the key is a symbol.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004809 Object* result;
4810 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4811 if (!maybe_result->ToObject(&result)) return maybe_result;
4812 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004814 int transitions = 0;
4815 int null_descriptors = 0;
4816 if (remove_transitions) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004817 for (int i = 0; i < number_of_descriptors(); i++) {
4818 if (IsTransition(i)) transitions++;
4819 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004820 }
4821 } else {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004822 for (int i = 0; i < number_of_descriptors(); i++) {
4823 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004824 }
4825 }
4826 int new_size = number_of_descriptors() - transitions - null_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004827
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004828 // If key is in descriptor, we replace it in-place when filtering.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004829 // Count a null descriptor for key as inserted, not replaced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004830 int index = Search(descriptor->GetKey());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004831 const bool inserting = (index == kNotFound);
4832 const bool replacing = !inserting;
4833 bool keep_enumeration_index = false;
4834 if (inserting) {
4835 ++new_size;
4836 }
4837 if (replacing) {
4838 // We are replacing an existing descriptor. We keep the enumeration
4839 // index of a visible property.
4840 PropertyType t = PropertyDetails(GetDetails(index)).type();
4841 if (t == CONSTANT_FUNCTION ||
4842 t == FIELD ||
4843 t == CALLBACKS ||
4844 t == INTERCEPTOR) {
4845 keep_enumeration_index = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004846 } else if (remove_transitions) {
4847 // Replaced descriptor has been counted as removed if it is
4848 // a transition that will be replaced. Adjust count in this case.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004849 ++new_size;
4850 }
4851 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004852 { MaybeObject* maybe_result = Allocate(new_size);
4853 if (!maybe_result->ToObject(&result)) return maybe_result;
4854 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004855 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 // Set the enumeration index in the descriptors and set the enumeration index
4857 // in the result.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004858 int enumeration_index = NextEnumerationIndex();
4859 if (!descriptor->GetDetails().IsTransition()) {
4860 if (keep_enumeration_index) {
4861 descriptor->SetEnumerationIndex(
4862 PropertyDetails(GetDetails(index)).index());
4863 } else {
4864 descriptor->SetEnumerationIndex(enumeration_index);
4865 ++enumeration_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004867 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004868 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4869
4870 // Copy the descriptors, filtering out transitions and null descriptors,
4871 // and inserting or replacing a descriptor.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004872 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004873 int from_index = 0;
4874 int to_index = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004875
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004876 for (; from_index < number_of_descriptors(); from_index++) {
4877 String* key = GetKey(from_index);
4878 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4879 break;
4880 }
4881 if (IsNullDescriptor(from_index)) continue;
4882 if (remove_transitions && IsTransition(from_index)) continue;
4883 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004884 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004885
4886 new_descriptors->Set(to_index++, descriptor);
4887 if (replacing) from_index++;
4888
4889 for (; from_index < number_of_descriptors(); from_index++) {
4890 if (IsNullDescriptor(from_index)) continue;
4891 if (remove_transitions && IsTransition(from_index)) continue;
4892 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004893 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004894
4895 ASSERT(to_index == new_descriptors->number_of_descriptors());
4896 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004897
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004898 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004899}
4900
4901
lrn@chromium.org303ada72010-10-27 09:33:13 +00004902MaybeObject* DescriptorArray::RemoveTransitions() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004903 // Remove all transitions and null descriptors. Return a copy of the array
4904 // with all transitions removed, or a Failure object if the new array could
4905 // not be allocated.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004906
4907 // Compute the size of the map transition entries to be removed.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004908 int num_removed = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004909 for (int i = 0; i < number_of_descriptors(); i++) {
4910 if (!IsProperty(i)) num_removed++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004911 }
4912
4913 // Allocate the new descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004914 Object* result;
4915 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4916 if (!maybe_result->ToObject(&result)) return maybe_result;
4917 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004918 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4919
4920 // Copy the content.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004921 int next_descriptor = 0;
4922 for (int i = 0; i < number_of_descriptors(); i++) {
4923 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004924 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004925 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004926
4927 return new_descriptors;
4928}
4929
4930
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004931void DescriptorArray::SortUnchecked() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004932 // In-place heap sort.
4933 int len = number_of_descriptors();
4934
4935 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004936 // Index of the last node with children
4937 const int max_parent_index = (len / 2) - 1;
4938 for (int i = max_parent_index; i >= 0; --i) {
4939 int parent_index = i;
4940 const uint32_t parent_hash = GetKey(i)->Hash();
4941 while (parent_index <= max_parent_index) {
4942 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004943 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004944 if (child_index + 1 < len) {
4945 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4946 if (right_child_hash > child_hash) {
4947 child_index++;
4948 child_hash = right_child_hash;
4949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004950 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004951 if (child_hash <= parent_hash) break;
4952 Swap(parent_index, child_index);
4953 // Now element at child_index could be < its children.
4954 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004955 }
4956 }
4957
4958 // Extract elements and create sorted array.
4959 for (int i = len - 1; i > 0; --i) {
4960 // Put max element at the back of the array.
4961 Swap(0, i);
4962 // Sift down the new top element.
4963 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004964 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4965 const int max_parent_index = (i / 2) - 1;
4966 while (parent_index <= max_parent_index) {
4967 int child_index = parent_index * 2 + 1;
4968 uint32_t child_hash = GetKey(child_index)->Hash();
4969 if (child_index + 1 < i) {
4970 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4971 if (right_child_hash > child_hash) {
4972 child_index++;
4973 child_hash = right_child_hash;
4974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004975 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004976 if (child_hash <= parent_hash) break;
4977 Swap(parent_index, child_index);
4978 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004979 }
4980 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004981}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004983
4984void DescriptorArray::Sort() {
4985 SortUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004986 SLOW_ASSERT(IsSortedNoDuplicates());
4987}
4988
4989
4990int DescriptorArray::BinarySearch(String* name, int low, int high) {
4991 uint32_t hash = name->Hash();
4992
4993 while (low <= high) {
4994 int mid = (low + high) / 2;
4995 String* mid_name = GetKey(mid);
4996 uint32_t mid_hash = mid_name->Hash();
4997
4998 if (mid_hash > hash) {
4999 high = mid - 1;
5000 continue;
5001 }
5002 if (mid_hash < hash) {
5003 low = mid + 1;
5004 continue;
5005 }
5006 // Found an element with the same hash-code.
5007 ASSERT(hash == mid_hash);
5008 // There might be more, so we find the first one and
5009 // check them all to see if we have a match.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005010 if (name == mid_name && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5012 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005013 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005014 }
5015 break;
5016 }
5017 return kNotFound;
5018}
5019
5020
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005021int DescriptorArray::LinearSearch(String* name, int len) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005022 uint32_t hash = name->Hash();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005023 for (int number = 0; number < len; number++) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005024 String* entry = GetKey(number);
5025 if ((entry->Hash() == hash) &&
5026 name->Equals(entry) &&
5027 !is_null_descriptor(number)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005028 return number;
5029 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005030 }
5031 return kNotFound;
5032}
5033
5034
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005035MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5036 PretenureFlag pretenure) {
5037 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005038 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005039 pretenure);
5040}
5041
5042
5043MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5044 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005045 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5046 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005047 pretenure);
5048}
5049
5050
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005051#ifdef DEBUG
5052bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5053 if (IsEmpty()) return other->IsEmpty();
5054 if (other->IsEmpty()) return false;
5055 if (length() != other->length()) return false;
5056 for (int i = 0; i < length(); ++i) {
5057 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5058 }
5059 return GetContentArray()->IsEqualTo(other->GetContentArray());
5060}
5061#endif
5062
5063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005064bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005066 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005067}
5068
5069
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005070int String::Utf8Length() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005071 if (IsAsciiRepresentation()) return length();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005072 // Attempt to flatten before accessing the string. It probably
5073 // doesn't make Utf8Length faster, but it is very likely that
5074 // the string will be accessed later (for example by WriteUtf8)
5075 // so it's still a good idea.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005076 Heap* heap = GetHeap();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005077 TryFlatten();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 Access<StringInputBuffer> buffer(
5079 heap->isolate()->objects_string_input_buffer());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005080 buffer->Reset(0, this);
5081 int result = 0;
5082 while (buffer->has_more())
5083 result += unibrow::Utf8::Length(buffer->GetNext());
5084 return result;
5085}
5086
5087
ager@chromium.org7c537e22008-10-16 08:43:32 +00005088Vector<const char> String::ToAsciiVector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005089 ASSERT(IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005090 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005091
5092 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005093 int length = this->length();
5094 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005095 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005096 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005097 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005098 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005099 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005100 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005101 }
5102 if (string_tag == kSeqStringTag) {
5103 SeqAsciiString* seq = SeqAsciiString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005104 char* start = seq->GetChars();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005105 return Vector<const char>(start + offset, length);
5106 }
5107 ASSERT(string_tag == kExternalStringTag);
5108 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
5109 const char* start = ext->resource()->data();
5110 return Vector<const char>(start + offset, length);
5111}
5112
5113
5114Vector<const uc16> String::ToUC16Vector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005115 ASSERT(IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005116 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005117
5118 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005119 int length = this->length();
5120 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005121 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005122 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005123 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005124 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005125 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005126 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005127 }
5128 if (string_tag == kSeqStringTag) {
5129 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005130 return Vector<const uc16>(seq->GetChars() + offset, length);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005131 }
5132 ASSERT(string_tag == kExternalStringTag);
5133 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
5134 const uc16* start =
5135 reinterpret_cast<const uc16*>(ext->resource()->data());
5136 return Vector<const uc16>(start + offset, length);
5137}
5138
5139
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005140SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5141 RobustnessFlag robust_flag,
5142 int offset,
5143 int length,
5144 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005145 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
5146 return SmartPointer<char>(NULL);
5147 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005148 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005149
5150 // Negative length means the to the end of the string.
5151 if (length < 0) length = kMaxInt - offset;
5152
5153 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005154 Access<StringInputBuffer> buffer(
5155 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005156 buffer->Reset(offset, this);
5157 int character_position = offset;
5158 int utf8_bytes = 0;
5159 while (buffer->has_more()) {
5160 uint16_t character = buffer->GetNext();
5161 if (character_position < offset + length) {
5162 utf8_bytes += unibrow::Utf8::Length(character);
5163 }
5164 character_position++;
5165 }
5166
5167 if (length_return) {
5168 *length_return = utf8_bytes;
5169 }
5170
5171 char* result = NewArray<char>(utf8_bytes + 1);
5172
5173 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5174 buffer->Rewind();
5175 buffer->Seek(offset);
5176 character_position = offset;
5177 int utf8_byte_position = 0;
5178 while (buffer->has_more()) {
5179 uint16_t character = buffer->GetNext();
5180 if (character_position < offset + length) {
5181 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5182 character = ' ';
5183 }
5184 utf8_byte_position +=
5185 unibrow::Utf8::Encode(result + utf8_byte_position, character);
5186 }
5187 character_position++;
5188 }
5189 result[utf8_byte_position] = 0;
5190 return SmartPointer<char>(result);
5191}
5192
5193
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00005194SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5195 RobustnessFlag robust_flag,
5196 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5198}
5199
5200
5201const uc16* String::GetTwoByteData() {
5202 return GetTwoByteData(0);
5203}
5204
5205
5206const uc16* String::GetTwoByteData(unsigned start) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005207 ASSERT(!IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005208 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005209 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00005210 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 case kExternalStringTag:
5212 return ExternalTwoByteString::cast(this)->
5213 ExternalTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005214 case kConsStringTag:
5215 UNREACHABLE();
5216 return NULL;
5217 }
5218 UNREACHABLE();
5219 return NULL;
5220}
5221
5222
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005223SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005224 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005225 return SmartPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005227 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 Access<StringInputBuffer> buffer(
5230 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005231 buffer->Reset(this);
5232
5233 uc16* result = NewArray<uc16>(length() + 1);
5234
5235 int i = 0;
5236 while (buffer->has_more()) {
5237 uint16_t character = buffer->GetNext();
5238 result[i++] = character;
5239 }
5240 result[i] = 0;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005241 return SmartPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242}
5243
5244
ager@chromium.org7c537e22008-10-16 08:43:32 +00005245const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005246 return reinterpret_cast<uc16*>(
5247 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5248}
5249
5250
ager@chromium.org7c537e22008-10-16 08:43:32 +00005251void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005252 unsigned* offset_ptr,
5253 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005254 unsigned chars_read = 0;
5255 unsigned offset = *offset_ptr;
5256 while (chars_read < max_chars) {
5257 uint16_t c = *reinterpret_cast<uint16_t*>(
5258 reinterpret_cast<char*>(this) -
5259 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5260 if (c <= kMaxAsciiCharCode) {
5261 // Fast case for ASCII characters. Cursor is an input output argument.
5262 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5263 rbb->util_buffer,
5264 rbb->capacity,
5265 rbb->cursor)) {
5266 break;
5267 }
5268 } else {
5269 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5270 rbb->util_buffer,
5271 rbb->capacity,
5272 rbb->cursor)) {
5273 break;
5274 }
5275 }
5276 offset++;
5277 chars_read++;
5278 }
5279 *offset_ptr = offset;
5280 rbb->remaining += chars_read;
5281}
5282
5283
ager@chromium.org7c537e22008-10-16 08:43:32 +00005284const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5285 unsigned* remaining,
5286 unsigned* offset_ptr,
5287 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5289 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5290 *remaining = max_chars;
5291 *offset_ptr += max_chars;
5292 return b;
5293}
5294
5295
5296// This will iterate unless the block of string data spans two 'halves' of
5297// a ConsString, in which case it will recurse. Since the block of string
5298// data to be read has a maximum size this limits the maximum recursion
5299// depth to something sane. Since C++ does not have tail call recursion
5300// elimination, the iteration must be explicit. Since this is not an
5301// -IntoBuffer method it can delegate to one of the efficient
5302// *AsciiStringReadBlock routines.
5303const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5304 unsigned* offset_ptr,
5305 unsigned max_chars) {
5306 ConsString* current = this;
5307 unsigned offset = *offset_ptr;
5308 int offset_correction = 0;
5309
5310 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005311 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005312 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 if (left_length > offset &&
5314 (max_chars <= left_length - offset ||
5315 (rbb->capacity <= left_length - offset &&
5316 (max_chars = left_length - offset, true)))) { // comma operator!
5317 // Left hand side only - iterate unless we have reached the bottom of
5318 // the cons tree. The assignment on the left of the comma operator is
5319 // in order to make use of the fact that the -IntoBuffer routines can
5320 // produce at most 'capacity' characters. This enables us to postpone
5321 // the point where we switch to the -IntoBuffer routines (below) in order
5322 // to maximize the chances of delegating a big chunk of work to the
5323 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005324 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 current = ConsString::cast(left);
5326 continue;
5327 } else {
5328 const unibrow::byte* answer =
5329 String::ReadBlock(left, rbb, &offset, max_chars);
5330 *offset_ptr = offset + offset_correction;
5331 return answer;
5332 }
5333 } else if (left_length <= offset) {
5334 // Right hand side only - iterate unless we have reached the bottom of
5335 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005336 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005337 offset -= left_length;
5338 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005339 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005340 current = ConsString::cast(right);
5341 continue;
5342 } else {
5343 const unibrow::byte* answer =
5344 String::ReadBlock(right, rbb, &offset, max_chars);
5345 *offset_ptr = offset + offset_correction;
5346 return answer;
5347 }
5348 } else {
5349 // The block to be read spans two sides of the ConsString, so we call the
5350 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5351 // are able to assemble data from several part strings because they use
5352 // the util_buffer to store their data and never return direct pointers
5353 // to their storage. We don't try to read more than the buffer capacity
5354 // here or we can get too much recursion.
5355 ASSERT(rbb->remaining == 0);
5356 ASSERT(rbb->cursor == 0);
5357 current->ConsStringReadBlockIntoBuffer(
5358 rbb,
5359 &offset,
5360 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5361 *offset_ptr = offset + offset_correction;
5362 return rbb->util_buffer;
5363 }
5364 }
5365}
5366
5367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005368uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5369 ASSERT(index >= 0 && index < length());
5370 return resource()->data()[index];
5371}
5372
5373
5374const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5375 unsigned* remaining,
5376 unsigned* offset_ptr,
5377 unsigned max_chars) {
5378 // Cast const char* to unibrow::byte* (signedness difference).
5379 const unibrow::byte* b =
5380 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
5381 *remaining = max_chars;
5382 *offset_ptr += max_chars;
5383 return b;
5384}
5385
5386
5387const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5388 unsigned start) {
5389 return resource()->data() + start;
5390}
5391
5392
5393uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5394 ASSERT(index >= 0 && index < length());
5395 return resource()->data()[index];
5396}
5397
5398
5399void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5400 ReadBlockBuffer* rbb,
5401 unsigned* offset_ptr,
5402 unsigned max_chars) {
5403 unsigned chars_read = 0;
5404 unsigned offset = *offset_ptr;
5405 const uint16_t* data = resource()->data();
5406 while (chars_read < max_chars) {
5407 uint16_t c = data[offset];
5408 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00005409 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005410 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5411 rbb->util_buffer,
5412 rbb->capacity,
5413 rbb->cursor))
5414 break;
5415 } else {
5416 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5417 rbb->util_buffer,
5418 rbb->capacity,
5419 rbb->cursor))
5420 break;
5421 }
5422 offset++;
5423 chars_read++;
5424 }
5425 *offset_ptr = offset;
5426 rbb->remaining += chars_read;
5427}
5428
5429
ager@chromium.org7c537e22008-10-16 08:43:32 +00005430void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005431 unsigned* offset_ptr,
5432 unsigned max_chars) {
5433 unsigned capacity = rbb->capacity - rbb->cursor;
5434 if (max_chars > capacity) max_chars = capacity;
5435 memcpy(rbb->util_buffer + rbb->cursor,
5436 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5437 *offset_ptr * kCharSize,
5438 max_chars);
5439 rbb->remaining += max_chars;
5440 *offset_ptr += max_chars;
5441 rbb->cursor += max_chars;
5442}
5443
5444
5445void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5446 ReadBlockBuffer* rbb,
5447 unsigned* offset_ptr,
5448 unsigned max_chars) {
5449 unsigned capacity = rbb->capacity - rbb->cursor;
5450 if (max_chars > capacity) max_chars = capacity;
5451 memcpy(rbb->util_buffer + rbb->cursor,
5452 resource()->data() + *offset_ptr,
5453 max_chars);
5454 rbb->remaining += max_chars;
5455 *offset_ptr += max_chars;
5456 rbb->cursor += max_chars;
5457}
5458
5459
5460// This method determines the type of string involved and then copies
5461// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5462// where they can be found. The pointer is not necessarily valid across a GC
5463// (see AsciiStringReadBlock).
5464const unibrow::byte* String::ReadBlock(String* input,
5465 ReadBlockBuffer* rbb,
5466 unsigned* offset_ptr,
5467 unsigned max_chars) {
5468 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5469 if (max_chars == 0) {
5470 rbb->remaining = 0;
5471 return NULL;
5472 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005473 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005474 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005475 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005476 SeqAsciiString* str = SeqAsciiString::cast(input);
5477 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5478 offset_ptr,
5479 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005480 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005481 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5482 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5483 offset_ptr,
5484 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005485 return rbb->util_buffer;
5486 }
5487 case kConsStringTag:
5488 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5489 offset_ptr,
5490 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005491 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005492 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005493 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5494 &rbb->remaining,
5495 offset_ptr,
5496 max_chars);
5497 } else {
5498 ExternalTwoByteString::cast(input)->
5499 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5500 offset_ptr,
5501 max_chars);
5502 return rbb->util_buffer;
5503 }
5504 default:
5505 break;
5506 }
5507
5508 UNREACHABLE();
5509 return 0;
5510}
5511
5512
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005513void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005514 Isolate* isolate = Isolate::Current();
5515 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005516 while (current != NULL) {
5517 current->PostGarbageCollection();
5518 current = current->prev_;
5519 }
5520}
5521
5522
5523// Reserve space for statics needing saving and restoring.
5524int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005525 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005526}
5527
5528
5529// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005530char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005531 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5532 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005533 return to + ArchiveSpacePerThread();
5534}
5535
5536
5537// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005538char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005539 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005540 return from + ArchiveSpacePerThread();
5541}
5542
5543
5544char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5545 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5546 Iterate(v, top);
5547 return thread_storage + ArchiveSpacePerThread();
5548}
5549
5550
5551void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005552 Isolate* isolate = Isolate::Current();
5553 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005554}
5555
5556
5557void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5558 Relocatable* current = top;
5559 while (current != NULL) {
5560 current->IterateInstance(v);
5561 current = current->prev_;
5562 }
5563}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005564
5565
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005566FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5567 : Relocatable(isolate),
5568 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005569 length_(str->length()) {
5570 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005571}
5572
5573
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005574FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5575 : Relocatable(isolate),
5576 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005577 is_ascii_(true),
5578 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005579 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005580
5581
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005582void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005583 if (str_ == NULL) return;
5584 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005585 ASSERT(str->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00005586 is_ascii_ = str->IsAsciiRepresentation();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005587 if (is_ascii_) {
5588 start_ = str->ToAsciiVector().start();
5589 } else {
5590 start_ = str->ToUC16Vector().start();
5591 }
5592}
5593
5594
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005595void StringInputBuffer::Seek(unsigned pos) {
5596 Reset(pos, input_);
5597}
5598
5599
5600void SafeStringInputBuffer::Seek(unsigned pos) {
5601 Reset(pos, input_);
5602}
5603
5604
5605// This method determines the type of string involved and then copies
5606// a whole chunk of characters into a buffer. It can be used with strings
5607// that have been glued together to form a ConsString and which must cooperate
5608// to fill up a buffer.
5609void String::ReadBlockIntoBuffer(String* input,
5610 ReadBlockBuffer* rbb,
5611 unsigned* offset_ptr,
5612 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005613 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005614 if (max_chars == 0) return;
5615
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005616 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005617 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005618 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005619 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005620 offset_ptr,
5621 max_chars);
5622 return;
5623 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005624 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005625 offset_ptr,
5626 max_chars);
5627 return;
5628 }
5629 case kConsStringTag:
5630 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5631 offset_ptr,
5632 max_chars);
5633 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005634 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005635 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005636 ExternalAsciiString::cast(input)->
5637 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5638 } else {
5639 ExternalTwoByteString::cast(input)->
5640 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5641 offset_ptr,
5642 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 }
5644 return;
5645 default:
5646 break;
5647 }
5648
5649 UNREACHABLE();
5650 return;
5651}
5652
5653
5654const unibrow::byte* String::ReadBlock(String* input,
5655 unibrow::byte* util_buffer,
5656 unsigned capacity,
5657 unsigned* remaining,
5658 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005659 ASSERT(*offset_ptr <= (unsigned)input->length());
5660 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005661 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5662 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005663 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 *remaining = rbb.remaining;
5665 return answer;
5666}
5667
5668
5669const unibrow::byte* String::ReadBlock(String** raw_input,
5670 unibrow::byte* util_buffer,
5671 unsigned capacity,
5672 unsigned* remaining,
5673 unsigned* offset_ptr) {
5674 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005675 ASSERT(*offset_ptr <= (unsigned)input->length());
5676 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677 if (chars > capacity) chars = capacity;
5678 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5679 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005680 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005681 *remaining = rbb.remaining;
5682 return rbb.util_buffer;
5683}
5684
5685
5686// This will iterate unless the block of string data spans two 'halves' of
5687// a ConsString, in which case it will recurse. Since the block of string
5688// data to be read has a maximum size this limits the maximum recursion
5689// depth to something sane. Since C++ does not have tail call recursion
5690// elimination, the iteration must be explicit.
5691void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5692 unsigned* offset_ptr,
5693 unsigned max_chars) {
5694 ConsString* current = this;
5695 unsigned offset = *offset_ptr;
5696 int offset_correction = 0;
5697
5698 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005699 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005700 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005701 if (left_length > offset &&
5702 max_chars <= left_length - offset) {
5703 // Left hand side only - iterate unless we have reached the bottom of
5704 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005705 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005706 current = ConsString::cast(left);
5707 continue;
5708 } else {
5709 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5710 *offset_ptr = offset + offset_correction;
5711 return;
5712 }
5713 } else if (left_length <= offset) {
5714 // Right hand side only - iterate unless we have reached the bottom of
5715 // the cons tree.
5716 offset -= left_length;
5717 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005718 String* right = current->second();
5719 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005720 current = ConsString::cast(right);
5721 continue;
5722 } else {
5723 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5724 *offset_ptr = offset + offset_correction;
5725 return;
5726 }
5727 } else {
5728 // The block to be read spans two sides of the ConsString, so we recurse.
5729 // First recurse on the left.
5730 max_chars -= left_length - offset;
5731 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5732 // We may have reached the max or there may not have been enough space
5733 // in the buffer for the characters in the left hand side.
5734 if (offset == left_length) {
5735 // Recurse on the right.
5736 String* right = String::cast(current->second());
5737 offset -= left_length;
5738 offset_correction += left_length;
5739 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5740 }
5741 *offset_ptr = offset + offset_correction;
5742 return;
5743 }
5744 }
5745}
5746
5747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748uint16_t ConsString::ConsStringGet(int index) {
5749 ASSERT(index >= 0 && index < this->length());
5750
5751 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00005752 if (second()->length() == 0) {
5753 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005754 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755 }
5756
5757 String* string = String::cast(this);
5758
5759 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005760 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005761 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005762 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005763 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005764 string = left;
5765 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005766 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005767 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005768 }
5769 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005770 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771 }
5772 }
5773
5774 UNREACHABLE();
5775 return 0;
5776}
5777
5778
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005779template <typename sinkchar>
5780void String::WriteToFlat(String* src,
5781 sinkchar* sink,
5782 int f,
5783 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005784 String* source = src;
5785 int from = f;
5786 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005787 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005788 ASSERT(0 <= from && from <= to && to <= source->length());
5789 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005790 case kAsciiStringTag | kExternalStringTag: {
5791 CopyChars(sink,
5792 ExternalAsciiString::cast(source)->resource()->data() + from,
5793 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005794 return;
5795 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005796 case kTwoByteStringTag | kExternalStringTag: {
5797 const uc16* data =
5798 ExternalTwoByteString::cast(source)->resource()->data();
5799 CopyChars(sink,
5800 data + from,
5801 to - from);
5802 return;
5803 }
5804 case kAsciiStringTag | kSeqStringTag: {
5805 CopyChars(sink,
5806 SeqAsciiString::cast(source)->GetChars() + from,
5807 to - from);
5808 return;
5809 }
5810 case kTwoByteStringTag | kSeqStringTag: {
5811 CopyChars(sink,
5812 SeqTwoByteString::cast(source)->GetChars() + from,
5813 to - from);
5814 return;
5815 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005816 case kAsciiStringTag | kConsStringTag:
5817 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005818 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005819 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005820 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005821 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005822 // Right hand side is longer. Recurse over left.
5823 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005824 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005825 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005826 from = 0;
5827 } else {
5828 from -= boundary;
5829 }
5830 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005831 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005833 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005834 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005835 String* second = cons_string->second();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005836 WriteToFlat(second,
5837 sink + boundary - from,
5838 0,
5839 to - boundary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005840 to = boundary;
5841 }
5842 source = first;
5843 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005844 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005845 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005846 }
5847 }
5848}
5849
5850
ager@chromium.org7c537e22008-10-16 08:43:32 +00005851template <typename IteratorA, typename IteratorB>
5852static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5853 // General slow case check. We know that the ia and ib iterators
5854 // have the same length.
5855 while (ia->has_more()) {
5856 uc32 ca = ia->GetNext();
5857 uc32 cb = ib->GetNext();
5858 if (ca != cb)
5859 return false;
5860 }
5861 return true;
5862}
5863
5864
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005865// Compares the contents of two strings by reading and comparing
5866// int-sized blocks of characters.
5867template <typename Char>
5868static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5869 int length = a.length();
5870 ASSERT_EQ(length, b.length());
5871 const Char* pa = a.start();
5872 const Char* pb = b.start();
5873 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00005874#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005875 // If this architecture isn't comfortable reading unaligned ints
5876 // then we have to check that the strings are aligned before
5877 // comparing them blockwise.
5878 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5879 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5880 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005881 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005882#endif
5883 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5884 int endpoint = length - kStepSize;
5885 // Compare blocks until we reach near the end of the string.
5886 for (; i <= endpoint; i += kStepSize) {
5887 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5888 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5889 if (wa != wb) {
5890 return false;
5891 }
5892 }
ager@chromium.org9085a012009-05-11 19:22:57 +00005893#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005894 }
5895#endif
5896 // Compare the remaining characters that didn't fit into a block.
5897 for (; i < length; i++) {
5898 if (a[i] != b[i]) {
5899 return false;
5900 }
5901 }
5902 return true;
5903}
5904
5905
ager@chromium.org7c537e22008-10-16 08:43:32 +00005906template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005907static inline bool CompareStringContentsPartial(Isolate* isolate,
5908 IteratorA* ia,
5909 String* b) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005910 if (b->IsFlat()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005911 if (b->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005912 VectorIterator<char> ib(b->ToAsciiVector());
5913 return CompareStringContents(ia, &ib);
5914 } else {
ager@chromium.org9085a012009-05-11 19:22:57 +00005915 VectorIterator<uc16> ib(b->ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005916 return CompareStringContents(ia, &ib);
5917 }
5918 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5920 return CompareStringContents(ia,
5921 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005922 }
5923}
5924
5925
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005926bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005928 int len = length();
5929 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005930 if (len == 0) return true;
5931
5932 // Fast check: if hash code is computed for both strings
5933 // a fast negative check can be performed.
5934 if (HasHashCode() && other->HasHashCode()) {
5935 if (Hash() != other->Hash()) return false;
5936 }
5937
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005938 // We know the strings are both non-empty. Compare the first chars
5939 // before we try to flatten the strings.
5940 if (this->Get(0) != other->Get(0)) return false;
5941
5942 String* lhs = this->TryFlattenGetString();
5943 String* rhs = other->TryFlattenGetString();
5944
5945 if (StringShape(lhs).IsSequentialAscii() &&
5946 StringShape(rhs).IsSequentialAscii()) {
5947 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5948 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005949 return CompareRawStringContents(Vector<const char>(str1, len),
5950 Vector<const char>(str2, len));
5951 }
5952
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005953 Isolate* isolate = GetIsolate();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005954 if (lhs->IsFlat()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00005955 if (lhs->IsAsciiRepresentation()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005956 Vector<const char> vec1 = lhs->ToAsciiVector();
5957 if (rhs->IsFlat()) {
5958 if (rhs->IsAsciiRepresentation()) {
5959 Vector<const char> vec2 = rhs->ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005960 return CompareRawStringContents(vec1, vec2);
5961 } else {
5962 VectorIterator<char> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005963 VectorIterator<uc16> ib(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005964 return CompareStringContents(&buf1, &ib);
5965 }
5966 } else {
5967 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005968 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5969 return CompareStringContents(&buf1,
5970 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005971 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005972 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005973 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5974 if (rhs->IsFlat()) {
5975 if (rhs->IsAsciiRepresentation()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005976 VectorIterator<uc16> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005977 VectorIterator<char> ib(rhs->ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005978 return CompareStringContents(&buf1, &ib);
5979 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005980 Vector<const uc16> vec2(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005981 return CompareRawStringContents(vec1, vec2);
5982 }
5983 } else {
5984 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005985 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5986 return CompareStringContents(&buf1,
5987 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005990 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005991 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5992 return CompareStringContentsPartial(isolate,
5993 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995}
5996
5997
5998bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005999 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000
6001 Map* map = this->map();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006002 Heap* heap = map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006003 if (map == heap->string_map()) {
6004 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006005 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006006 } else if (map == heap->ascii_string_map()) {
6007 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 return true;
6009 }
6010 // Rest cannot be marked as undetectable
6011 return false;
6012}
6013
6014
6015bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006016 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006017 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006018 Access<UnicodeCache::Utf8Decoder>
6019 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006020 decoder->Reset(str.start(), str.length());
6021 int i;
6022 for (i = 0; i < slen && decoder->has_more(); i++) {
6023 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006024 if (Get(i) != r) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025 }
6026 return i == slen && !decoder->has_more();
6027}
6028
6029
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006030bool String::IsAsciiEqualTo(Vector<const char> str) {
6031 int slen = length();
6032 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006033 if (IsFlat() && IsAsciiRepresentation()) {
6034 return CompareChars(ToAsciiVector().start(), str.start(), slen) == 0;
6035 }
6036 for (int i = 0; i < slen; i++) {
6037 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006038 }
6039 return true;
6040}
6041
6042
6043bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6044 int slen = length();
6045 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006046 if (IsFlat() && IsTwoByteRepresentation()) {
6047 return CompareChars(ToUC16Vector().start(), str.start(), slen) == 0;
6048 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006049 for (int i = 0; i < slen; i++) {
6050 if (Get(i) != str[i]) return false;
6051 }
6052 return true;
6053}
6054
6055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006056uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006057 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006058 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006059
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006060 const int len = length();
6061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006063 uint32_t field = 0;
6064 if (StringShape(this).IsSequentialAscii()) {
6065 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
6066 } else if (StringShape(this).IsSequentialTwoByte()) {
6067 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
6068 } else {
6069 StringInputBuffer buffer(this);
6070 field = ComputeHashField(&buffer, len);
6071 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006072
6073 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006074 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075
6076 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006077 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006078 uint32_t result = field >> kHashShift;
6079 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6080 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081}
6082
6083
6084bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6085 uint32_t* index,
6086 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006087 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006088 uc32 ch = buffer->GetNext();
6089
6090 // If the string begins with a '0' character, it must only consist
6091 // of it to be a legal array index.
6092 if (ch == '0') {
6093 *index = 0;
6094 return length == 1;
6095 }
6096
6097 // Convert string to uint32 array index; character by character.
6098 int d = ch - '0';
6099 if (d < 0 || d > 9) return false;
6100 uint32_t result = d;
6101 while (buffer->has_more()) {
6102 d = buffer->GetNext() - '0';
6103 if (d < 0 || d > 9) return false;
6104 // Check that the new result is below the 32 bit limit.
6105 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6106 result = (result * 10) + d;
6107 }
6108
6109 *index = result;
6110 return true;
6111}
6112
6113
6114bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006115 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006116 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006117 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006118 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006119 // Isolate the array index form the full hash field.
6120 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006121 return true;
6122 } else {
6123 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006124 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006126}
6127
6128
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006129uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006130 // For array indexes mix the length into the hash as an array index could
6131 // be zero.
6132 ASSERT(length > 0);
6133 ASSERT(length <= String::kMaxArrayIndexSize);
6134 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6135 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006136
6137 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006138 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006139
6140 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6141 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6142 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006143 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144}
6145
6146
ager@chromium.org7c537e22008-10-16 08:43:32 +00006147uint32_t StringHasher::GetHashField() {
6148 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006149 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006150 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006151 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006152 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006153 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006154 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006155 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006156 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006157}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006158
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006159
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006160uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
6161 int length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006162 StringHasher hasher(length);
6163
6164 // Very long strings have a trivial hash that doesn't inspect the
6165 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006166 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006167 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006168 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006169
6170 // Do the iterative array index computation as long as there is a
6171 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006172 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006173 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006174 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006175
6176 // Process the remaining characters without updating the array
6177 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006178 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006179 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006180 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006181
6182 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183}
6184
6185
lrn@chromium.org303ada72010-10-27 09:33:13 +00006186MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006187 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006189 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006190 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006191}
6192
6193
6194void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006195 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006196 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006197 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006198 }
6199}
6200
6201
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006202void Map::CreateBackPointers() {
6203 DescriptorArray* descriptors = instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006204 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006205 if (descriptors->GetType(i) == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006206 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006207 descriptors->GetType(i) == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006208 // Get target.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006209 Map* target = Map::cast(descriptors->GetValue(i));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006210#ifdef DEBUG
6211 // Verify target.
6212 Object* source_prototype = prototype();
6213 Object* target_prototype = target->prototype();
6214 ASSERT(source_prototype->IsJSObject() ||
6215 source_prototype->IsMap() ||
6216 source_prototype->IsNull());
6217 ASSERT(target_prototype->IsJSObject() ||
6218 target_prototype->IsNull());
6219 ASSERT(source_prototype->IsMap() ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006220 source_prototype == target_prototype);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006221#endif
6222 // Point target back to source. set_prototype() will not let us set
6223 // the prototype to a map, as we do here.
6224 *RawField(target, kPrototypeOffset) = this;
6225 }
6226 }
6227}
6228
6229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006230void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006231 // Live DescriptorArray objects will be marked, so we must use
6232 // low-level accessors to get and modify their data.
6233 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00006234 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6235 if (d->IsEmpty()) return;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006236 Smi* NullDescriptorDetails =
6237 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
6238 FixedArray* contents = reinterpret_cast<FixedArray*>(
6239 d->get(DescriptorArray::kContentArrayIndex));
6240 ASSERT(contents->length() >= 2);
6241 for (int i = 0; i < contents->length(); i += 2) {
6242 // If the pair (value, details) is a map transition,
6243 // check if the target is live. If not, null the descriptor.
6244 // Also drop the back pointer for that map transition, so that this
6245 // map is not reached again by following a back pointer from a
6246 // non-live object.
6247 PropertyDetails details(Smi::cast(contents->get(i + 1)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006248 if (details.type() == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006249 details.type() == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006250 details.type() == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006251 Map* target = reinterpret_cast<Map*>(contents->get(i));
6252 ASSERT(target->IsHeapObject());
6253 if (!target->IsMarked()) {
6254 ASSERT(target->IsMap());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006255 contents->set_unchecked(i + 1, NullDescriptorDetails);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006256 contents->set_null_unchecked(heap, i);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006257 ASSERT(target->prototype() == this ||
6258 target->prototype() == real_prototype);
6259 // Getter prototype() is read-only, set_prototype() has side effects.
6260 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6261 }
6262 }
6263 }
6264}
6265
6266
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00006267int Map::Hash() {
6268 // For performance reasons we only hash the 3 most variable fields of a map:
6269 // constructor, prototype and bit_field2.
6270
6271 // Shift away the tag.
6272 int hash = (static_cast<uint32_t>(
6273 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6274
6275 // XOR-ing the prototype and constructor directly yields too many zero bits
6276 // when the two pointers are close (which is fairly common).
6277 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6278 hash ^= (static_cast<uint32_t>(
6279 reinterpret_cast<uintptr_t>(prototype())) << 2);
6280
6281 return hash ^ (hash >> 16) ^ bit_field2();
6282}
6283
6284
6285bool Map::EquivalentToForNormalization(Map* other,
6286 PropertyNormalizationMode mode) {
6287 return
6288 constructor() == other->constructor() &&
6289 prototype() == other->prototype() &&
6290 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6291 0 :
6292 other->inobject_properties()) &&
6293 instance_type() == other->instance_type() &&
6294 bit_field() == other->bit_field() &&
6295 bit_field2() == other->bit_field2() &&
6296 (bit_field3() & ~(1<<Map::kIsShared)) ==
6297 (other->bit_field3() & ~(1<<Map::kIsShared));
6298}
6299
6300
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006301void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6302 // Iterate over all fields in the body but take care in dealing with
6303 // the code entry.
6304 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6305 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6306 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6307}
6308
6309
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006310void JSFunction::MarkForLazyRecompilation() {
6311 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006312 ASSERT(shared()->allows_lazy_compilation() ||
6313 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006314 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006315 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006316}
6317
6318
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006319bool JSFunction::IsInlineable() {
6320 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006321 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006322 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006323 if (!shared_info->script()->IsScript()) return false;
6324 if (shared_info->optimization_disabled()) return false;
6325 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006326 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6327 // If we never ran this (unlikely) then lets try to optimize it.
6328 if (code->kind() != Code::FUNCTION) return true;
6329 return code->optimizable();
6330}
6331
6332
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006333Object* JSFunction::SetInstancePrototype(Object* value) {
6334 ASSERT(value->IsJSObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006336 if (has_initial_map()) {
6337 initial_map()->set_prototype(value);
6338 } else {
6339 // Put the value in the initial map field until an initial map is
6340 // needed. At that point, a new initial map is created and the
6341 // prototype is put into the initial map where it belongs.
6342 set_prototype_or_initial_map(value);
6343 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006344 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006345 return value;
6346}
6347
6348
lrn@chromium.org303ada72010-10-27 09:33:13 +00006349MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006350 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006351 Object* construct_prototype = value;
6352
6353 // If the value is not a JSObject, store the value in the map's
6354 // constructor field so it can be accessed. Also, set the prototype
6355 // used for constructing objects to the original object prototype.
6356 // See ECMA-262 13.2.2.
6357 if (!value->IsJSObject()) {
6358 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006359 // Remove map transitions because they point to maps with a
6360 // different prototype.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006361 Object* new_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006362 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006363 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006364 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006365 Map* new_map = Map::cast(new_object);
6366 Heap* heap = new_map->heap();
6367 set_map(new_map);
6368 new_map->set_constructor(value);
6369 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006370 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006371 heap->isolate()->context()->global_context()->
6372 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006373 } else {
6374 map()->set_non_instance_prototype(false);
6375 }
6376
6377 return SetInstancePrototype(construct_prototype);
6378}
6379
6380
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006381Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006382 Context* global_context = context()->global_context();
6383 Map* no_prototype_map = shared()->strict_mode()
6384 ? global_context->strict_mode_function_without_prototype_map()
6385 : global_context->function_without_prototype_map();
6386
6387 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006388 // Be idempotent.
6389 return this;
6390 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006391
6392 ASSERT(!shared()->strict_mode() ||
6393 map() == global_context->strict_mode_function_map());
6394 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
6395
6396 set_map(no_prototype_map);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006397 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006398 return this;
6399}
6400
6401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006402Object* JSFunction::SetInstanceClassName(String* name) {
6403 shared()->set_instance_class_name(name);
6404 return this;
6405}
6406
6407
whesse@chromium.org023421e2010-12-21 12:19:12 +00006408void JSFunction::PrintName(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006409 SmartPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006410 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006411}
6412
6413
ager@chromium.org236ad962008-09-25 09:45:57 +00006414Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6415 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6416}
6417
6418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006419MaybeObject* Oddball::Initialize(const char* to_string,
6420 Object* to_number,
6421 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006422 Object* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006423 { MaybeObject* maybe_symbol =
6424 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006425 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6426 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006427 set_to_string(String::cast(symbol));
6428 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006429 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006430 return this;
6431}
6432
6433
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006434String* SharedFunctionInfo::DebugName() {
6435 Object* n = name();
6436 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6437 return String::cast(n);
6438}
6439
6440
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006441bool SharedFunctionInfo::HasSourceCode() {
6442 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006443 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006444}
6445
6446
6447Object* SharedFunctionInfo::GetSourceCode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006448 Isolate* isolate = GetIsolate();
6449 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6450 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006451 Object* source = Script::cast(script())->source();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 return *SubString(Handle<String>(String::cast(source), isolate),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006453 start_position(), end_position());
6454}
6455
6456
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006457int SharedFunctionInfo::SourceSize() {
6458 return end_position() - start_position();
6459}
6460
6461
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006462int SharedFunctionInfo::CalculateInstanceSize() {
6463 int instance_size =
6464 JSObject::kHeaderSize +
6465 expected_nof_properties() * kPointerSize;
6466 if (instance_size > JSObject::kMaxInstanceSize) {
6467 instance_size = JSObject::kMaxInstanceSize;
6468 }
6469 return instance_size;
6470}
6471
6472
6473int SharedFunctionInfo::CalculateInObjectProperties() {
6474 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6475}
6476
6477
ager@chromium.org5c838252010-02-19 08:53:10 +00006478bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6479 // Check the basic conditions for generating inline constructor code.
6480 if (!FLAG_inline_new
6481 || !has_only_simple_this_property_assignments()
6482 || this_property_assignments_count() == 0) {
6483 return false;
6484 }
6485
6486 // If the prototype is null inline constructors cause no problems.
6487 if (!prototype->IsJSObject()) {
6488 ASSERT(prototype->IsNull());
6489 return true;
6490 }
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492 Heap* heap = GetHeap();
6493
ager@chromium.org5c838252010-02-19 08:53:10 +00006494 // Traverse the proposed prototype chain looking for setters for properties of
6495 // the same names as are set by the inline constructor.
6496 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006497 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00006498 obj = obj->GetPrototype()) {
6499 JSObject* js_object = JSObject::cast(obj);
6500 for (int i = 0; i < this_property_assignments_count(); i++) {
6501 LookupResult result;
6502 String* name = GetThisPropertyAssignmentName(i);
6503 js_object->LocalLookupRealNamedProperty(name, &result);
6504 if (result.IsProperty() && result.type() == CALLBACKS) {
6505 return false;
6506 }
6507 }
6508 }
6509
6510 return true;
6511}
6512
6513
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00006514void SharedFunctionInfo::ForbidInlineConstructor() {
6515 set_compiler_hints(BooleanBit::set(compiler_hints(),
6516 kHasOnlySimpleThisPropertyAssignments,
6517 false));
6518}
6519
6520
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006521void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006522 bool only_simple_this_property_assignments,
6523 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006524 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006525 kHasOnlySimpleThisPropertyAssignments,
6526 only_simple_this_property_assignments));
6527 set_this_property_assignments(assignments);
6528 set_this_property_assignments_count(assignments->length() / 3);
6529}
6530
6531
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006532void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006533 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006534 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006535 kHasOnlySimpleThisPropertyAssignments,
6536 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006537 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006538 set_this_property_assignments_count(0);
6539}
6540
6541
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006542String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6543 Object* obj = this_property_assignments();
6544 ASSERT(obj->IsFixedArray());
6545 ASSERT(index < this_property_assignments_count());
6546 obj = FixedArray::cast(obj)->get(index * 3);
6547 ASSERT(obj->IsString());
6548 return String::cast(obj);
6549}
6550
6551
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006552bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6553 Object* obj = this_property_assignments();
6554 ASSERT(obj->IsFixedArray());
6555 ASSERT(index < this_property_assignments_count());
6556 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6557 return Smi::cast(obj)->value() != -1;
6558}
6559
6560
6561int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6562 ASSERT(IsThisPropertyAssignmentArgument(index));
6563 Object* obj =
6564 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6565 return Smi::cast(obj)->value();
6566}
6567
6568
6569Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6570 ASSERT(!IsThisPropertyAssignmentArgument(index));
6571 Object* obj =
6572 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6573 return obj;
6574}
6575
6576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006577// Support function for printing the source code to a StringStream
6578// without any allocation in the heap.
6579void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6580 int max_length) {
6581 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006582 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 accumulator->Add("<No Source>");
6584 return;
6585 }
6586
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006587 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006588 // Don't use String::cast because we don't want more assertion errors while
6589 // we are already creating a stack dump.
6590 String* script_source =
6591 reinterpret_cast<String*>(Script::cast(script())->source());
6592
6593 if (!script_source->LooksValid()) {
6594 accumulator->Add("<Invalid Source>");
6595 return;
6596 }
6597
6598 if (!is_toplevel()) {
6599 accumulator->Add("function ");
6600 Object* name = this->name();
6601 if (name->IsString() && String::cast(name)->length() > 0) {
6602 accumulator->PrintName(name);
6603 }
6604 }
6605
6606 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006607 if (len <= max_length || max_length < 0) {
6608 accumulator->Put(script_source, start_position(), end_position());
6609 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610 accumulator->Put(script_source,
6611 start_position(),
6612 start_position() + max_length);
6613 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614 }
6615}
6616
6617
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006618static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6619 if (code->instruction_size() != recompiled->instruction_size()) return false;
6620 ByteArray* code_relocation = code->relocation_info();
6621 ByteArray* recompiled_relocation = recompiled->relocation_info();
6622 int length = code_relocation->length();
6623 if (length != recompiled_relocation->length()) return false;
6624 int compare = memcmp(code_relocation->GetDataStartAddress(),
6625 recompiled_relocation->GetDataStartAddress(),
6626 length);
6627 return compare == 0;
6628}
6629
6630
6631void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6632 ASSERT(!has_deoptimization_support());
6633 AssertNoAllocation no_allocation;
6634 Code* code = this->code();
6635 if (IsCodeEquivalent(code, recompiled)) {
6636 // Copy the deoptimization data from the recompiled code.
6637 code->set_deoptimization_data(recompiled->deoptimization_data());
6638 code->set_has_deoptimization_support(true);
6639 } else {
6640 // TODO(3025757): In case the recompiled isn't equivalent to the
6641 // old code, we have to replace it. We should try to avoid this
6642 // altogether because it flushes valuable type feedback by
6643 // effectively resetting all IC state.
6644 set_code(recompiled);
6645 }
6646 ASSERT(has_deoptimization_support());
6647}
6648
6649
ager@chromium.orgea91cc52011-05-23 06:06:11 +00006650void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6651 // Disable optimization for the shared function info and mark the
6652 // code as non-optimizable. The marker on the shared function info
6653 // is there because we flush non-optimized code thereby loosing the
6654 // non-optimizable information for the code. When the code is
6655 // regenerated and set on the shared function info it is marked as
6656 // non-optimizable if optimization is disabled for the shared
6657 // function info.
6658 set_optimization_disabled(true);
6659 // Code should be the lazy compilation stub or else unoptimized. If the
6660 // latter, disable optimization for the code too.
6661 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6662 if (code()->kind() == Code::FUNCTION) {
6663 code()->set_optimizable(false);
6664 }
6665 if (FLAG_trace_opt) {
6666 PrintF("[disabled optimization for: ");
6667 function->PrintName();
6668 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6669 }
6670}
6671
6672
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006673bool SharedFunctionInfo::VerifyBailoutId(int id) {
6674 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6675 // we are always bailing out on ARM.
6676
6677 ASSERT(id != AstNode::kNoNumber);
6678 Code* unoptimized = code();
6679 DeoptimizationOutputData* data =
6680 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6681 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6682 USE(ignore);
6683 return true; // Return true if there was no ASSERT.
6684}
6685
6686
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006687void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6688 ASSERT(!IsInobjectSlackTrackingInProgress());
6689
6690 // Only initiate the tracking the first time.
6691 if (live_objects_may_exist()) return;
6692 set_live_objects_may_exist(true);
6693
6694 // No tracking during the snapshot construction phase.
6695 if (Serializer::enabled()) return;
6696
6697 if (map->unused_property_fields() == 0) return;
6698
6699 // Nonzero counter is a leftover from the previous attempt interrupted
6700 // by GC, keep it.
6701 if (construction_count() == 0) {
6702 set_construction_count(kGenerousAllocationCount);
6703 }
6704 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006705 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006706 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006707 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006708 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006709}
6710
6711
6712// Called from GC, hence reinterpret_cast and unchecked accessors.
6713void SharedFunctionInfo::DetachInitialMap() {
6714 Map* map = reinterpret_cast<Map*>(initial_map());
6715
6716 // Make the map remember to restore the link if it survives the GC.
6717 map->set_bit_field2(
6718 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6719
6720 // Undo state changes made by StartInobjectTracking (except the
6721 // construction_count). This way if the initial map does not survive the GC
6722 // then StartInobjectTracking will be called again the next time the
6723 // constructor is called. The countdown will continue and (possibly after
6724 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006725 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6726 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006727 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006728 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006729 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006730 // It is safe to clear the flag: it will be set again if the map is live.
6731 set_live_objects_may_exist(false);
6732}
6733
6734
6735// Called from GC, hence reinterpret_cast and unchecked accessors.
6736void SharedFunctionInfo::AttachInitialMap(Map* map) {
6737 map->set_bit_field2(
6738 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6739
6740 // Resume inobject slack tracking.
6741 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006742 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006743 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006744 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006745 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006746 // The map survived the gc, so there may be objects referencing it.
6747 set_live_objects_may_exist(true);
6748}
6749
6750
6751static void GetMinInobjectSlack(Map* map, void* data) {
6752 int slack = map->unused_property_fields();
6753 if (*reinterpret_cast<int*>(data) > slack) {
6754 *reinterpret_cast<int*>(data) = slack;
6755 }
6756}
6757
6758
6759static void ShrinkInstanceSize(Map* map, void* data) {
6760 int slack = *reinterpret_cast<int*>(data);
6761 map->set_inobject_properties(map->inobject_properties() - slack);
6762 map->set_unused_property_fields(map->unused_property_fields() - slack);
6763 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6764
6765 // Visitor id might depend on the instance size, recalculate it.
6766 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6767}
6768
6769
6770void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6771 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6772 Map* map = Map::cast(initial_map());
6773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006774 Heap* heap = map->heap();
6775 set_initial_map(heap->undefined_value());
6776 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006777 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006778 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006779 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006780
6781 int slack = map->unused_property_fields();
6782 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6783 if (slack != 0) {
6784 // Resize the initial map and all maps in its transition tree.
6785 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00006786
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006787 // Give the correct expected_nof_properties to initial maps created later.
6788 ASSERT(expected_nof_properties() >= slack);
6789 set_expected_nof_properties(expected_nof_properties() - slack);
6790 }
6791}
6792
6793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006795 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006796 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6797 Object* old_target = target;
6798 VisitPointer(&target);
6799 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006800}
6801
6802
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006803void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6804 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6805 Object* old_code = code;
6806 VisitPointer(&code);
6807 if (code != old_code) {
6808 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6809 }
6810}
6811
6812
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006813void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6814 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6815 Object* cell = rinfo->target_cell();
6816 Object* old_cell = cell;
6817 VisitPointer(&cell);
6818 if (cell != old_cell) {
6819 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6820 }
6821}
6822
6823
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006824void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00006825 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6826 rinfo->IsPatchedReturnSequence()) ||
6827 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6828 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006829 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6830 Object* old_target = target;
6831 VisitPointer(&target);
6832 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833}
6834
6835
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006836void Code::InvalidateRelocation() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006837 set_relocation_info(heap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006838}
6839
6840
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006841void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006842 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6843 it.rinfo()->apply(delta);
6844 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006845 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006846}
6847
6848
6849void Code::CopyFrom(const CodeDesc& desc) {
6850 // copy code
6851 memmove(instruction_start(), desc.buffer, desc.instr_size);
6852
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006853 // copy reloc info
6854 memmove(relocation_start(),
6855 desc.buffer + desc.buffer_size - desc.reloc_size,
6856 desc.reloc_size);
6857
6858 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006859 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006860 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00006861 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006862 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006864 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006866 RelocInfo::Mode mode = it.rinfo()->rmode();
6867 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006868 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006869 it.rinfo()->set_target_object(*p);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006870 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006871 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006872 it.rinfo()->set_target_cell(*cell);
ager@chromium.org236ad962008-09-25 09:45:57 +00006873 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006874 // rewrite code handles in inline cache targets to direct
6875 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006876 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877 Code* code = Code::cast(*p);
6878 it.rinfo()->set_target_address(code->instruction_start());
6879 } else {
6880 it.rinfo()->apply(delta);
6881 }
6882 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006883 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006884}
6885
6886
6887// Locate the source position which is closest to the address in the code. This
6888// is using the source position information embedded in the relocation info.
6889// The position returned is relative to the beginning of the script where the
6890// source for this function is found.
6891int Code::SourcePosition(Address pc) {
6892 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00006893 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006894 // Run through all the relocation info to find the best matching source
6895 // position. All the code needs to be considered as the sequence of the
6896 // instructions in the code does not necessarily follow the same order as the
6897 // source.
6898 RelocIterator it(this, RelocInfo::kPositionMask);
6899 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006900 // Only look at positions after the current pc.
6901 if (it.rinfo()->pc() < pc) {
6902 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006903
6904 int dist = static_cast<int>(pc - it.rinfo()->pc());
6905 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00006906 // If this position is closer than the current candidate or if it has the
6907 // same distance as the current candidate and the position is higher then
6908 // this position is the new candidate.
6909 if ((dist < distance) ||
6910 (dist == distance && pos > position)) {
6911 position = pos;
6912 distance = dist;
6913 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914 }
6915 it.next();
6916 }
6917 return position;
6918}
6919
6920
6921// Same as Code::SourcePosition above except it only looks for statement
6922// positions.
6923int Code::SourceStatementPosition(Address pc) {
6924 // First find the position as close as possible using all position
6925 // information.
6926 int position = SourcePosition(pc);
6927 // Now find the closest statement position before the position.
6928 int statement_position = 0;
6929 RelocIterator it(this, RelocInfo::kPositionMask);
6930 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006931 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006932 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933 if (statement_position < p && p <= position) {
6934 statement_position = p;
6935 }
6936 }
6937 it.next();
6938 }
6939 return statement_position;
6940}
6941
6942
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006943SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006944 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006945 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006946}
6947
6948
6949void Code::SetNoStackCheckTable() {
6950 // Indicate the absence of a stack-check table by a table start after the
6951 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006952 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006953}
6954
6955
6956Map* Code::FindFirstMap() {
6957 ASSERT(is_inline_cache_stub());
6958 AssertNoAllocation no_allocation;
6959 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6960 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6961 RelocInfo* info = it.rinfo();
6962 Object* object = info->target_object();
6963 if (object->IsMap()) return Map::cast(object);
6964 }
6965 return NULL;
6966}
6967
6968
ricow@chromium.org4f693d62011-07-04 14:01:31 +00006969#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006970
whesse@chromium.org023421e2010-12-21 12:19:12 +00006971void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006972 disasm::NameConverter converter;
6973 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006974 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006975 if (0 == deopt_count) return;
6976
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006977 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc",
6978 FLAG_print_code_verbose ? "commands" : "");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006979 for (int i = 0; i < deopt_count; i++) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006980 PrintF(out, "%6d %6d %6d",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006981 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006982
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00006983 if (!FLAG_print_code_verbose) {
6984 PrintF(out, "\n");
6985 continue;
6986 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006987 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006988 int translation_index = TranslationIndex(i)->value();
6989 TranslationIterator iterator(TranslationByteArray(), translation_index);
6990 Translation::Opcode opcode =
6991 static_cast<Translation::Opcode>(iterator.Next());
6992 ASSERT(Translation::BEGIN == opcode);
6993 int frame_count = iterator.Next();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006994 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6995 frame_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006996
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006997 while (iterator.HasNext() &&
6998 Translation::BEGIN !=
6999 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
7000 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
7001
7002 switch (opcode) {
7003 case Translation::BEGIN:
7004 UNREACHABLE();
7005 break;
7006
7007 case Translation::FRAME: {
7008 int ast_id = iterator.Next();
7009 int function_id = iterator.Next();
7010 JSFunction* function =
7011 JSFunction::cast(LiteralArray()->get(function_id));
7012 unsigned height = iterator.Next();
7013 PrintF(out, "{ast_id=%d, \nfunction=", ast_id);
7014 function->PrintName(out);
7015 PrintF(out, ", height=%u}", height);
7016 break;
7017 }
7018
7019 case Translation::DUPLICATE:
7020 break;
7021
7022 case Translation::REGISTER: {
7023 int reg_code = iterator.Next();
7024 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7025 break;
7026 }
7027
7028 case Translation::INT32_REGISTER: {
7029 int reg_code = iterator.Next();
7030 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7031 break;
7032 }
7033
7034 case Translation::DOUBLE_REGISTER: {
7035 int reg_code = iterator.Next();
7036 PrintF(out, "{input=%s}",
7037 DoubleRegister::AllocationIndexToString(reg_code));
7038 break;
7039 }
7040
7041 case Translation::STACK_SLOT: {
7042 int input_slot_index = iterator.Next();
7043 PrintF(out, "{input=%d}", input_slot_index);
7044 break;
7045 }
7046
7047 case Translation::INT32_STACK_SLOT: {
7048 int input_slot_index = iterator.Next();
7049 PrintF(out, "{input=%d}", input_slot_index);
7050 break;
7051 }
7052
7053 case Translation::DOUBLE_STACK_SLOT: {
7054 int input_slot_index = iterator.Next();
7055 PrintF(out, "{input=%d}", input_slot_index);
7056 break;
7057 }
7058
7059 case Translation::LITERAL: {
7060 unsigned literal_index = iterator.Next();
7061 PrintF(out, "{literal_id=%u}", literal_index);
7062 break;
7063 }
7064
7065 case Translation::ARGUMENTS_OBJECT:
7066 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007067 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00007068 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007069 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007070 }
7071}
7072
7073
whesse@chromium.org023421e2010-12-21 12:19:12 +00007074void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7075 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007076 this->DeoptPoints());
7077 if (this->DeoptPoints() == 0) return;
7078
7079 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7080 for (int i = 0; i < this->DeoptPoints(); i++) {
7081 int pc_and_state = this->PcAndState(i)->value();
7082 PrintF("%6d %8d %s\n",
7083 this->AstId(i)->value(),
7084 FullCodeGenerator::PcField::decode(pc_and_state),
7085 FullCodeGenerator::State2String(
7086 FullCodeGenerator::StateField::decode(pc_and_state)));
7087 }
7088}
7089
whesse@chromium.org7b260152011-06-20 15:33:18 +00007090
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007091// Identify kind of code.
7092const char* Code::Kind2String(Kind kind) {
7093 switch (kind) {
7094 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007095 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007096 case STUB: return "STUB";
7097 case BUILTIN: return "BUILTIN";
7098 case LOAD_IC: return "LOAD_IC";
7099 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7100 case STORE_IC: return "STORE_IC";
7101 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7102 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007103 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00007104 case UNARY_OP_IC: return "UNARY_OP_IC";
7105 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007106 case COMPARE_IC: return "COMPARE_IC";
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007107 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007108 }
7109 UNREACHABLE();
7110 return NULL;
7111}
mads.s.ager31e71382008-08-13 09:32:07 +00007112
7113
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007114const char* Code::ICState2String(InlineCacheState state) {
7115 switch (state) {
7116 case UNINITIALIZED: return "UNINITIALIZED";
7117 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7118 case MONOMORPHIC: return "MONOMORPHIC";
7119 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7120 case MEGAMORPHIC: return "MEGAMORPHIC";
7121 case DEBUG_BREAK: return "DEBUG_BREAK";
7122 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7123 }
7124 UNREACHABLE();
7125 return NULL;
7126}
7127
7128
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007129const char* Code::PropertyType2String(PropertyType type) {
7130 switch (type) {
7131 case NORMAL: return "NORMAL";
7132 case FIELD: return "FIELD";
7133 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7134 case CALLBACKS: return "CALLBACKS";
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00007135 case HANDLER: return "HANDLER";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007136 case INTERCEPTOR: return "INTERCEPTOR";
7137 case MAP_TRANSITION: return "MAP_TRANSITION";
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007138 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007139 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7140 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7141 }
7142 UNREACHABLE();
7143 return NULL;
7144}
7145
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007146
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007147void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7148 const char* name = NULL;
7149 switch (kind) {
7150 case CALL_IC:
7151 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7152 name = "STRING_INDEX_OUT_OF_BOUNDS";
7153 }
7154 break;
7155 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007156 case KEYED_STORE_IC:
7157 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007158 name = "STRICT";
7159 }
7160 break;
7161 default:
7162 break;
7163 }
7164 if (name != NULL) {
7165 PrintF(out, "extra_ic_state = %s\n", name);
7166 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007167 PrintF(out, "extra_ic_state = %d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007168 }
7169}
7170
7171
whesse@chromium.org023421e2010-12-21 12:19:12 +00007172void Code::Disassemble(const char* name, FILE* out) {
7173 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007174 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007175 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007176 PrintExtraICState(out, kind(), extra_ic_state());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007177 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007178 if (ic_state() == MONOMORPHIC) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007179 PrintF(out, "type = %s\n", PropertyType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007180 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00007181 if (is_call_stub() || is_keyed_call_stub()) {
7182 PrintF(out, "argc = %d\n", arguments_count());
7183 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007184 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007185 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007186 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007187 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007188 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007189 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007190 }
mads.s.ager31e71382008-08-13 09:32:07 +00007191
whesse@chromium.org023421e2010-12-21 12:19:12 +00007192 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7193 Disassembler::Decode(out, this);
7194 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00007195
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007196 if (kind() == FUNCTION) {
7197 DeoptimizationOutputData* data =
7198 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007199 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007200 } else if (kind() == OPTIMIZED_FUNCTION) {
7201 DeoptimizationInputData* data =
7202 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007203 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007204 }
7205 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007206
7207 if (kind() == OPTIMIZED_FUNCTION) {
7208 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007209 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007210 for (unsigned i = 0; i < table.length(); i++) {
7211 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007212 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007213 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007214 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007215 SafepointEntry entry = table.GetEntry(i);
7216 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7217 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007218 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007219 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007220 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007221 if (entry.argument_count() > 0) {
7222 PrintF(out, " argc: %d", entry.argument_count());
7223 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007224 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007225 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007226 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007227 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007228 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007229 // If there is no stack check table, the "table start" will at or after
7230 // (due to alignment) the end of the instruction stream.
7231 if (static_cast<int>(offset) < instruction_size()) {
7232 unsigned* address =
7233 reinterpret_cast<unsigned*>(instruction_start() + offset);
7234 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00007235 PrintF(out, "Stack checks (size = %u)\n", length);
7236 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007237 for (unsigned i = 0; i < length; ++i) {
7238 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00007239 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007240 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007241 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007242 }
7243 }
7244
mads.s.ager31e71382008-08-13 09:32:07 +00007245 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007246 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7247 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00007248}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007249#endif // ENABLE_DISASSEMBLER
7250
7251
whesse@chromium.org7b260152011-06-20 15:33:18 +00007252static void CopyFastElementsToFast(FixedArray* source,
7253 FixedArray* destination,
7254 WriteBarrierMode mode) {
7255 uint32_t count = static_cast<uint32_t>(source->length());
7256 for (uint32_t i = 0; i < count; ++i) {
7257 destination->set(i, source->get(i), mode);
7258 }
7259}
7260
7261
7262static void CopySlowElementsToFast(NumberDictionary* source,
7263 FixedArray* destination,
7264 WriteBarrierMode mode) {
7265 for (int i = 0; i < source->Capacity(); ++i) {
7266 Object* key = source->KeyAt(i);
7267 if (key->IsNumber()) {
7268 uint32_t entry = static_cast<uint32_t>(key->Number());
7269 destination->set(entry, source->ValueAt(i), mode);
7270 }
7271 }
7272}
7273
7274
lrn@chromium.org303ada72010-10-27 09:33:13 +00007275MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7276 int length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007277 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00007278 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007279 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007280
whesse@chromium.org7b260152011-06-20 15:33:18 +00007281 // Allocate a new fast elements backing store.
7282 FixedArray* new_elements = NULL;
7283 { Object* object;
7284 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
7285 if (!maybe->ToObject(&object)) return maybe;
7286 new_elements = FixedArray::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007287 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007288
whesse@chromium.org7b260152011-06-20 15:33:18 +00007289 // Find the new map to use for this object if there is a map change.
7290 Map* new_map = NULL;
7291 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
7292 Object* object;
7293 MaybeObject* maybe = map()->GetFastElementsMap();
7294 if (!maybe->ToObject(&object)) return maybe;
7295 new_map = Map::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007296 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007297
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007298 switch (GetElementsKind()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007299 case FAST_ELEMENTS: {
7300 AssertNoAllocation no_gc;
7301 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007302 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
7303 set_map(new_map);
7304 set_elements(new_elements);
7305 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007306 }
7307 case DICTIONARY_ELEMENTS: {
7308 AssertNoAllocation no_gc;
7309 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007310 CopySlowElementsToFast(NumberDictionary::cast(elements()),
7311 new_elements,
7312 mode);
7313 set_map(new_map);
7314 set_elements(new_elements);
7315 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007316 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007317 case NON_STRICT_ARGUMENTS_ELEMENTS: {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007318 AssertNoAllocation no_gc;
7319 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007320 // The object's map and the parameter map are unchanged, the unaliased
7321 // arguments are copied to the new backing store.
7322 FixedArray* parameter_map = FixedArray::cast(elements());
7323 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7324 if (arguments->IsDictionary()) {
7325 CopySlowElementsToFast(NumberDictionary::cast(arguments),
7326 new_elements,
7327 mode);
7328 } else {
7329 CopyFastElementsToFast(arguments, new_elements, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007330 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007331 parameter_map->set(1, new_elements);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007332 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007334 case FAST_DOUBLE_ELEMENTS: {
7335 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7336 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7337 // Fill out the new array with this content and array holes.
7338 for (uint32_t i = 0; i < old_length; i++) {
7339 if (!old_elements->is_the_hole(i)) {
7340 Object* obj;
7341 // Objects must be allocated in the old object space, since the
7342 // overall number of HeapNumbers needed for the conversion might
7343 // exceed the capacity of new space, and we would fail repeatedly
7344 // trying to convert the FixedDoubleArray.
7345 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00007346 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
7347 TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007348 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7349 // Force write barrier. It's not worth trying to exploit
7350 // elems->GetWriteBarrierMode(), since it requires an
7351 // AssertNoAllocation stack object that would have to be positioned
7352 // after the HeapNumber allocation anyway.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007353 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007354 }
7355 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007356 set_map(new_map);
7357 set_elements(new_elements);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007358 break;
7359 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007360 case EXTERNAL_BYTE_ELEMENTS:
7361 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7362 case EXTERNAL_SHORT_ELEMENTS:
7363 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7364 case EXTERNAL_INT_ELEMENTS:
7365 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7366 case EXTERNAL_FLOAT_ELEMENTS:
7367 case EXTERNAL_DOUBLE_ELEMENTS:
7368 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007369 UNREACHABLE();
7370 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007372
whesse@chromium.org7b260152011-06-20 15:33:18 +00007373 // Update the length if necessary.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007374 if (IsJSArray()) {
7375 JSArray::cast(this)->set_length(Smi::FromInt(length));
7376 }
7377
whesse@chromium.org7b260152011-06-20 15:33:18 +00007378 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007379}
7380
7381
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007382MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7383 int capacity,
7384 int length) {
7385 Heap* heap = GetHeap();
7386 // We should never end in here with a pixel or external array.
7387 ASSERT(!HasExternalArrayElements());
7388
7389 Object* obj;
7390 { MaybeObject* maybe_obj =
7391 heap->AllocateUninitializedFixedDoubleArray(capacity);
7392 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7393 }
7394 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
7395
7396 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
7397 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7398 }
7399 Map* new_map = Map::cast(obj);
7400
7401 AssertNoAllocation no_gc;
7402 switch (GetElementsKind()) {
7403 case FAST_ELEMENTS: {
7404 elems->Initialize(FixedArray::cast(elements()));
7405 break;
7406 }
7407 case FAST_DOUBLE_ELEMENTS: {
7408 elems->Initialize(FixedDoubleArray::cast(elements()));
7409 break;
7410 }
7411 case DICTIONARY_ELEMENTS: {
7412 elems->Initialize(NumberDictionary::cast(elements()));
7413 break;
7414 }
7415 default:
7416 UNREACHABLE();
7417 break;
7418 }
7419
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007420 ASSERT(new_map->has_fast_double_elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007421 set_map(new_map);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007422 ASSERT(elems->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007423 set_elements(elems);
7424
7425 if (IsJSArray()) {
7426 JSArray::cast(this)->set_length(Smi::FromInt(length));
7427 }
7428
7429 return this;
7430}
7431
7432
lrn@chromium.org303ada72010-10-27 09:33:13 +00007433MaybeObject* JSObject::SetSlowElements(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00007434 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007435 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007436
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437 uint32_t new_length = static_cast<uint32_t>(len->Number());
7438
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007439 switch (GetElementsKind()) {
7440 case FAST_ELEMENTS: {
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007441 case FAST_DOUBLE_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007442 // Make sure we never try to shrink dense arrays into sparse arrays.
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007443 ASSERT(static_cast<uint32_t>(
7444 FixedArrayBase::cast(elements())->length()) <= new_length);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007445 MaybeObject* result = NormalizeElements();
7446 if (result->IsFailure()) return result;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007447
7448 // Update length for JSArrays.
7449 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7450 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007452 case DICTIONARY_ELEMENTS: {
7453 if (IsJSArray()) {
7454 uint32_t old_length =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007455 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007456 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7457 JSArray::cast(this)->set_length(len);
7458 }
7459 break;
7460 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007461 case NON_STRICT_ARGUMENTS_ELEMENTS:
7462 UNIMPLEMENTED();
7463 break;
7464 case EXTERNAL_BYTE_ELEMENTS:
7465 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7466 case EXTERNAL_SHORT_ELEMENTS:
7467 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7468 case EXTERNAL_INT_ELEMENTS:
7469 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7470 case EXTERNAL_FLOAT_ELEMENTS:
7471 case EXTERNAL_DOUBLE_ELEMENTS:
7472 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007473 UNREACHABLE();
7474 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007475 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476 return this;
7477}
7478
7479
lrn@chromium.org303ada72010-10-27 09:33:13 +00007480MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007481 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007482 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007483 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007484 FixedArray* new_elements;
7485 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007486 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007488 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007490 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7491 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007492 new_elements = FixedArray::cast(obj);
7493 }
7494 set_elements(new_elements);
7495 return this;
7496}
7497
7498
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007499void JSArray::Expand(int required_size) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007500 Handle<JSArray> self(this);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007501 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007502 int old_size = old_backing->length();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00007503 int new_size = required_size > old_size ? required_size : old_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007504 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007505 // Can't use this any more now because we may have had a GC!
7506 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7507 self->SetContent(*new_backing);
7508}
7509
7510
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511static Failure* ArrayLengthRangeError(Heap* heap) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007512 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007513 return heap->isolate()->Throw(
7514 *FACTORY->NewRangeError("invalid_array_length",
7515 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007516}
7517
7518
lrn@chromium.org303ada72010-10-27 09:33:13 +00007519MaybeObject* JSObject::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00007520 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00007521 ASSERT(AllowsSetElementsLength());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007522
lrn@chromium.org303ada72010-10-27 09:33:13 +00007523 MaybeObject* maybe_smi_length = len->ToSmi();
7524 Object* smi_length = Smi::FromInt(0);
7525 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007526 const int value = Smi::cast(smi_length)->value();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007527 if (value < 0) return ArrayLengthRangeError(GetHeap());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007528 JSObject::ElementsKind elements_kind = GetElementsKind();
7529 switch (elements_kind) {
7530 case FAST_ELEMENTS:
7531 case FAST_DOUBLE_ELEMENTS: {
7532 int old_capacity = FixedArrayBase::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007533 if (value <= old_capacity) {
7534 if (IsJSArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007535 Object* obj;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007536 if (elements_kind == FAST_ELEMENTS) {
7537 MaybeObject* maybe_obj = EnsureWritableFastElements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007538 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7539 }
ager@chromium.org04921a82011-06-27 13:21:41 +00007540 if (2 * value <= old_capacity) {
7541 // If more than half the elements won't be used, trim the array.
7542 if (value == 0) {
7543 initialize_elements();
7544 } else {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007545 Address filler_start;
7546 int filler_size;
7547 if (GetElementsKind() == FAST_ELEMENTS) {
7548 FixedArray* fast_elements = FixedArray::cast(elements());
7549 fast_elements->set_length(value);
7550 filler_start = fast_elements->address() +
7551 FixedArray::OffsetOfElementAt(value);
7552 filler_size = (old_capacity - value) * kPointerSize;
7553 } else {
7554 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7555 FixedDoubleArray* fast_double_elements =
7556 FixedDoubleArray::cast(elements());
7557 fast_double_elements->set_length(value);
7558 filler_start = fast_double_elements->address() +
7559 FixedDoubleArray::OffsetOfElementAt(value);
7560 filler_size = (old_capacity - value) * kDoubleSize;
7561 }
ager@chromium.org04921a82011-06-27 13:21:41 +00007562 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
7563 }
7564 } else {
7565 // Otherwise, fill the unused tail with holes.
7566 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007567 if (GetElementsKind() == FAST_ELEMENTS) {
7568 FixedArray* fast_elements = FixedArray::cast(elements());
7569 for (int i = value; i < old_length; i++) {
7570 fast_elements->set_the_hole(i);
7571 }
7572 } else {
7573 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7574 FixedDoubleArray* fast_double_elements =
7575 FixedDoubleArray::cast(elements());
7576 for (int i = value; i < old_length; i++) {
7577 fast_double_elements->set_the_hole(i);
7578 }
ager@chromium.org04921a82011-06-27 13:21:41 +00007579 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007580 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007581 JSArray::cast(this)->set_length(Smi::cast(smi_length));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007582 }
7583 return this;
7584 }
7585 int min = NewElementsCapacity(old_capacity);
7586 int new_capacity = value > min ? value : min;
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007587 if (!ShouldConvertToSlowElements(new_capacity)) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007588 MaybeObject* result;
7589 if (GetElementsKind() == FAST_ELEMENTS) {
7590 result = SetFastElementsCapacityAndLength(new_capacity, value);
7591 } else {
7592 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7593 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
7594 value);
7595 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007596 if (result->IsFailure()) return result;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007597 return this;
7598 }
7599 break;
7600 }
7601 case DICTIONARY_ELEMENTS: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007602 if (IsJSArray()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007603 if (value == 0) {
7604 // If the length of a slow array is reset to zero, we clear
7605 // the array and flush backing storage. This has the added
7606 // benefit that the array returns to fast mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007607 Object* obj;
7608 { MaybeObject* maybe_obj = ResetElements();
7609 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7610 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007611 } else {
7612 // Remove deleted elements.
7613 uint32_t old_length =
7614 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7615 element_dictionary()->RemoveNumberEntries(value, old_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007616 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007617 JSArray::cast(this)->set_length(Smi::cast(smi_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007618 }
7619 return this;
7620 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007621 case NON_STRICT_ARGUMENTS_ELEMENTS:
7622 case EXTERNAL_BYTE_ELEMENTS:
7623 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7624 case EXTERNAL_SHORT_ELEMENTS:
7625 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7626 case EXTERNAL_INT_ELEMENTS:
7627 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7628 case EXTERNAL_FLOAT_ELEMENTS:
7629 case EXTERNAL_DOUBLE_ELEMENTS:
7630 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007631 UNREACHABLE();
7632 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007633 }
7634 }
7635
7636 // General slow case.
7637 if (len->IsNumber()) {
7638 uint32_t length;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007639 if (len->ToArrayIndex(&length)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007640 return SetSlowElements(len);
7641 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007642 return ArrayLengthRangeError(GetHeap());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007643 }
7644 }
7645
7646 // len is not a number so make the array size one and
7647 // set only element to len.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007648 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007649 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007650 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7651 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007652 FixedArray::cast(obj)->set(0, len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007653 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007654 set_elements(FixedArray::cast(obj));
7655 return this;
7656}
7657
7658
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007659Object* Map::GetPrototypeTransition(Object* prototype) {
7660 FixedArray* cache = prototype_transitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007661 int number_of_transitions = NumberOfProtoTransitions();
7662 const int proto_offset =
7663 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7664 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7665 const int step = kProtoTransitionElementsPerEntry;
7666 for (int i = 0; i < number_of_transitions; i++) {
7667 if (cache->get(proto_offset + i * step) == prototype) {
7668 Object* map = cache->get(map_offset + i * step);
7669 ASSERT(map->IsMap());
7670 return map;
7671 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007672 }
7673 return NULL;
7674}
7675
7676
7677MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007678 ASSERT(map->IsMap());
7679 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007680 // Don't cache prototype transition if this map is shared.
7681 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7682
7683 FixedArray* cache = prototype_transitions();
7684
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007685 const int step = kProtoTransitionElementsPerEntry;
7686 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007687
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007688 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007689
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007690 int transitions = NumberOfProtoTransitions() + 1;
7691
7692 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007693 if (capacity > kMaxCachedPrototypeTransitions) return this;
7694
7695 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007696 // Grow array by factor 2 over and above what we need.
7697 { MaybeObject* maybe_cache =
7698 heap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007699 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7700 }
7701
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007702 for (int i = 0; i < capacity * step; i++) {
7703 new_cache->set(i + header, cache->get(i + header));
7704 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007705 cache = new_cache;
7706 set_prototype_transitions(cache);
7707 }
7708
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007709 int last = transitions - 1;
7710
7711 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7712 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7713 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007714
7715 return cache;
7716}
7717
7718
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007719MaybeObject* JSReceiver::SetPrototype(Object* value,
7720 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007721#ifdef DEBUG
7722 int size = Size();
7723#endif
7724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007725 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00007726 // Silently ignore the change if value is not a JSObject or null.
7727 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007728 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00007729
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007730 // From 8.6.2 Object Internal Methods
7731 // ...
7732 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7733 // [[Prototype]] internal properties of the object may not be modified.
7734 // ...
7735 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7736 // or [[Extensible]] must not violate the invariants defined in the preceding
7737 // paragraph.
7738 if (!this->map()->is_extensible()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007739 HandleScope scope(heap->isolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007740 Handle<Object> handle(this, heap->isolate());
7741 return heap->isolate()->Throw(
7742 *FACTORY->NewTypeError("non_extensible_proto",
7743 HandleVector<Object>(&handle, 1)));
7744 }
7745
ager@chromium.org5c838252010-02-19 08:53:10 +00007746 // Before we can set the prototype we need to be sure
7747 // prototype cycles are prevented.
7748 // It is sufficient to validate that the receiver is not in the new prototype
7749 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007750 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007751 if (JSObject::cast(pt) == this) {
7752 // Cycle detected.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007753 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007754 return heap->isolate()->Throw(
7755 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00007756 }
7757 }
7758
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007759 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00007760
7761 if (skip_hidden_prototypes) {
7762 // Find the first object in the chain whose prototype object is not
7763 // hidden and set the new prototype on that object.
7764 Object* current_proto = real_receiver->GetPrototype();
7765 while (current_proto->IsJSObject() &&
7766 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7767 real_receiver = JSObject::cast(current_proto);
7768 current_proto = current_proto->GetPrototype();
7769 }
7770 }
7771
7772 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007773 Map* map = real_receiver->map();
7774
7775 // Nothing to do if prototype is already set.
7776 if (map->prototype() == value) return value;
7777
7778 Object* new_map = map->GetPrototypeTransition(value);
7779 if (new_map == NULL) {
7780 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7781 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7782 }
7783
7784 { MaybeObject* maybe_new_cache =
7785 map->PutPrototypeTransition(value, Map::cast(new_map));
7786 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7787 }
7788
7789 Map::cast(new_map)->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007790 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007791 ASSERT(Map::cast(new_map)->prototype() == value);
ager@chromium.org5c838252010-02-19 08:53:10 +00007792 real_receiver->set_map(Map::cast(new_map));
7793
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007794 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007795 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +00007796 return value;
7797}
7798
7799
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007800bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007801 switch (GetElementsKind()) {
7802 case FAST_ELEMENTS: {
7803 uint32_t length = IsJSArray() ?
7804 static_cast<uint32_t>
7805 (Smi::cast(JSArray::cast(this)->length())->value()) :
7806 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7807 if ((index < length) &&
7808 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7809 return true;
7810 }
7811 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007812 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007813 case FAST_DOUBLE_ELEMENTS: {
7814 uint32_t length = IsJSArray() ?
7815 static_cast<uint32_t>
7816 (Smi::cast(JSArray::cast(this)->length())->value()) :
7817 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7818 if ((index < length) &&
7819 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7820 return true;
7821 }
7822 break;
7823 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007824 case EXTERNAL_PIXEL_ELEMENTS: {
7825 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007826 if (index < static_cast<uint32_t>(pixels->length())) {
7827 return true;
7828 }
7829 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007830 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007831 case EXTERNAL_BYTE_ELEMENTS:
7832 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7833 case EXTERNAL_SHORT_ELEMENTS:
7834 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7835 case EXTERNAL_INT_ELEMENTS:
7836 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007837 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007838 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007839 ExternalArray* array = ExternalArray::cast(elements());
7840 if (index < static_cast<uint32_t>(array->length())) {
7841 return true;
7842 }
7843 break;
7844 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007845 case DICTIONARY_ELEMENTS: {
7846 if (element_dictionary()->FindEntry(index)
7847 != NumberDictionary::kNotFound) {
7848 return true;
7849 }
7850 break;
7851 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007852 case NON_STRICT_ARGUMENTS_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007853 UNREACHABLE();
7854 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 }
7856
7857 // Handle [] on String objects.
7858 if (this->IsStringObjectWithCharacterAt(index)) return true;
7859
7860 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007861 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007862 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7863}
7864
7865
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007866bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007867 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007868 // Make sure that the top context does not change when doing
7869 // callbacks or interceptor calls.
7870 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007871 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007872 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007873 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007874 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007875 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007876 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007877 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007878 v8::IndexedPropertyQuery query =
7879 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 LOG(isolate,
7881 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007882 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007883 {
7884 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007885 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007886 result = query(index, info);
7887 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007888 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007889 ASSERT(result->IsInt32());
7890 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007891 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007892 } else if (!interceptor->getter()->IsUndefined()) {
7893 v8::IndexedPropertyGetter getter =
7894 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007895 LOG(isolate,
7896 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007897 v8::Handle<v8::Value> result;
7898 {
7899 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007900 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007901 result = getter(index, info);
7902 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007903 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007904 }
7905 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7906}
7907
7908
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007909JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007910 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007911 if (IsAccessCheckNeeded()) {
7912 Heap* heap = GetHeap();
7913 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7914 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7915 return UNDEFINED_ELEMENT;
7916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917 }
7918
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007919 if (IsJSGlobalProxy()) {
7920 Object* proto = GetPrototype();
7921 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7922 ASSERT(proto->IsJSGlobalObject());
7923 return JSObject::cast(proto)->HasLocalElement(index);
7924 }
7925
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007926 // Check for lookup interceptor
7927 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007928 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7929 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007930 }
7931
7932 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007933 if (this->IsStringObjectWithCharacterAt(index)) {
7934 return STRING_CHARACTER_ELEMENT;
7935 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007936
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007937 switch (GetElementsKind()) {
7938 case FAST_ELEMENTS: {
7939 uint32_t length = IsJSArray() ?
7940 static_cast<uint32_t>
7941 (Smi::cast(JSArray::cast(this)->length())->value()) :
7942 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007943 if ((index < length) &&
7944 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7945 return FAST_ELEMENT;
7946 }
7947 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007948 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007949 case FAST_DOUBLE_ELEMENTS: {
7950 uint32_t length = IsJSArray() ?
7951 static_cast<uint32_t>
7952 (Smi::cast(JSArray::cast(this)->length())->value()) :
7953 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7954 if ((index < length) &&
7955 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7956 return FAST_ELEMENT;
7957 }
7958 break;
7959 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007960 case EXTERNAL_PIXEL_ELEMENTS: {
7961 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007962 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7963 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007964 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007965 case EXTERNAL_BYTE_ELEMENTS:
7966 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7967 case EXTERNAL_SHORT_ELEMENTS:
7968 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7969 case EXTERNAL_INT_ELEMENTS:
7970 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007971 case EXTERNAL_FLOAT_ELEMENTS:
7972 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007973 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007974 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7975 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00007976 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007977 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007978 if (element_dictionary()->FindEntry(index) !=
whesse@chromium.org7b260152011-06-20 15:33:18 +00007979 NumberDictionary::kNotFound) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007980 return DICTIONARY_ELEMENT;
7981 }
7982 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007983 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007984 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7985 // Aliased parameters and non-aliased elements in a fast backing store
7986 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
7987 // backing store behave as DICTIONARY_ELEMENT.
7988 FixedArray* parameter_map = FixedArray::cast(elements());
7989 uint32_t length = parameter_map->length();
7990 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00007991 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00007992 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
7993 // If not aliased, check the arguments.
7994 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7995 if (arguments->IsDictionary()) {
7996 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
7997 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
7998 return DICTIONARY_ELEMENT;
7999 }
8000 } else {
8001 length = arguments->length();
8002 probe = (index < length) ? arguments->get(index) : NULL;
8003 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8004 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008005 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008006 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008007 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008008
8009 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008010}
8011
8012
whesse@chromium.org7b260152011-06-20 15:33:18 +00008013bool JSObject::HasElementInElements(FixedArray* elements,
8014 ElementsKind kind,
8015 uint32_t index) {
8016 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8017 if (kind == FAST_ELEMENTS) {
8018 int length = IsJSArray()
8019 ? Smi::cast(JSArray::cast(this)->length())->value()
8020 : elements->length();
8021 if (index < static_cast<uint32_t>(length) &&
8022 !elements->get(index)->IsTheHole()) {
8023 return true;
8024 }
8025 } else {
8026 if (NumberDictionary::cast(elements)->FindEntry(index) !=
8027 NumberDictionary::kNotFound) {
8028 return true;
8029 }
8030 }
8031 return false;
8032}
8033
8034
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008035bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008036 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008037 if (IsAccessCheckNeeded()) {
8038 Heap* heap = GetHeap();
8039 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8040 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8041 return false;
8042 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008043 }
8044
8045 // Check for lookup interceptor
8046 if (HasIndexedInterceptor()) {
8047 return HasElementWithInterceptor(receiver, index);
8048 }
8049
whesse@chromium.org7b260152011-06-20 15:33:18 +00008050 ElementsKind kind = GetElementsKind();
8051 switch (kind) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008052 case FAST_ELEMENTS: {
8053 uint32_t length = IsJSArray() ?
8054 static_cast<uint32_t>
8055 (Smi::cast(JSArray::cast(this)->length())->value()) :
8056 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8057 if ((index < length) &&
8058 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8059 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008060 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00008061 case FAST_DOUBLE_ELEMENTS: {
8062 uint32_t length = IsJSArray() ?
8063 static_cast<uint32_t>
8064 (Smi::cast(JSArray::cast(this)->length())->value()) :
8065 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8066 if ((index < length) &&
8067 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8068 break;
8069 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008070 case EXTERNAL_PIXEL_ELEMENTS: {
8071 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008072 if (index < static_cast<uint32_t>(pixels->length())) {
8073 return true;
8074 }
8075 break;
8076 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008077 case EXTERNAL_BYTE_ELEMENTS:
8078 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8079 case EXTERNAL_SHORT_ELEMENTS:
8080 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8081 case EXTERNAL_INT_ELEMENTS:
8082 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008083 case EXTERNAL_FLOAT_ELEMENTS:
8084 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008085 ExternalArray* array = ExternalArray::cast(elements());
8086 if (index < static_cast<uint32_t>(array->length())) {
8087 return true;
8088 }
8089 break;
8090 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008091 case DICTIONARY_ELEMENTS: {
8092 if (element_dictionary()->FindEntry(index)
8093 != NumberDictionary::kNotFound) {
8094 return true;
8095 }
8096 break;
8097 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008098 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8099 FixedArray* parameter_map = FixedArray::cast(elements());
8100 uint32_t length = parameter_map->length();
8101 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00008102 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008103 if (probe != NULL && !probe->IsTheHole()) return true;
8104
8105 // Not a mapped parameter, check the arguments.
8106 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8107 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8108 if (HasElementInElements(arguments, kind, index)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008109 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008110 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008111 }
8112
8113 // Handle [] on String objects.
8114 if (this->IsStringObjectWithCharacterAt(index)) return true;
8115
8116 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008117 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008118 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8119}
8120
8121
lrn@chromium.org303ada72010-10-27 09:33:13 +00008122MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008123 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008124 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008125 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008126 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008127 // Make sure that the top context does not change when doing
8128 // callbacks or interceptor calls.
8129 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008130 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008131 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8132 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008133 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008134 if (!interceptor->setter()->IsUndefined()) {
8135 v8::IndexedPropertySetter setter =
8136 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008137 LOG(isolate,
8138 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8139 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008140 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008141 v8::Handle<v8::Value> result;
8142 {
8143 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008144 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008145 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8146 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008147 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008148 if (!result.IsEmpty()) return *value_handle;
8149 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008150 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008151 this_handle->SetElementWithoutInterceptor(index,
8152 *value_handle,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008153 strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008154 check_prototype);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008155 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008156 return raw_result;
8157}
8158
8159
lrn@chromium.org303ada72010-10-27 09:33:13 +00008160MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8161 Object* structure,
8162 uint32_t index,
8163 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008164 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00008165 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008166
8167 // api style callbacks.
8168 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008169 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008170 Object* fun_obj = data->getter();
8171 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008172 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008173 Handle<JSObject> self(JSObject::cast(receiver));
8174 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008175 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008176 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008177 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8178 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008179 v8::AccessorInfo info(args.end());
8180 v8::Handle<v8::Value> result;
8181 {
8182 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008183 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008184 result = call_fun(v8::Utils::ToLocal(key), info);
8185 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008186 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8187 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008188 return *v8::Utils::OpenHandle(*result);
8189 }
8190
8191 // __defineGetter__ callback
8192 if (structure->IsFixedArray()) {
8193 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
8194 if (getter->IsJSFunction()) {
8195 return Object::GetPropertyWithDefinedGetter(receiver,
8196 JSFunction::cast(getter));
8197 }
8198 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008199 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008200 }
8201
8202 UNREACHABLE();
8203 return NULL;
8204}
8205
8206
lrn@chromium.org303ada72010-10-27 09:33:13 +00008207MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8208 uint32_t index,
8209 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008210 JSObject* holder,
8211 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 Isolate* isolate = GetIsolate();
8213 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008214
8215 // We should never get here to initialize a const with the hole
8216 // value since a const declaration would conflict with the setter.
8217 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008218 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008219
8220 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00008221 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008222 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00008223 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008224
8225 if (structure->IsAccessorInfo()) {
8226 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008227 Handle<JSObject> self(this);
8228 Handle<JSObject> holder_handle(JSObject::cast(holder));
8229 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008230 Object* call_obj = data->setter();
8231 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8232 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008233 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8234 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008235 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8236 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008237 v8::AccessorInfo info(args.end());
8238 {
8239 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008241 call_fun(v8::Utils::ToLocal(key),
8242 v8::Utils::ToLocal(value_handle),
8243 info);
8244 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008245 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008246 return *value_handle;
8247 }
8248
8249 if (structure->IsFixedArray()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008250 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008251 if (setter->IsJSFunction()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008252 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008253 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008254 if (strict_mode == kNonStrictMode) {
8255 return value;
8256 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008257 Handle<Object> holder_handle(holder, isolate);
8258 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008259 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008260 return isolate->Throw(
8261 *isolate->factory()->NewTypeError("no_setter_in_callback",
8262 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008263 }
8264 }
8265
8266 UNREACHABLE();
8267 return NULL;
8268}
8269
8270
whesse@chromium.org7b260152011-06-20 15:33:18 +00008271bool JSObject::HasFastArgumentsElements() {
8272 Heap* heap = GetHeap();
8273 if (!elements()->IsFixedArray()) return false;
8274 FixedArray* elements = FixedArray::cast(this->elements());
8275 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8276 return false;
8277 }
8278 FixedArray* arguments = FixedArray::cast(elements->get(1));
8279 return !arguments->IsDictionary();
8280}
8281
8282
8283bool JSObject::HasDictionaryArgumentsElements() {
8284 Heap* heap = GetHeap();
8285 if (!elements()->IsFixedArray()) return false;
8286 FixedArray* elements = FixedArray::cast(this->elements());
8287 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8288 return false;
8289 }
8290 FixedArray* arguments = FixedArray::cast(elements->get(1));
8291 return arguments->IsDictionary();
8292}
8293
8294
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008295// Adding n elements in fast case is O(n*n).
8296// Note: revisit design to have dual undefined values to capture absent
8297// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008298MaybeObject* JSObject::SetFastElement(uint32_t index,
8299 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008300 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008301 bool check_prototype) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008302 ASSERT(HasFastElements() || HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008303
whesse@chromium.org7b260152011-06-20 15:33:18 +00008304 FixedArray* backing_store = FixedArray::cast(elements());
8305 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
8306 backing_store = FixedArray::cast(backing_store->get(1));
8307 } else {
8308 Object* writable;
8309 MaybeObject* maybe = EnsureWritableFastElements();
8310 if (!maybe->ToObject(&writable)) return maybe;
8311 backing_store = FixedArray::cast(writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008312 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008313 uint32_t length = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008314
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008315 if (check_prototype &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00008316 (index >= length || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008317 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008318 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8319 value,
8320 &found,
8321 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008322 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008323 }
8324
ager@chromium.org04921a82011-06-27 13:21:41 +00008325 // Check whether there is extra space in fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008326 if (index < length) {
8327 backing_store->set(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008328 if (IsJSArray()) {
8329 // Update the length of the array if needed.
8330 uint32_t array_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008331 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 if (index >= array_length) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008333 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008334 }
8335 }
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00008336 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 }
8338
8339 // Allow gap in fast case.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008340 if ((index - length) < kMaxGap) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008341 // Try allocating extra space.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008342 int new_capacity = NewElementsCapacity(index + 1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008343 if (!ShouldConvertToSlowElements(new_capacity)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 ASSERT(static_cast<uint32_t>(new_capacity) > index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008345 Object* new_elements;
8346 MaybeObject* maybe =
8347 SetFastElementsCapacityAndLength(new_capacity, index + 1);
8348 if (!maybe->ToObject(&new_elements)) return maybe;
8349 FixedArray::cast(new_elements)->set(index, value);
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00008350 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008351 }
8352 }
8353
8354 // Otherwise default to slow case.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008355 MaybeObject* result = NormalizeElements();
8356 if (result->IsFailure()) return result;
8357 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8358}
8359
8360
8361MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
8362 Object* value,
8363 StrictModeFlag strict_mode,
8364 bool check_prototype) {
8365 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
8366 Isolate* isolate = GetIsolate();
8367 Heap* heap = isolate->heap();
8368
8369 // Insert element in the dictionary.
8370 FixedArray* elements = FixedArray::cast(this->elements());
8371 bool is_arguments =
8372 (elements->map() == heap->non_strict_arguments_elements_map());
8373 NumberDictionary* dictionary = NULL;
8374 if (is_arguments) {
8375 dictionary = NumberDictionary::cast(elements->get(1));
8376 } else {
8377 dictionary = NumberDictionary::cast(elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008378 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008379
8380 int entry = dictionary->FindEntry(index);
8381 if (entry != NumberDictionary::kNotFound) {
8382 Object* element = dictionary->ValueAt(entry);
8383 PropertyDetails details = dictionary->DetailsAt(entry);
8384 if (details.type() == CALLBACKS) {
8385 return SetElementWithCallback(element, index, value, this, strict_mode);
8386 } else {
8387 dictionary->UpdateMaxNumberKey(index);
8388 // If put fails in strict mode, throw an exception.
8389 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008390 Handle<Object> holder(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00008391 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008392 Handle<Object> args[2] = { number, holder };
8393 Handle<Object> error =
8394 isolate->factory()->NewTypeError("strict_read_only_property",
8395 HandleVector(args, 2));
8396 return isolate->Throw(*error);
8397 }
8398 }
8399 } else {
8400 // Index not already used. Look for an accessor in the prototype chain.
8401 if (check_prototype) {
8402 bool found;
8403 MaybeObject* result =
8404 SetElementWithCallbackSetterInPrototypes(
8405 index, value, &found, strict_mode);
8406 if (found) return result;
8407 }
8408 // When we set the is_extensible flag to false we always force the
8409 // element into dictionary mode (and force them to stay there).
8410 if (!map()->is_extensible()) {
8411 if (strict_mode == kNonStrictMode) {
8412 return isolate->heap()->undefined_value();
8413 } else {
8414 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8415 Handle<String> name = isolate->factory()->NumberToString(number);
8416 Handle<Object> args[1] = { name };
8417 Handle<Object> error =
8418 isolate->factory()->NewTypeError("object_not_extensible",
8419 HandleVector(args, 1));
8420 return isolate->Throw(*error);
8421 }
8422 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008423 FixedArrayBase* new_dictionary;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008424 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008425 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008426 if (dictionary != NumberDictionary::cast(new_dictionary)) {
8427 if (is_arguments) {
8428 elements->set(1, new_dictionary);
8429 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008430 set_elements(new_dictionary);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008431 }
8432 dictionary = NumberDictionary::cast(new_dictionary);
8433 }
8434 }
8435
8436 // Update the array length if this JSObject is an array.
8437 if (IsJSArray()) {
8438 MaybeObject* result =
8439 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
8440 if (result->IsFailure()) return result;
8441 }
8442
8443 // Attempt to put this object back in fast case.
8444 if (ShouldConvertToFastElements()) {
8445 uint32_t new_length = 0;
8446 if (IsJSArray()) {
8447 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
8448 } else {
8449 new_length = dictionary->max_number_key() + 1;
8450 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008451 MaybeObject* result = CanConvertToFastDoubleElements()
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008452 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
8453 : SetFastElementsCapacityAndLength(new_length, new_length);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008454 if (result->IsFailure()) return result;
8455#ifdef DEBUG
8456 if (FLAG_trace_normalization) {
8457 PrintF("Object elements are fast case again:\n");
8458 Print();
8459 }
8460#endif
8461 }
8462 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008463}
8464
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008465
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008466MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8467 uint32_t index,
8468 Object* value,
8469 StrictModeFlag strict_mode,
8470 bool check_prototype) {
8471 ASSERT(HasFastDoubleElements());
8472
8473 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8474 uint32_t elms_length = static_cast<uint32_t>(elms->length());
8475
8476 // If storing to an element that isn't in the array, pass the store request
8477 // up the prototype chain before storing in the receiver's elements.
8478 if (check_prototype &&
8479 (index >= elms_length || elms->is_the_hole(index))) {
8480 bool found;
8481 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8482 value,
8483 &found,
8484 strict_mode);
8485 if (found) return result;
8486 }
8487
8488 // If the value object is not a heap number, switch to fast elements and try
8489 // again.
8490 bool value_is_smi = value->IsSmi();
8491 if (!value->IsNumber()) {
8492 Object* obj;
8493 uint32_t length = elms_length;
8494 if (IsJSArray()) {
8495 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8496 }
8497 MaybeObject* maybe_obj =
8498 SetFastElementsCapacityAndLength(elms_length, length);
8499 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8500 return SetFastElement(index, value, strict_mode, check_prototype);
8501 }
8502
8503 double double_value = value_is_smi
8504 ? static_cast<double>(Smi::cast(value)->value())
8505 : HeapNumber::cast(value)->value();
8506
8507 // Check whether there is extra space in the fixed array.
8508 if (index < elms_length) {
8509 elms->set(index, double_value);
8510 if (IsJSArray()) {
8511 // Update the length of the array if needed.
8512 uint32_t array_length = 0;
8513 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8514 if (index >= array_length) {
8515 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
8516 }
8517 }
8518 return value;
8519 }
8520
8521 // Allow gap in fast case.
8522 if ((index - elms_length) < kMaxGap) {
8523 // Try allocating extra space.
8524 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008525 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008526 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8527 Object* obj;
8528 { MaybeObject* maybe_obj =
8529 SetFastDoubleElementsCapacityAndLength(new_capacity,
8530 index + 1);
8531 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8532 }
8533 FixedDoubleArray::cast(elements())->set(index, double_value);
8534 return value;
8535 }
8536 }
8537
8538 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008539 ASSERT(HasFastDoubleElements());
8540 ASSERT(map()->has_fast_double_elements());
8541 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008542 Object* obj;
8543 { MaybeObject* maybe_obj = NormalizeElements();
8544 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8545 }
8546 ASSERT(HasDictionaryElements());
8547 return SetElement(index, value, strict_mode, check_prototype);
8548}
8549
8550
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008551MaybeObject* JSObject::SetElement(uint32_t index,
8552 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008553 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008554 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008555 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008556 if (IsAccessCheckNeeded()) {
8557 Heap* heap = GetHeap();
8558 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008559 HandleScope scope(heap->isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008560 Handle<Object> value_handle(value);
8561 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8562 return *value_handle;
8563 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008564 }
8565
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008566 if (IsJSGlobalProxy()) {
8567 Object* proto = GetPrototype();
8568 if (proto->IsNull()) return value;
8569 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008570 return JSObject::cast(proto)->SetElement(index,
8571 value,
8572 strict_mode,
8573 check_prototype);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008574 }
8575
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576 // Check for lookup interceptor
8577 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008578 return SetElementWithInterceptor(index,
8579 value,
8580 strict_mode,
8581 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008582 }
8583
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008584 return SetElementWithoutInterceptor(index,
8585 value,
8586 strict_mode,
8587 check_prototype);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008588}
8589
8590
lrn@chromium.org303ada72010-10-27 09:33:13 +00008591MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008592 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008593 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008594 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008595 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008596 switch (GetElementsKind()) {
8597 case FAST_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008598 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008599 case FAST_DOUBLE_ELEMENTS:
8600 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008601 case EXTERNAL_PIXEL_ELEMENTS: {
8602 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008603 return pixels->SetValue(index, value);
8604 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008605 case EXTERNAL_BYTE_ELEMENTS: {
8606 ExternalByteArray* array = ExternalByteArray::cast(elements());
8607 return array->SetValue(index, value);
8608 }
8609 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8610 ExternalUnsignedByteArray* array =
8611 ExternalUnsignedByteArray::cast(elements());
8612 return array->SetValue(index, value);
8613 }
8614 case EXTERNAL_SHORT_ELEMENTS: {
8615 ExternalShortArray* array = ExternalShortArray::cast(elements());
8616 return array->SetValue(index, value);
8617 }
8618 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8619 ExternalUnsignedShortArray* array =
8620 ExternalUnsignedShortArray::cast(elements());
8621 return array->SetValue(index, value);
8622 }
8623 case EXTERNAL_INT_ELEMENTS: {
8624 ExternalIntArray* array = ExternalIntArray::cast(elements());
8625 return array->SetValue(index, value);
8626 }
8627 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8628 ExternalUnsignedIntArray* array =
8629 ExternalUnsignedIntArray::cast(elements());
8630 return array->SetValue(index, value);
8631 }
8632 case EXTERNAL_FLOAT_ELEMENTS: {
8633 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8634 return array->SetValue(index, value);
8635 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008636 case EXTERNAL_DOUBLE_ELEMENTS: {
8637 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8638 return array->SetValue(index, value);
8639 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008640 case DICTIONARY_ELEMENTS:
8641 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8642 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8643 FixedArray* parameter_map = FixedArray::cast(elements());
8644 uint32_t length = parameter_map->length();
8645 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00008646 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008647 if (probe != NULL && !probe->IsTheHole()) {
8648 Context* context = Context::cast(parameter_map->get(0));
8649 int context_index = Smi::cast(probe)->value();
8650 ASSERT(!context->get(context_index)->IsTheHole());
8651 context->set(context_index, value);
8652 return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008653 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008654 // Object is not mapped, defer to the arguments.
8655 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8656 if (arguments->IsDictionary()) {
8657 return SetDictionaryElement(index, value, strict_mode,
8658 check_prototype);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008659 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008660 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008661 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008662 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008663 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008664 }
8665 // All possible cases have been handled above. Add a return to avoid the
8666 // complaints from the compiler.
8667 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008668 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669}
8670
8671
lrn@chromium.org303ada72010-10-27 09:33:13 +00008672MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8673 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008674 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008675 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676 // Check to see if we need to update the length. For now, we make
8677 // sure that the length stays within 32-bits (unsigned).
8678 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008679 Object* len;
8680 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008681 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008682 if (!maybe_len->ToObject(&len)) return maybe_len;
8683 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 set_length(len);
8685 }
8686 return value;
8687}
8688
8689
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008690MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008691 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008692 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008693 // Make sure that the top context does not change when doing
8694 // callbacks or interceptor calls.
8695 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008697 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8698 Handle<Object> this_handle(receiver, isolate);
8699 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008701 v8::IndexedPropertyGetter getter =
8702 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008703 LOG(isolate,
8704 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8705 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008706 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707 v8::Handle<v8::Value> result;
8708 {
8709 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008710 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008711 result = getter(index, info);
8712 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008714 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8715 }
8716
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008717 Heap* heap = holder_handle->GetHeap();
8718 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
8719 MaybeObject* raw_result = handler->GetWithReceiver(*holder_handle,
8720 *this_handle,
8721 index);
8722 if (raw_result != heap->the_hole_value()) return raw_result;
8723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008724 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008725
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008726 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008727 if (pt == heap->null_value()) return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008728 return pt->GetElementWithReceiver(*this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008729}
8730
8731
8732bool JSObject::HasDenseElements() {
8733 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008734 int used = 0;
8735 GetElementsCapacityAndUsage(&capacity, &used);
8736 return (capacity == 0) || (used > (capacity / 2));
8737}
8738
8739
8740void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
8741 *capacity = 0;
8742 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008743
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008744 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
8745 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008746 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008747 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008748 backing_store_base =
8749 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
8750 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008751 if (backing_store->IsDictionary()) {
8752 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008753 *capacity = dictionary->Capacity();
8754 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008755 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008756 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008757 // Fall through.
8758 case FAST_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008759 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008760 *capacity = backing_store->length();
8761 for (int i = 0; i < *capacity; ++i) {
8762 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008763 }
8764 break;
8765 case DICTIONARY_ELEMENTS: {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008766 NumberDictionary* dictionary =
8767 NumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008768 *capacity = dictionary->Capacity();
8769 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008770 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008771 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008772 case FAST_DOUBLE_ELEMENTS: {
8773 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008774 *capacity = elms->length();
8775 for (int i = 0; i < *capacity; i++) {
8776 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008777 }
8778 break;
8779 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008780 case EXTERNAL_BYTE_ELEMENTS:
8781 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8782 case EXTERNAL_SHORT_ELEMENTS:
8783 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8784 case EXTERNAL_INT_ELEMENTS:
8785 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008786 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008787 case EXTERNAL_DOUBLE_ELEMENTS:
8788 case EXTERNAL_PIXEL_ELEMENTS:
8789 // External arrays are considered 100% used.
8790 ExternalArray* external_array = ExternalArray::cast(elements());
8791 *capacity = external_array->length();
8792 *used = external_array->length();
8793 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008795}
8796
8797
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008798bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008799 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
8800 kMaxUncheckedFastElementsLength);
8801 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
8802 (new_capacity <= kMaxUncheckedFastElementsLength &&
8803 GetHeap()->InNewSpace(this))) {
8804 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008805 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008806 // If the fast-case backing storage takes up roughly three times as
8807 // much space (in machine words) as a dictionary backing storage
8808 // would, the object should have slow elements.
8809 int old_capacity = 0;
8810 int used_elements = 0;
8811 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
8812 int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
8813 NumberDictionary::kEntrySize;
8814 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815}
8816
8817
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008818bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008819 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008820 // If the elements are sparse, we should not go back to fast case.
8821 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008822 // An object requiring access checks is never allowed to have fast
8823 // elements. If it had fast elements we would skip security checks.
8824 if (IsAccessCheckNeeded()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008825
8826 FixedArray* elements = FixedArray::cast(this->elements());
8827 NumberDictionary* dictionary = NULL;
8828 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
8829 dictionary = NumberDictionary::cast(elements->get(1));
8830 } else {
8831 dictionary = NumberDictionary::cast(elements);
8832 }
8833 // If an element has been added at a very high index in the elements
8834 // dictionary, we cannot go back to fast case.
8835 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008837 // space (in machine words) as a fast-case backing storage would,
8838 // the object should have fast elements.
8839 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008840 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008841 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008843 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008845 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
8846 NumberDictionary::kEntrySize;
8847 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008848}
8849
8850
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008851bool JSObject::CanConvertToFastDoubleElements() {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008852 if (FLAG_unbox_double_arrays) {
8853 ASSERT(HasDictionaryElements());
8854 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8855 for (int i = 0; i < dictionary->Capacity(); i++) {
8856 Object* key = dictionary->KeyAt(i);
8857 if (key->IsNumber()) {
8858 if (!dictionary->ValueAt(i)->IsNumber()) return false;
8859 }
8860 }
8861 return true;
8862 } else {
8863 return false;
8864 }
8865}
8866
8867
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008868// Certain compilers request function template instantiation when they
8869// see the definition of the other template functions in the
8870// class. This requires us to have the template functions put
8871// together, so even though this function belongs in objects-debug.cc,
8872// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +00008873#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008874template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +00008875void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008876 int capacity = HashTable<Shape, Key>::Capacity();
8877 for (int i = 0; i < capacity; i++) {
8878 Object* k = HashTable<Shape, Key>::KeyAt(i);
8879 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008880 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008881 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008882 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008883 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008884 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008885 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008886 PrintF(out, ": ");
8887 ValueAt(i)->ShortPrint(out);
8888 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008889 }
8890 }
8891}
8892#endif
8893
8894
8895template<typename Shape, typename Key>
8896void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008897 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008898 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008899 AssertNoAllocation no_gc;
8900 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008901 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008902 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8903 if (Dictionary<Shape, Key>::IsKey(k)) {
8904 elements->set(pos++, ValueAt(i), mode);
8905 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008906 }
8907 ASSERT(pos == elements->length());
8908}
8909
8910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008911InterceptorInfo* JSObject::GetNamedInterceptor() {
8912 ASSERT(map()->has_named_interceptor());
8913 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008914 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008916 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917 return InterceptorInfo::cast(result);
8918}
8919
8920
8921InterceptorInfo* JSObject::GetIndexedInterceptor() {
8922 ASSERT(map()->has_indexed_interceptor());
8923 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008924 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008925 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008926 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927 return InterceptorInfo::cast(result);
8928}
8929
8930
lrn@chromium.org303ada72010-10-27 09:33:13 +00008931MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008932 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008933 String* name,
8934 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008935 // Check local property in holder, ignore interceptor.
8936 LookupResult result;
8937 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008938 if (result.IsProperty()) {
8939 return GetProperty(receiver, &result, name, attributes);
8940 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008941 // Continue searching via the prototype chain.
8942 Object* pt = GetPrototype();
8943 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008944 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008945 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8946}
8947
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008948
lrn@chromium.org303ada72010-10-27 09:33:13 +00008949MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008950 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008951 String* name,
8952 PropertyAttributes* attributes) {
8953 // Check local property in holder, ignore interceptor.
8954 LookupResult result;
8955 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008956 if (result.IsProperty()) {
8957 return GetProperty(receiver, &result, name, attributes);
8958 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008959 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008960}
8961
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008962
lrn@chromium.org303ada72010-10-27 09:33:13 +00008963MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008964 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00008965 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008966 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008968 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008969 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008970 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008971 Handle<JSObject> holder_handle(this);
8972 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973
8974 if (!interceptor->getter()->IsUndefined()) {
8975 v8::NamedPropertyGetter getter =
8976 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977 LOG(isolate,
8978 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8979 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008980 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008981 v8::Handle<v8::Value> result;
8982 {
8983 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985 result = getter(v8::Utils::ToLocal(name_handle), info);
8986 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008987 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008988 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008989 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008990 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991 }
8992 }
8993
lrn@chromium.org303ada72010-10-27 09:33:13 +00008994 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008995 *receiver_handle,
8996 *name_handle,
8997 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008998 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00008999 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009000}
9001
9002
9003bool JSObject::HasRealNamedProperty(String* key) {
9004 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009005 if (IsAccessCheckNeeded()) {
9006 Heap* heap = GetHeap();
9007 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9008 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9009 return false;
9010 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 }
9012
9013 LookupResult result;
9014 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00009015 return result.IsProperty() && (result.type() != INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009016}
9017
9018
9019bool JSObject::HasRealElementProperty(uint32_t index) {
9020 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009021 if (IsAccessCheckNeeded()) {
9022 Heap* heap = GetHeap();
9023 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9024 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9025 return false;
9026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009027 }
9028
9029 // Handle [] on String objects.
9030 if (this->IsStringObjectWithCharacterAt(index)) return true;
9031
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009032 switch (GetElementsKind()) {
9033 case FAST_ELEMENTS: {
9034 uint32_t length = IsJSArray() ?
9035 static_cast<uint32_t>(
9036 Smi::cast(JSArray::cast(this)->length())->value()) :
9037 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9038 return (index < length) &&
9039 !FixedArray::cast(elements())->get(index)->IsTheHole();
9040 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00009041 case FAST_DOUBLE_ELEMENTS: {
9042 uint32_t length = IsJSArray() ?
9043 static_cast<uint32_t>(
9044 Smi::cast(JSArray::cast(this)->length())->value()) :
9045 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9046 return (index < length) &&
9047 !FixedDoubleArray::cast(elements())->is_the_hole(index);
9048 break;
9049 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009050 case EXTERNAL_PIXEL_ELEMENTS: {
9051 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009052 return index < static_cast<uint32_t>(pixels->length());
9053 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009054 case EXTERNAL_BYTE_ELEMENTS:
9055 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9056 case EXTERNAL_SHORT_ELEMENTS:
9057 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9058 case EXTERNAL_INT_ELEMENTS:
9059 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009060 case EXTERNAL_FLOAT_ELEMENTS:
9061 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009062 ExternalArray* array = ExternalArray::cast(elements());
9063 return index < static_cast<uint32_t>(array->length());
9064 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009065 case DICTIONARY_ELEMENTS: {
9066 return element_dictionary()->FindEntry(index)
9067 != NumberDictionary::kNotFound;
9068 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009069 case NON_STRICT_ARGUMENTS_ELEMENTS:
9070 UNIMPLEMENTED();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009071 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009072 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009073 // All possibilities have been handled above already.
9074 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009075 return GetHeap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009076}
9077
9078
9079bool JSObject::HasRealNamedCallbackProperty(String* key) {
9080 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009081 if (IsAccessCheckNeeded()) {
9082 Heap* heap = GetHeap();
9083 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9084 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9085 return false;
9086 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087 }
9088
9089 LookupResult result;
9090 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00009091 return result.IsProperty() && (result.type() == CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009092}
9093
9094
9095int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
9096 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009097 DescriptorArray* descs = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009099 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009100 PropertyDetails details(descs->GetDetails(i));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009101 if (details.IsProperty() && (details.attributes() & filter) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 result++;
9103 }
9104 }
9105 return result;
9106 } else {
9107 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9108 }
9109}
9110
9111
9112int JSObject::NumberOfEnumProperties() {
9113 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
9114}
9115
9116
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009117void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118 Object* temp = get(i);
9119 set(i, get(j));
9120 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009121 if (this != numbers) {
9122 temp = numbers->get(i);
9123 numbers->set(i, numbers->get(j));
9124 numbers->set(j, temp);
9125 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009126}
9127
9128
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009129static void InsertionSortPairs(FixedArray* content,
9130 FixedArray* numbers,
9131 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009132 for (int i = 1; i < len; i++) {
9133 int j = i;
9134 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009135 (NumberToUint32(numbers->get(j - 1)) >
9136 NumberToUint32(numbers->get(j)))) {
9137 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138 j--;
9139 }
9140 }
9141}
9142
9143
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009144void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009146 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009147
9148 // Bottom-up max-heap construction.
9149 for (int i = 1; i < len; ++i) {
9150 int child_index = i;
9151 while (child_index > 0) {
9152 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009153 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9154 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009156 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157 } else {
9158 break;
9159 }
9160 child_index = parent_index;
9161 }
9162 }
9163
9164 // Extract elements and create sorted array.
9165 for (int i = len - 1; i > 0; --i) {
9166 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009167 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168 // Sift down the new top element.
9169 int parent_index = 0;
9170 while (true) {
9171 int child_index = ((parent_index + 1) << 1) - 1;
9172 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009173 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
9174 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
9175 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 if (child_index + 1 >= i || child1_value > child2_value) {
9177 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009178 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179 parent_index = child_index;
9180 } else {
9181 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009182 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009183 parent_index = child_index + 1;
9184 }
9185 }
9186 }
9187}
9188
9189
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009190// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9191void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9192 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009193 // For small arrays, simply use insertion sort.
9194 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009195 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009196 return;
9197 }
9198 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009199 uint32_t min_index = NumberToUint32(numbers->get(0));
9200 uint32_t max_index = min_index;
9201 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009203 if (NumberToUint32(numbers->get(i)) < min_index) {
9204 min_index = NumberToUint32(numbers->get(i));
9205 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9206 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009207 }
9208 }
9209 if (max_index - min_index + 1 == len) {
9210 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009211 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 // avoid hanging in case they are not.
9213 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009214 uint32_t p;
9215 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216 // While the current element at i is not at its correct position p,
9217 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009218 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009219 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009220 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009221 }
9222 }
9223 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009224 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009225 return;
9226 }
9227}
9228
9229
9230// Fill in the names of local properties into the supplied storage. The main
9231// purpose of this function is to provide reflection information for the object
9232// mirrors.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009233void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009234 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009236 DescriptorArray* descs = map()->instance_descriptors();
9237 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9238 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009240 ASSERT(storage->length() >= index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009242 property_dictionary()->CopyKeysTo(storage,
9243 index,
9244 StringDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009245 }
9246}
9247
9248
9249int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9250 return GetLocalElementKeys(NULL, filter);
9251}
9252
9253
9254int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009255 // Fast case for objects with no elements.
9256 if (!IsJSValue() && HasFastElements()) {
9257 uint32_t length = IsJSArray() ?
9258 static_cast<uint32_t>(
9259 Smi::cast(JSArray::cast(this)->length())->value()) :
9260 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9261 if (length == 0) return 0;
9262 }
9263 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9265}
9266
9267
9268int JSObject::GetLocalElementKeys(FixedArray* storage,
9269 PropertyAttributes filter) {
9270 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009271 switch (GetElementsKind()) {
9272 case FAST_ELEMENTS: {
9273 int length = IsJSArray() ?
9274 Smi::cast(JSArray::cast(this)->length())->value() :
9275 FixedArray::cast(elements())->length();
9276 for (int i = 0; i < length; i++) {
9277 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9278 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009279 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009280 }
9281 counter++;
9282 }
9283 }
9284 ASSERT(!storage || storage->length() >= counter);
9285 break;
9286 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00009287 case FAST_DOUBLE_ELEMENTS: {
9288 int length = IsJSArray() ?
9289 Smi::cast(JSArray::cast(this)->length())->value() :
9290 FixedDoubleArray::cast(elements())->length();
9291 for (int i = 0; i < length; i++) {
9292 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
9293 if (storage != NULL) {
9294 storage->set(counter, Smi::FromInt(i));
9295 }
9296 counter++;
9297 }
9298 }
9299 ASSERT(!storage || storage->length() >= counter);
9300 break;
9301 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009302 case EXTERNAL_PIXEL_ELEMENTS: {
9303 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009304 while (counter < length) {
9305 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009306 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307 }
9308 counter++;
9309 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009310 ASSERT(!storage || storage->length() >= counter);
9311 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009312 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009313 case EXTERNAL_BYTE_ELEMENTS:
9314 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9315 case EXTERNAL_SHORT_ELEMENTS:
9316 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9317 case EXTERNAL_INT_ELEMENTS:
9318 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009319 case EXTERNAL_FLOAT_ELEMENTS:
9320 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009321 int length = ExternalArray::cast(elements())->length();
9322 while (counter < length) {
9323 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009324 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +00009325 }
9326 counter++;
9327 }
9328 ASSERT(!storage || storage->length() >= counter);
9329 break;
9330 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009331 case DICTIONARY_ELEMENTS: {
9332 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009333 element_dictionary()->CopyKeysTo(storage,
9334 filter,
9335 NumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009336 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009337 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009338 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009339 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009340 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9341 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009342 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009343 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9344 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009345 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
9346 // will insert in storage starting at index 0.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009347 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009348 if (storage != NULL) {
9349 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
9350 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009351 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009352 for (int i = 0; i < mapped_length; ++i) {
9353 if (!parameter_map->get(i + 2)->IsTheHole()) {
9354 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +00009355 ++counter;
9356 }
9357 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009358 if (storage != NULL) storage->SortPairs(storage, counter);
9359
9360 } else {
9361 int backing_length = arguments->length();
9362 int i = 0;
9363 for (; i < mapped_length; ++i) {
9364 if (!parameter_map->get(i + 2)->IsTheHole()) {
9365 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9366 ++counter;
9367 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
9368 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9369 ++counter;
9370 }
9371 }
9372 for (; i < backing_length; ++i) {
9373 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9374 ++counter;
9375 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009376 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009377 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009378 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009379 }
9380
9381 if (this->IsJSValue()) {
9382 Object* val = JSValue::cast(this)->value();
9383 if (val->IsString()) {
9384 String* str = String::cast(val);
9385 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009386 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009387 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009388 }
9389 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009390 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009391 }
9392 }
9393 ASSERT(!storage || storage->length() == counter);
9394 return counter;
9395}
9396
9397
9398int JSObject::GetEnumElementKeys(FixedArray* storage) {
9399 return GetLocalElementKeys(storage,
9400 static_cast<PropertyAttributes>(DONT_ENUM));
9401}
9402
9403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009404// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009405class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009407 explicit StringKey(String* string) :
9408 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009409 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009410
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009411 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009412 // We know that all entries in a hash table had their hash keys created.
9413 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009414 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009415 return false;
9416 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009417 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009418 }
9419
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009420 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009421
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009422 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009423
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009424 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009425
9426 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009427 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009428};
9429
ager@chromium.org381abbb2009-02-25 13:23:22 +00009430
9431// StringSharedKeys are used as keys in the eval cache.
9432class StringSharedKey : public HashTableKey {
9433 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009434 StringSharedKey(String* source,
9435 SharedFunctionInfo* shared,
9436 StrictModeFlag strict_mode)
9437 : source_(source),
9438 shared_(shared),
9439 strict_mode_(strict_mode) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009440
9441 bool IsMatch(Object* other) {
9442 if (!other->IsFixedArray()) return false;
9443 FixedArray* pair = FixedArray::cast(other);
9444 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9445 if (shared != shared_) return false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009446 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9447 Smi::cast(pair->get(2))->value());
9448 if (strict_mode != strict_mode_) return false;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009449 String* source = String::cast(pair->get(1));
9450 return source->Equals(source_);
9451 }
9452
ager@chromium.org381abbb2009-02-25 13:23:22 +00009453 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009454 SharedFunctionInfo* shared,
9455 StrictModeFlag strict_mode) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00009456 uint32_t hash = source->Hash();
9457 if (shared->HasSourceCode()) {
9458 // Instead of using the SharedFunctionInfo pointer in the hash
9459 // code computation, we use a combination of the hash of the
9460 // script source code and the start and end positions. We do
9461 // this to ensure that the cache entries can survive garbage
9462 // collection.
9463 Script* script = Script::cast(shared->script());
9464 hash ^= String::cast(script->source())->Hash();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009465 if (strict_mode == kStrictMode) hash ^= 0x8000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009466 hash += shared->start_position();
9467 }
9468 return hash;
9469 }
9470
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009471 uint32_t Hash() {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009472 return StringSharedHashHelper(source_, shared_, strict_mode_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009473 }
9474
9475 uint32_t HashForObject(Object* obj) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00009476 FixedArray* pair = FixedArray::cast(obj);
9477 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9478 String* source = String::cast(pair->get(1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009479 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9480 Smi::cast(pair->get(2))->value());
9481 return StringSharedHashHelper(source, shared, strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009482 }
9483
lrn@chromium.org303ada72010-10-27 09:33:13 +00009484 MUST_USE_RESULT MaybeObject* AsObject() {
9485 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009487 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9488 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009489 FixedArray* pair = FixedArray::cast(obj);
9490 pair->set(0, shared_);
9491 pair->set(1, source_);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009492 pair->set(2, Smi::FromInt(strict_mode_));
ager@chromium.org381abbb2009-02-25 13:23:22 +00009493 return pair;
9494 }
9495
ager@chromium.org381abbb2009-02-25 13:23:22 +00009496 private:
9497 String* source_;
9498 SharedFunctionInfo* shared_;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009499 StrictModeFlag strict_mode_;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009500};
9501
9502
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009503// RegExpKey carries the source and flags of a regular expression as key.
9504class RegExpKey : public HashTableKey {
9505 public:
9506 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009507 : string_(string),
9508 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009509
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00009510 // Rather than storing the key in the hash table, a pointer to the
9511 // stored value is stored where the key should be. IsMatch then
9512 // compares the search key to the found object, rather than comparing
9513 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009514 bool IsMatch(Object* obj) {
9515 FixedArray* val = FixedArray::cast(obj);
9516 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9517 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9518 }
9519
9520 uint32_t Hash() { return RegExpHash(string_, flags_); }
9521
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009522 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009523 // Plain hash maps, which is where regexp keys are used, don't
9524 // use this function.
9525 UNREACHABLE();
9526 return NULL;
9527 }
9528
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009529 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009530 FixedArray* val = FixedArray::cast(obj);
9531 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9532 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9533 }
9534
9535 static uint32_t RegExpHash(String* string, Smi* flags) {
9536 return string->Hash() + flags->value();
9537 }
9538
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009539 String* string_;
9540 Smi* flags_;
9541};
9542
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009543// Utf8SymbolKey carries a vector of chars as key.
9544class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545 public:
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009546 explicit Utf8SymbolKey(Vector<const char> string)
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009547 : string_(string), hash_field_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009548
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009549 bool IsMatch(Object* string) {
9550 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009551 }
9552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009554 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9556 static_cast<unsigned>(string_.length()));
9557 chars_ = buffer.Length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009558 hash_field_ = String::ComputeHashField(&buffer, chars_);
9559 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009560 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9561 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009562 }
9563
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009564 uint32_t HashForObject(Object* other) {
9565 return String::cast(other)->Hash();
9566 }
9567
lrn@chromium.org303ada72010-10-27 09:33:13 +00009568 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009569 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 return Isolate::Current()->heap()->AllocateSymbol(
9571 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009572 }
9573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009574 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009575 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009576 int chars_; // Caches the number of characters when computing the hash code.
9577};
9578
9579
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009580template <typename Char>
9581class SequentialSymbolKey : public HashTableKey {
9582 public:
9583 explicit SequentialSymbolKey(Vector<const Char> string)
9584 : string_(string), hash_field_(0) { }
9585
9586 uint32_t Hash() {
9587 StringHasher hasher(string_.length());
9588
9589 // Very long strings have a trivial hash that doesn't inspect the
9590 // string contents.
9591 if (hasher.has_trivial_hash()) {
9592 hash_field_ = hasher.GetHashField();
9593 } else {
9594 int i = 0;
9595 // Do the iterative array index computation as long as there is a
9596 // chance this is an array index.
9597 while (i < string_.length() && hasher.is_array_index()) {
9598 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9599 i++;
9600 }
9601
9602 // Process the remaining characters without updating the array
9603 // index.
9604 while (i < string_.length()) {
9605 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9606 i++;
9607 }
9608 hash_field_ = hasher.GetHashField();
9609 }
9610
9611 uint32_t result = hash_field_ >> String::kHashShift;
9612 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9613 return result;
9614 }
9615
9616
9617 uint32_t HashForObject(Object* other) {
9618 return String::cast(other)->Hash();
9619 }
9620
9621 Vector<const Char> string_;
9622 uint32_t hash_field_;
9623};
9624
9625
9626
9627class AsciiSymbolKey : public SequentialSymbolKey<char> {
9628 public:
9629 explicit AsciiSymbolKey(Vector<const char> str)
9630 : SequentialSymbolKey<char>(str) { }
9631
9632 bool IsMatch(Object* string) {
9633 return String::cast(string)->IsAsciiEqualTo(string_);
9634 }
9635
9636 MaybeObject* AsObject() {
9637 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009638 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009639 }
9640};
9641
9642
danno@chromium.org40cb8782011-05-25 07:58:50 +00009643class SubStringAsciiSymbolKey : public HashTableKey {
9644 public:
9645 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9646 int from,
9647 int length)
9648 : string_(string), from_(from), length_(length) { }
9649
9650 uint32_t Hash() {
9651 ASSERT(length_ >= 0);
9652 ASSERT(from_ + length_ <= string_->length());
9653 StringHasher hasher(length_);
9654
9655 // Very long strings have a trivial hash that doesn't inspect the
9656 // string contents.
9657 if (hasher.has_trivial_hash()) {
9658 hash_field_ = hasher.GetHashField();
9659 } else {
9660 int i = 0;
9661 // Do the iterative array index computation as long as there is a
9662 // chance this is an array index.
9663 while (i < length_ && hasher.is_array_index()) {
9664 hasher.AddCharacter(static_cast<uc32>(
9665 string_->SeqAsciiStringGet(i + from_)));
9666 i++;
9667 }
9668
9669 // Process the remaining characters without updating the array
9670 // index.
9671 while (i < length_) {
9672 hasher.AddCharacterNoIndex(static_cast<uc32>(
9673 string_->SeqAsciiStringGet(i + from_)));
9674 i++;
9675 }
9676 hash_field_ = hasher.GetHashField();
9677 }
9678
9679 uint32_t result = hash_field_ >> String::kHashShift;
9680 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9681 return result;
9682 }
9683
9684
9685 uint32_t HashForObject(Object* other) {
9686 return String::cast(other)->Hash();
9687 }
9688
9689 bool IsMatch(Object* string) {
9690 Vector<const char> chars(string_->GetChars() + from_, length_);
9691 return String::cast(string)->IsAsciiEqualTo(chars);
9692 }
9693
9694 MaybeObject* AsObject() {
9695 if (hash_field_ == 0) Hash();
9696 Vector<const char> chars(string_->GetChars() + from_, length_);
9697 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
9698 }
9699
9700 private:
9701 Handle<SeqAsciiString> string_;
9702 int from_;
9703 int length_;
9704 uint32_t hash_field_;
9705};
9706
9707
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009708class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
9709 public:
9710 explicit TwoByteSymbolKey(Vector<const uc16> str)
9711 : SequentialSymbolKey<uc16>(str) { }
9712
9713 bool IsMatch(Object* string) {
9714 return String::cast(string)->IsTwoByteEqualTo(string_);
9715 }
9716
9717 MaybeObject* AsObject() {
9718 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009719 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009720 }
9721};
9722
9723
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009724// SymbolKey carries a string/symbol object as key.
9725class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009726 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009727 explicit SymbolKey(String* string)
9728 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009729
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009730 bool IsMatch(Object* string) {
9731 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009732 }
9733
9734 uint32_t Hash() { return string_->Hash(); }
9735
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009736 uint32_t HashForObject(Object* other) {
9737 return String::cast(other)->Hash();
9738 }
9739
lrn@chromium.org303ada72010-10-27 09:33:13 +00009740 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00009741 // Attempt to flatten the string, so that symbols will most often
9742 // be flat strings.
9743 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009744 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009745 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009747 if (map != NULL) {
9748 string_->set_map(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009749 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009750 return string_;
9751 }
9752 // Otherwise allocate a new symbol.
9753 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009754 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009755 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009756 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009757 }
9758
9759 static uint32_t StringHash(Object* obj) {
9760 return String::cast(obj)->Hash();
9761 }
9762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009763 String* string_;
9764};
9765
9766
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009767template<typename Shape, typename Key>
9768void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009769 IteratePointers(v, 0, kElementsStartOffset);
9770}
9771
9772
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009773template<typename Shape, typename Key>
9774void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009775 IteratePointers(v,
9776 kElementsStartOffset,
9777 kHeaderSize + length() * kPointerSize);
9778}
9779
9780
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009781template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009782MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9783 PretenureFlag pretenure) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009784 int capacity = ComputeCapacity(at_least_space_for);
9785 if (capacity > HashTable::kMaxCapacity) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009786 return Failure::OutOfMemoryException();
9787 }
9788
lrn@chromium.org303ada72010-10-27 09:33:13 +00009789 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009790 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9791 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009792 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009794 HashTable::cast(obj)->SetNumberOfElements(0);
9795 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9796 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009797 return obj;
9798}
9799
9800
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009801// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +00009802int StringDictionary::FindEntry(String* key) {
9803 if (!key->IsSymbol()) {
9804 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9805 }
9806
9807 // Optimized for symbol key. Knowledge of the key type allows:
9808 // 1. Move the check if the key is a symbol out of the loop.
9809 // 2. Avoid comparing hash codes in symbol to symbol comparision.
9810 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9811 // In case of positive result the dictionary key may be replaced by
9812 // the symbol with minimal performance penalty. It gives a chance to
9813 // perform further lookups in code stubs (and significant performance boost
9814 // a certain style of code).
9815
9816 // EnsureCapacity will guarantee the hash table is never full.
9817 uint32_t capacity = Capacity();
9818 uint32_t entry = FirstProbe(key->Hash(), capacity);
9819 uint32_t count = 1;
9820
9821 while (true) {
9822 int index = EntryToIndex(entry);
9823 Object* element = get(index);
9824 if (element->IsUndefined()) break; // Empty entry.
9825 if (key == element) return entry;
9826 if (!element->IsSymbol() &&
9827 !element->IsNull() &&
9828 String::cast(element)->Equals(key)) {
9829 // Replace a non-symbol key by the equivalent symbol for faster further
9830 // lookups.
9831 set(index, key);
9832 return entry;
9833 }
9834 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9835 entry = NextProbe(entry, count++, capacity);
9836 }
9837 return kNotFound;
9838}
9839
9840
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009841template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +00009842MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
9843 ASSERT(NumberOfElements() < new_table->Capacity());
9844
9845 AssertNoAllocation no_gc;
9846 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
9847
9848 // Copy prefix to new array.
9849 for (int i = kPrefixStartIndex;
9850 i < kPrefixStartIndex + Shape::kPrefixSize;
9851 i++) {
9852 new_table->set(i, get(i), mode);
9853 }
9854
9855 // Rehash the elements.
9856 int capacity = Capacity();
9857 for (int i = 0; i < capacity; i++) {
9858 uint32_t from_index = EntryToIndex(i);
9859 Object* k = get(from_index);
9860 if (IsKey(k)) {
9861 uint32_t hash = Shape::HashForObject(key, k);
9862 uint32_t insertion_index =
9863 EntryToIndex(new_table->FindInsertionEntry(hash));
9864 for (int j = 0; j < Shape::kEntrySize; j++) {
9865 new_table->set(insertion_index + j, get(from_index + j), mode);
9866 }
9867 }
9868 }
9869 new_table->SetNumberOfElements(NumberOfElements());
9870 new_table->SetNumberOfDeletedElements(0);
9871 return new_table;
9872}
9873
9874
9875template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009876MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877 int capacity = Capacity();
9878 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009879 int nod = NumberOfDeletedElements();
9880 // Return if:
9881 // 50% is still free after adding n elements and
9882 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009883 if (nod <= (capacity - nof) >> 1) {
9884 int needed_free = nof >> 1;
9885 if (nof + needed_free <= capacity) return this;
9886 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009887
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009888 const int kMinCapacityForPretenure = 256;
9889 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009890 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009891 Object* obj;
9892 { MaybeObject* maybe_obj =
9893 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9894 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9895 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009896
ager@chromium.org04921a82011-06-27 13:21:41 +00009897 return Rehash(HashTable::cast(obj), key);
9898}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009899
ager@chromium.org04921a82011-06-27 13:21:41 +00009900
9901template<typename Shape, typename Key>
9902MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
9903 int capacity = Capacity();
9904 int nof = NumberOfElements();
9905
9906 // Shrink to fit the number of elements if only a quarter of the
9907 // capacity is filled with elements.
9908 if (nof > (capacity >> 2)) return this;
9909 // Allocate a new dictionary with room for at least the current
9910 // number of elements. The allocation method will make sure that
9911 // there is extra room in the dictionary for additions. Don't go
9912 // lower than room for 16 elements.
9913 int at_least_room_for = nof;
9914 if (at_least_room_for < 16) return this;
9915
9916 const int kMinCapacityForPretenure = 256;
9917 bool pretenure =
9918 (at_least_room_for > kMinCapacityForPretenure) &&
9919 !GetHeap()->InNewSpace(this);
9920 Object* obj;
9921 { MaybeObject* maybe_obj =
9922 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
9923 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 }
ager@chromium.org04921a82011-06-27 13:21:41 +00009925
9926 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009927}
9928
9929
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009930template<typename Shape, typename Key>
9931uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009932 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009933 uint32_t entry = FirstProbe(hash, capacity);
9934 uint32_t count = 1;
9935 // EnsureCapacity will guarantee the hash table is never full.
9936 while (true) {
9937 Object* element = KeyAt(entry);
9938 if (element->IsUndefined() || element->IsNull()) break;
9939 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009940 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009941 return entry;
9942}
9943
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009944// Force instantiation of template instances class.
9945// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009946
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009947template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009948
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009949template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009951template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009952
vegorov@chromium.org7943d462011-08-01 11:41:52 +00009953template class HashTable<ObjectHashTableShape, JSObject*>;
9954
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009955template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009957template class Dictionary<NumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009958
lrn@chromium.org303ada72010-10-27 09:33:13 +00009959template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009960 int);
9961
lrn@chromium.org303ada72010-10-27 09:33:13 +00009962template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009963 int);
9964
lrn@chromium.org303ada72010-10-27 09:33:13 +00009965template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009966 uint32_t, Object*);
9967
9968template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9969 Object*);
9970
9971template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9972 Object*);
9973
9974template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009975 FixedArray*,
9976 PropertyAttributes,
9977 Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009978
9979template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9980 int, JSObject::DeleteMode);
9981
9982template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
9983 int, JSObject::DeleteMode);
9984
ager@chromium.org04921a82011-06-27 13:21:41 +00009985template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
9986 String*);
9987
9988template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
9989 uint32_t);
9990
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009991template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009992 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009993 int,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009994 Dictionary<StringDictionaryShape, String*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009995
9996template int
9997Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
9998 PropertyAttributes);
9999
lrn@chromium.org303ada72010-10-27 09:33:13 +000010000template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010001 String*, Object*, PropertyDetails);
10002
lrn@chromium.org303ada72010-10-27 09:33:13 +000010003template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010004Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
10005
10006template int
10007Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
10008 PropertyAttributes);
10009
lrn@chromium.org303ada72010-10-27 09:33:13 +000010010template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010011 uint32_t, Object*, PropertyDetails);
10012
lrn@chromium.org303ada72010-10-27 09:33:13 +000010013template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
10014 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010015
lrn@chromium.org303ada72010-10-27 09:33:13 +000010016template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10017 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010018
lrn@chromium.org303ada72010-10-27 09:33:13 +000010019template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010020 uint32_t, Object*, PropertyDetails, uint32_t);
10021
lrn@chromium.org303ada72010-10-27 09:33:13 +000010022template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010023 String*, Object*, PropertyDetails, uint32_t);
10024
10025template
10026int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
10027
10028template
10029int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010030
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010031template
10032int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
10033
10034
ager@chromium.org5ec48922009-05-05 07:25:34 +000010035// Collates undefined and unexisting elements below limit from position
10036// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010037MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010038 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010039 // Must stay in dictionary mode, either because of requires_slow_elements,
10040 // or because we are not going to sort (and therefore compact) all of the
10041 // elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010042 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010043 HeapNumber* result_double = NULL;
10044 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10045 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010046 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010047 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010048 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10049 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010050 result_double = HeapNumber::cast(new_double);
10051 }
10052
lrn@chromium.org303ada72010-10-27 09:33:13 +000010053 Object* obj;
10054 { MaybeObject* maybe_obj =
10055 NumberDictionary::Allocate(dict->NumberOfElements());
10056 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10057 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010058 NumberDictionary* new_dict = NumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010059
10060 AssertNoAllocation no_alloc;
10061
ager@chromium.org5ec48922009-05-05 07:25:34 +000010062 uint32_t pos = 0;
10063 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010064 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010065 for (int i = 0; i < capacity; i++) {
10066 Object* k = dict->KeyAt(i);
10067 if (dict->IsKey(k)) {
10068 ASSERT(k->IsNumber());
10069 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10070 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10071 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10072 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010073 PropertyDetails details = dict->DetailsAt(i);
10074 if (details.type() == CALLBACKS) {
10075 // Bail out and do the sorting of undefineds and array holes in JS.
10076 return Smi::FromInt(-1);
10077 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010078 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010079 // In the following we assert that adding the entry to the new dictionary
10080 // does not cause GC. This is the case because we made sure to allocate
10081 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000010082 if (key < limit) {
10083 if (value->IsUndefined()) {
10084 undefs++;
10085 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010086 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10087 // Adding an entry with the key beyond smi-range requires
10088 // allocation. Bailout.
10089 return Smi::FromInt(-1);
10090 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010091 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010092 pos++;
10093 }
10094 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010095 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10096 // Adding an entry with the key beyond smi-range requires
10097 // allocation. Bailout.
10098 return Smi::FromInt(-1);
10099 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010100 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010101 }
10102 }
10103 }
10104
10105 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010106 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010107 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010108 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010109 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10110 // Adding an entry with the key beyond smi-range requires
10111 // allocation. Bailout.
10112 return Smi::FromInt(-1);
10113 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000010115 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010116 pos++;
10117 undefs--;
10118 }
10119
10120 set_elements(new_dict);
10121
10122 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10123 return Smi::FromInt(static_cast<int>(result));
10124 }
10125
10126 ASSERT_NE(NULL, result_double);
10127 result_double->set_value(static_cast<double>(result));
10128 return result_double;
10129}
10130
10131
10132// Collects all defined (non-hole) and non-undefined (array) elements at
10133// the start of the elements array.
10134// If the object is in dictionary mode, it is converted to fast elements
10135// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010136MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010137 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010139 Heap* heap = GetHeap();
10140
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010141 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010142 // Convert to fast elements containing only the existing properties.
10143 // Ordering is irrelevant, since we are going to sort anyway.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010144 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010145 if (IsJSArray() || dict->requires_slow_elements() ||
10146 dict->max_number_key() >= limit) {
10147 return PrepareSlowElementsForSort(limit);
10148 }
10149 // Convert to fast elements.
10150
lrn@chromium.org303ada72010-10-27 09:33:13 +000010151 Object* obj;
10152 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
10153 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10154 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010155 Map* new_map = Map::cast(obj);
10156
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010157 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010158 Object* new_array;
10159 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010160 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010161 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
10162 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010163 FixedArray* fast_elements = FixedArray::cast(new_array);
10164 dict->CopyValuesTo(fast_elements);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010165
10166 set_map(new_map);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010167 set_elements(fast_elements);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010168 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010169 Object* obj;
10170 { MaybeObject* maybe_obj = EnsureWritableFastElements();
10171 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10172 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010173 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010174 ASSERT(HasFastElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010175
10176 // Collect holes at the end, undefined before that and the rest at the
10177 // start, and return the number of non-hole, non-undefined values.
10178
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010179 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
10180 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010181 if (limit > elements_length) {
10182 limit = elements_length ;
10183 }
10184 if (limit == 0) {
10185 return Smi::FromInt(0);
10186 }
10187
10188 HeapNumber* result_double = NULL;
10189 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10190 // Pessimistically allocate space for return value before
10191 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010192 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010194 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10195 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010196 result_double = HeapNumber::cast(new_double);
10197 }
10198
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010199 uint32_t result = 0;
10200 if (elements_base->map() == heap->fixed_double_array_map()) {
10201 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
10202 // Split elements into defined and the_hole, in that order.
10203 unsigned int holes = limit;
10204 // Assume most arrays contain no holes and undefined values, so minimize the
10205 // number of stores of non-undefined, non-the-hole values.
10206 for (unsigned int i = 0; i < holes; i++) {
10207 if (elements->is_the_hole(i)) {
10208 holes--;
10209 } else {
10210 continue;
10211 }
10212 // Position i needs to be filled.
10213 while (holes > i) {
10214 if (elements->is_the_hole(holes)) {
10215 holes--;
10216 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010217 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010218 break;
10219 }
10220 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010221 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010222 result = holes;
10223 while (holes < limit) {
10224 elements->set_the_hole(holes);
10225 holes++;
10226 }
10227 } else {
10228 FixedArray* elements = FixedArray::cast(elements_base);
10229 AssertNoAllocation no_alloc;
10230
10231 // Split elements into defined, undefined and the_hole, in that order. Only
10232 // count locations for undefined and the hole, and fill them afterwards.
10233 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
10234 unsigned int undefs = limit;
10235 unsigned int holes = limit;
10236 // Assume most arrays contain no holes and undefined values, so minimize the
10237 // number of stores of non-undefined, non-the-hole values.
10238 for (unsigned int i = 0; i < undefs; i++) {
10239 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010240 if (current->IsTheHole()) {
10241 holes--;
10242 undefs--;
10243 } else if (current->IsUndefined()) {
10244 undefs--;
10245 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010246 continue;
10247 }
10248 // Position i needs to be filled.
10249 while (undefs > i) {
10250 current = elements->get(undefs);
10251 if (current->IsTheHole()) {
10252 holes--;
10253 undefs--;
10254 } else if (current->IsUndefined()) {
10255 undefs--;
10256 } else {
10257 elements->set(i, current, write_barrier);
10258 break;
10259 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010260 }
10261 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010262 result = undefs;
10263 while (undefs < holes) {
10264 elements->set_undefined(undefs);
10265 undefs++;
10266 }
10267 while (holes < limit) {
10268 elements->set_the_hole(holes);
10269 holes++;
10270 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010271 }
10272
10273 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10274 return Smi::FromInt(static_cast<int>(result));
10275 }
10276 ASSERT_NE(NULL, result_double);
10277 result_double->set_value(static_cast<double>(result));
10278 return result_double;
10279}
10280
10281
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010282Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010283 uint8_t clamped_value = 0;
10284 if (index < static_cast<uint32_t>(length())) {
10285 if (value->IsSmi()) {
10286 int int_value = Smi::cast(value)->value();
10287 if (int_value < 0) {
10288 clamped_value = 0;
10289 } else if (int_value > 255) {
10290 clamped_value = 255;
10291 } else {
10292 clamped_value = static_cast<uint8_t>(int_value);
10293 }
10294 } else if (value->IsHeapNumber()) {
10295 double double_value = HeapNumber::cast(value)->value();
10296 if (!(double_value > 0)) {
10297 // NaN and less than zero clamp to zero.
10298 clamped_value = 0;
10299 } else if (double_value > 255) {
10300 // Greater than 255 clamp to 255.
10301 clamped_value = 255;
10302 } else {
10303 // Other doubles are rounded to the nearest integer.
10304 clamped_value = static_cast<uint8_t>(double_value + 0.5);
10305 }
10306 } else {
10307 // Clamp undefined to zero (default). All other types have been
10308 // converted to a number type further up in the call chain.
10309 ASSERT(value->IsUndefined());
10310 }
10311 set(index, clamped_value);
10312 }
10313 return Smi::FromInt(clamped_value);
10314}
10315
10316
ager@chromium.org3811b432009-10-28 14:53:37 +000010317template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010318static MaybeObject* ExternalArrayIntSetter(Heap* heap,
10319 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010320 uint32_t index,
10321 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010322 ValueType cast_value = 0;
10323 if (index < static_cast<uint32_t>(receiver->length())) {
10324 if (value->IsSmi()) {
10325 int int_value = Smi::cast(value)->value();
10326 cast_value = static_cast<ValueType>(int_value);
10327 } else if (value->IsHeapNumber()) {
10328 double double_value = HeapNumber::cast(value)->value();
10329 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10330 } else {
10331 // Clamp undefined to zero (default). All other types have been
10332 // converted to a number type further up in the call chain.
10333 ASSERT(value->IsUndefined());
10334 }
10335 receiver->set(index, cast_value);
10336 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010337 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010338}
10339
10340
lrn@chromium.org303ada72010-10-27 09:33:13 +000010341MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010342 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010343 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010344}
10345
10346
lrn@chromium.org303ada72010-10-27 09:33:13 +000010347MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10348 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010349 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010351}
10352
10353
lrn@chromium.org303ada72010-10-27 09:33:13 +000010354MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10355 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010356 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010357 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010358}
10359
10360
lrn@chromium.org303ada72010-10-27 09:33:13 +000010361MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10362 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010363 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010364 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010365}
10366
10367
lrn@chromium.org303ada72010-10-27 09:33:13 +000010368MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010369 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010371}
10372
10373
lrn@chromium.org303ada72010-10-27 09:33:13 +000010374MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010375 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010376 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010377 if (index < static_cast<uint32_t>(length())) {
10378 if (value->IsSmi()) {
10379 int int_value = Smi::cast(value)->value();
10380 cast_value = static_cast<uint32_t>(int_value);
10381 } else if (value->IsHeapNumber()) {
10382 double double_value = HeapNumber::cast(value)->value();
10383 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10384 } else {
10385 // Clamp undefined to zero (default). All other types have been
10386 // converted to a number type further up in the call chain.
10387 ASSERT(value->IsUndefined());
10388 }
10389 set(index, cast_value);
10390 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010392}
10393
10394
lrn@chromium.org303ada72010-10-27 09:33:13 +000010395MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010396 float cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010397 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010398 if (index < static_cast<uint32_t>(length())) {
10399 if (value->IsSmi()) {
10400 int int_value = Smi::cast(value)->value();
10401 cast_value = static_cast<float>(int_value);
10402 } else if (value->IsHeapNumber()) {
10403 double double_value = HeapNumber::cast(value)->value();
10404 cast_value = static_cast<float>(double_value);
10405 } else {
10406 // Clamp undefined to zero (default). All other types have been
10407 // converted to a number type further up in the call chain.
10408 ASSERT(value->IsUndefined());
10409 }
10410 set(index, cast_value);
10411 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010412 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010413}
10414
10415
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010416MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
10417 double double_value = 0;
10418 Heap* heap = GetHeap();
10419 if (index < static_cast<uint32_t>(length())) {
10420 if (value->IsSmi()) {
10421 int int_value = Smi::cast(value)->value();
10422 double_value = static_cast<double>(int_value);
10423 } else if (value->IsHeapNumber()) {
10424 double_value = HeapNumber::cast(value)->value();
10425 } else {
10426 // Clamp undefined to zero (default). All other types have been
10427 // converted to a number type further up in the call chain.
10428 ASSERT(value->IsUndefined());
10429 }
10430 set(index, double_value);
10431 }
10432 return heap->AllocateHeapNumber(double_value);
10433}
10434
10435
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010436JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010437 ASSERT(!HasFastProperties());
10438 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010439 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010440}
10441
10442
lrn@chromium.org303ada72010-10-27 09:33:13 +000010443MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010444 ASSERT(!HasFastProperties());
10445 int entry = property_dictionary()->FindEntry(name);
10446 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010447 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010448 Object* cell;
10449 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010450 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010451 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10452 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010453 PropertyDetails details(NONE, NORMAL);
10454 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010455 Object* dictionary;
10456 { MaybeObject* maybe_dictionary =
10457 property_dictionary()->Add(name, cell, details);
10458 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10459 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010460 set_properties(StringDictionary::cast(dictionary));
10461 return cell;
10462 } else {
10463 Object* value = property_dictionary()->ValueAt(entry);
10464 ASSERT(value->IsJSGlobalPropertyCell());
10465 return value;
10466 }
10467}
10468
10469
lrn@chromium.org303ada72010-10-27 09:33:13 +000010470MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010471 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010472 return LookupKey(&key, s);
10473}
10474
10475
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010476// This class is used for looking up two character strings in the symbol table.
10477// If we don't have a hit we don't want to waste much time so we unroll the
10478// string hash calculation loop here for speed. Doesn't work if the two
10479// characters form a decimal integer, since such strings have a different hash
10480// algorithm.
10481class TwoCharHashTableKey : public HashTableKey {
10482 public:
10483 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
10484 : c1_(c1), c2_(c2) {
10485 // Char 1.
10486 uint32_t hash = c1 + (c1 << 10);
10487 hash ^= hash >> 6;
10488 // Char 2.
10489 hash += c2;
10490 hash += hash << 10;
10491 hash ^= hash >> 6;
10492 // GetHash.
10493 hash += hash << 3;
10494 hash ^= hash >> 11;
10495 hash += hash << 15;
10496 if (hash == 0) hash = 27;
10497#ifdef DEBUG
10498 StringHasher hasher(2);
10499 hasher.AddCharacter(c1);
10500 hasher.AddCharacter(c2);
10501 // If this assert fails then we failed to reproduce the two-character
10502 // version of the string hashing algorithm above. One reason could be
10503 // that we were passed two digits as characters, since the hash
10504 // algorithm is different in that case.
10505 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10506#endif
10507 hash_ = hash;
10508 }
10509
10510 bool IsMatch(Object* o) {
10511 if (!o->IsString()) return false;
10512 String* other = String::cast(o);
10513 if (other->length() != 2) return false;
10514 if (other->Get(0) != c1_) return false;
10515 return other->Get(1) == c2_;
10516 }
10517
10518 uint32_t Hash() { return hash_; }
10519 uint32_t HashForObject(Object* key) {
10520 if (!key->IsString()) return 0;
10521 return String::cast(key)->Hash();
10522 }
10523
10524 Object* AsObject() {
10525 // The TwoCharHashTableKey is only used for looking in the symbol
10526 // table, not for adding to it.
10527 UNREACHABLE();
10528 return NULL;
10529 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010530
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010531 private:
10532 uint32_t c1_;
10533 uint32_t c2_;
10534 uint32_t hash_;
10535};
10536
10537
ager@chromium.org7c537e22008-10-16 08:43:32 +000010538bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10539 SymbolKey key(string);
10540 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010541 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010542 return false;
10543 } else {
10544 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +000010545 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +000010546 *symbol = result;
10547 return true;
10548 }
10549}
10550
10551
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010552bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10553 uint32_t c2,
10554 String** symbol) {
10555 TwoCharHashTableKey key(c1, c2);
10556 int entry = FindEntry(&key);
10557 if (entry == kNotFound) {
10558 return false;
10559 } else {
10560 String* result = String::cast(KeyAt(entry));
10561 ASSERT(StringShape(result).IsSymbol());
10562 *symbol = result;
10563 return true;
10564 }
10565}
10566
10567
lrn@chromium.org303ada72010-10-27 09:33:13 +000010568MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010569 Utf8SymbolKey key(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570 return LookupKey(&key, s);
10571}
10572
10573
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010574MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10575 Object** s) {
10576 AsciiSymbolKey key(str);
10577 return LookupKey(&key, s);
10578}
10579
10580
danno@chromium.org40cb8782011-05-25 07:58:50 +000010581MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10582 int from,
10583 int length,
10584 Object** s) {
10585 SubStringAsciiSymbolKey key(str, from, length);
10586 return LookupKey(&key, s);
10587}
10588
10589
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010590MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10591 Object** s) {
10592 TwoByteSymbolKey key(str);
10593 return LookupKey(&key, s);
10594}
10595
lrn@chromium.org303ada72010-10-27 09:33:13 +000010596MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597 int entry = FindEntry(key);
10598
10599 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010600 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010601 *s = KeyAt(entry);
10602 return this;
10603 }
10604
10605 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010606 Object* obj;
10607 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10608 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610
10611 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010612 Object* symbol;
10613 { MaybeObject* maybe_symbol = key->AsObject();
10614 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616
10617 // If the symbol table grew as part of EnsureCapacity, obj is not
10618 // the current symbol table and therefore we cannot use
10619 // SymbolTable::cast here.
10620 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10621
10622 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010623 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010624 table->set(EntryToIndex(entry), symbol);
10625 table->ElementAdded();
10626 *s = symbol;
10627 return table;
10628}
10629
10630
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010631Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010632 StringKey key(src);
10633 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010634 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010635 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010636}
10637
10638
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010639Object* CompilationCacheTable::LookupEval(String* src,
10640 Context* context,
10641 StrictModeFlag strict_mode) {
10642 StringSharedKey key(src, context->closure()->shared(), strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010643 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010644 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000010645 return get(EntryToIndex(entry) + 1);
10646}
10647
10648
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010649Object* CompilationCacheTable::LookupRegExp(String* src,
10650 JSRegExp::Flags flags) {
10651 RegExpKey key(src, flags);
10652 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010653 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010654 return get(EntryToIndex(entry) + 1);
10655}
10656
10657
lrn@chromium.org303ada72010-10-27 09:33:13 +000010658MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010659 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010660 Object* obj;
10661 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10662 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10663 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010664
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010665 CompilationCacheTable* cache =
10666 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010667 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010668 cache->set(EntryToIndex(entry), src);
10669 cache->set(EntryToIndex(entry) + 1, value);
10670 cache->ElementAdded();
10671 return cache;
10672}
10673
10674
lrn@chromium.org303ada72010-10-27 09:33:13 +000010675MaybeObject* CompilationCacheTable::PutEval(String* src,
10676 Context* context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010677 SharedFunctionInfo* value) {
10678 StringSharedKey key(src,
10679 context->closure()->shared(),
10680 value->strict_mode() ? kStrictMode : kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010681 Object* obj;
10682 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10683 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10684 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010685
10686 CompilationCacheTable* cache =
10687 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010688 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000010689
lrn@chromium.org303ada72010-10-27 09:33:13 +000010690 Object* k;
10691 { MaybeObject* maybe_k = key.AsObject();
10692 if (!maybe_k->ToObject(&k)) return maybe_k;
10693 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010694
10695 cache->set(EntryToIndex(entry), k);
10696 cache->set(EntryToIndex(entry) + 1, value);
10697 cache->ElementAdded();
10698 return cache;
10699}
10700
10701
lrn@chromium.org303ada72010-10-27 09:33:13 +000010702MaybeObject* CompilationCacheTable::PutRegExp(String* src,
10703 JSRegExp::Flags flags,
10704 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010705 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010706 Object* obj;
10707 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10708 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10709 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010710
10711 CompilationCacheTable* cache =
10712 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010713 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010714 // We store the value in the key slot, and compare the search key
10715 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010716 cache->set(EntryToIndex(entry), value);
10717 cache->set(EntryToIndex(entry) + 1, value);
10718 cache->ElementAdded();
10719 return cache;
10720}
10721
10722
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010723void CompilationCacheTable::Remove(Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010724 Object* null_value = GetHeap()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010725 for (int entry = 0, size = Capacity(); entry < size; entry++) {
10726 int entry_index = EntryToIndex(entry);
10727 int value_index = entry_index + 1;
10728 if (get(value_index) == value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010729 fast_set(this, entry_index, null_value);
10730 fast_set(this, value_index, null_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010731 ElementRemoved();
10732 }
10733 }
10734 return;
10735}
10736
10737
ager@chromium.org236ad962008-09-25 09:45:57 +000010738// SymbolsKey used for HashTable where key is array of symbols.
10739class SymbolsKey : public HashTableKey {
10740 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010741 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000010742
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010743 bool IsMatch(Object* symbols) {
10744 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +000010745 int len = symbols_->length();
10746 if (o->length() != len) return false;
10747 for (int i = 0; i < len; i++) {
10748 if (o->get(i) != symbols_->get(i)) return false;
10749 }
10750 return true;
10751 }
10752
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010753 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000010754
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010755 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010756 FixedArray* symbols = FixedArray::cast(obj);
10757 int len = symbols->length();
10758 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000010759 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010760 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000010761 }
10762 return hash;
10763 }
10764
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010765 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000010766
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010767 private:
ager@chromium.org236ad962008-09-25 09:45:57 +000010768 FixedArray* symbols_;
10769};
10770
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010771
ager@chromium.org236ad962008-09-25 09:45:57 +000010772Object* MapCache::Lookup(FixedArray* array) {
10773 SymbolsKey key(array);
10774 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010775 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010776 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000010777}
10778
10779
lrn@chromium.org303ada72010-10-27 09:33:13 +000010780MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010781 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010782 Object* obj;
10783 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10785 }
ager@chromium.org236ad962008-09-25 09:45:57 +000010786
10787 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010788 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000010789 cache->set(EntryToIndex(entry), array);
10790 cache->set(EntryToIndex(entry) + 1, value);
10791 cache->ElementAdded();
10792 return cache;
10793}
10794
10795
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010796template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010797MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
10798 Object* obj;
10799 { MaybeObject* maybe_obj =
10800 HashTable<Shape, Key>::Allocate(at_least_space_for);
10801 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010803 // Initialize the next enumeration index.
10804 Dictionary<Shape, Key>::cast(obj)->
10805 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 return obj;
10807}
10808
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010809
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010810template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010811MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010812 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010813 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814
10815 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010816 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010818 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10819 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010821 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010822 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010823 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010824
10825 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010826 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010827 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829 FixedArray* enumeration_order = FixedArray::cast(obj);
10830
10831 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010832 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010833 int pos = 0;
10834 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010835 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010836 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837 }
10838 }
10839
10840 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010841 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842
10843 // Overwrite the enumeration_order with the enumeration indices.
10844 for (int i = 0; i < length; i++) {
10845 int index = Smi::cast(iteration_order->get(i))->value();
10846 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010847 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010848 }
10849
10850 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010851 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010852 pos = 0;
10853 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010854 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010855 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10856 PropertyDetails details = DetailsAt(i);
10857 PropertyDetails new_details =
10858 PropertyDetails(details.attributes(), details.type(), enum_index);
10859 DetailsAtPut(i, new_details);
10860 }
10861 }
10862
10863 // Set the next enumeration index.
10864 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10865 return this;
10866}
10867
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010868template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010869MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010870 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010871 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10873 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010874 Object* result;
10875 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10876 if (!maybe_result->ToObject(&result)) return maybe_result;
10877 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010879 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880}
10881
10882
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010883void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010884 // Do nothing if the interval [from, to) is empty.
10885 if (from >= to) return;
10886
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010887 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888 int removed_entries = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010889 Object* sentinel = heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 int capacity = Capacity();
10891 for (int i = 0; i < capacity; i++) {
10892 Object* key = KeyAt(i);
10893 if (key->IsNumber()) {
10894 uint32_t number = static_cast<uint32_t>(key->Number());
10895 if (from <= number && number < to) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010896 SetEntry(i, sentinel, sentinel);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897 removed_entries++;
10898 }
10899 }
10900 }
10901
10902 // Update the number of elements.
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000010903 ElementsRemoved(removed_entries);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010904}
10905
10906
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010907template<typename Shape, typename Key>
10908Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010909 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010910 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010911 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010912 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010913 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010914 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000010915 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010916 SetEntry(entry, heap->null_value(), heap->null_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010917 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010918 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919}
10920
10921
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010922template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000010923MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
10924 return HashTable<Shape, Key>::Shrink(key);
10925}
10926
10927
10928template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010929MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010930 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931
10932 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010933 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 ValueAtPut(entry, value);
10935 return this;
10936 }
10937
10938 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010939 Object* obj;
10940 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10941 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10942 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010943
lrn@chromium.org303ada72010-10-27 09:33:13 +000010944 Object* k;
10945 { MaybeObject* maybe_k = Shape::AsObject(key);
10946 if (!maybe_k->ToObject(&k)) return maybe_k;
10947 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010948 PropertyDetails details = PropertyDetails(NONE, NORMAL);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010949 return Dictionary<Shape, Key>::cast(obj)->
10950 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010951}
10952
10953
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010954template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010955MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10956 Object* value,
10957 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010958 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010959 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010961 Object* obj;
10962 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10963 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10964 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010965 return Dictionary<Shape, Key>::cast(obj)->
10966 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967}
10968
10969
10970// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010971template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010972MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
10973 Object* value,
10974 PropertyDetails details,
10975 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010976 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010977 Object* k;
10978 { MaybeObject* maybe_k = Shape::AsObject(key);
10979 if (!maybe_k->ToObject(&k)) return maybe_k;
10980 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010981
10982 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010984 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010985 // Assign an enumeration index to the property and update
10986 // SetNextEnumerationIndex.
10987 int index = NextEnumerationIndex();
10988 details = PropertyDetails(details.attributes(), details.type(), index);
10989 SetNextEnumerationIndex(index + 1);
10990 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010991 SetEntry(entry, k, value, details);
10992 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
10993 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
10994 HashTable<Shape, Key>::ElementAdded();
10995 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996}
10997
10998
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010999void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011000 // If the dictionary requires slow elements an element has already
11001 // been added at a high index.
11002 if (requires_slow_elements()) return;
11003 // Check if this index is high enough that we should require slow
11004 // elements.
11005 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011006 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007 return;
11008 }
11009 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011010 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011012 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011013 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 }
11015}
11016
11017
lrn@chromium.org303ada72010-10-27 09:33:13 +000011018MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
11019 Object* value,
11020 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011021 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011022 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011023 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011024}
11025
11026
lrn@chromium.org303ada72010-10-27 09:33:13 +000011027MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011028 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011029 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011030}
11031
11032
lrn@chromium.org303ada72010-10-27 09:33:13 +000011033MaybeObject* NumberDictionary::Set(uint32_t key,
11034 Object* value,
11035 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011036 int entry = FindEntry(key);
11037 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011038 // Preserve enumeration index.
11039 details = PropertyDetails(details.attributes(),
11040 details.type(),
11041 DetailsAt(entry).index());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011042 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
11043 Object* object_key;
11044 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011045 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046 return this;
11047}
11048
11049
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011050
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011051template<typename Shape, typename Key>
11052int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11053 PropertyAttributes filter) {
11054 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011055 int result = 0;
11056 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011057 Object* k = HashTable<Shape, Key>::KeyAt(i);
11058 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011059 PropertyDetails details = DetailsAt(i);
11060 if (details.IsDeleted()) continue;
11061 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011062 if ((attr & filter) == 0) result++;
11063 }
11064 }
11065 return result;
11066}
11067
11068
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011069template<typename Shape, typename Key>
11070int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011071 return NumberOfElementsFilterAttributes(
11072 static_cast<PropertyAttributes>(DONT_ENUM));
11073}
11074
11075
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011076template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011077void Dictionary<Shape, Key>::CopyKeysTo(
11078 FixedArray* storage,
11079 PropertyAttributes filter,
11080 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011081 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011082 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011083 int index = 0;
11084 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011085 Object* k = HashTable<Shape, Key>::KeyAt(i);
11086 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011087 PropertyDetails details = DetailsAt(i);
11088 if (details.IsDeleted()) continue;
11089 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090 if ((attr & filter) == 0) storage->set(index++, k);
11091 }
11092 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011093 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11094 storage->SortPairs(storage, index);
11095 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011096 ASSERT(storage->length() >= index);
11097}
11098
11099
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011100void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11101 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011102 ASSERT(storage->length() >= NumberOfEnumElements());
11103 int capacity = Capacity();
11104 int index = 0;
11105 for (int i = 0; i < capacity; i++) {
11106 Object* k = KeyAt(i);
11107 if (IsKey(k)) {
11108 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011109 if (details.IsDeleted() || details.IsDontEnum()) continue;
11110 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011111 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011112 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011113 }
11114 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011115 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011116 ASSERT(storage->length() >= index);
11117}
11118
11119
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011120template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011121void Dictionary<Shape, Key>::CopyKeysTo(
11122 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011123 int index,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011124 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011125 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11126 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011127 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011128 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011129 Object* k = HashTable<Shape, Key>::KeyAt(i);
11130 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011131 PropertyDetails details = DetailsAt(i);
11132 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011133 storage->set(index++, k);
11134 }
11135 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011136 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11137 storage->SortPairs(storage, index);
11138 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011139 ASSERT(storage->length() >= index);
11140}
11141
11142
11143// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011144template<typename Shape, typename Key>
11145Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11146 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011148 Object* k = HashTable<Shape, Key>::KeyAt(i);
11149 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011150 Object* e = ValueAt(i);
11151 if (e->IsJSGlobalPropertyCell()) {
11152 e = JSGlobalPropertyCell::cast(e)->value();
11153 }
11154 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011155 }
11156 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011157 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011158 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011159}
11160
11161
lrn@chromium.org303ada72010-10-27 09:33:13 +000011162MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011163 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011164 // Make sure we preserve dictionary representation if there are too many
11165 // descriptors.
11166 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
11167
11168 // Figure out if it is necessary to generate new enumeration indices.
11169 int max_enumeration_index =
11170 NextEnumerationIndex() +
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011171 (DescriptorArray::kMaxNumberOfDescriptors -
11172 NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011173 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011174 Object* result;
11175 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11176 if (!maybe_result->ToObject(&result)) return maybe_result;
11177 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011178 }
11179
11180 int instance_descriptor_length = 0;
11181 int number_of_fields = 0;
11182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011183 Heap* heap = GetHeap();
11184
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011185 // Compute the length of the instance descriptor.
11186 int capacity = Capacity();
11187 for (int i = 0; i < capacity; i++) {
11188 Object* k = KeyAt(i);
11189 if (IsKey(k)) {
11190 Object* value = ValueAt(i);
11191 PropertyType type = DetailsAt(i).type();
11192 ASSERT(type != FIELD);
11193 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000011194 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011195 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000011196 number_of_fields += 1;
11197 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011198 }
11199 }
11200
11201 // Allocate the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011202 Object* descriptors_unchecked;
11203 { MaybeObject* maybe_descriptors_unchecked =
11204 DescriptorArray::Allocate(instance_descriptor_length);
11205 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
11206 return maybe_descriptors_unchecked;
11207 }
11208 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011209 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011210
ager@chromium.org32912102009-01-16 10:38:43 +000011211 int inobject_props = obj->map()->inobject_properties();
11212 int number_of_allocated_fields =
11213 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011214 if (number_of_allocated_fields < 0) {
11215 // There is enough inobject space for all fields (including unused).
11216 number_of_allocated_fields = 0;
11217 unused_property_fields = inobject_props - number_of_fields;
11218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011219
11220 // Allocate the fixed array for the fields.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011221 Object* fields;
11222 { MaybeObject* maybe_fields =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011223 heap->AllocateFixedArray(number_of_allocated_fields);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011224 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
11225 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011226
11227 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011228 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011229 int current_offset = 0;
11230 for (int i = 0; i < capacity; i++) {
11231 Object* k = KeyAt(i);
11232 if (IsKey(k)) {
11233 Object* value = ValueAt(i);
11234 // Ensure the key is a symbol before writing into the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011235 Object* key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011236 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011237 if (!maybe_key->ToObject(&key)) return maybe_key;
11238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011239 PropertyDetails details = DetailsAt(i);
11240 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000011241
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011242 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011243 ConstantFunctionDescriptor d(String::cast(key),
11244 JSFunction::cast(value),
11245 details.attributes(),
11246 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011247 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011248 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000011249 if (current_offset < inobject_props) {
11250 obj->InObjectPropertyAtPut(current_offset,
11251 value,
11252 UPDATE_WRITE_BARRIER);
11253 } else {
11254 int offset = current_offset - inobject_props;
11255 FixedArray::cast(fields)->set(offset, value);
11256 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011257 FieldDescriptor d(String::cast(key),
11258 current_offset++,
11259 details.attributes(),
11260 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011261 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011262 } else if (type == CALLBACKS) {
11263 CallbacksDescriptor d(String::cast(key),
11264 value,
11265 details.attributes(),
11266 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011267 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011268 } else {
11269 UNREACHABLE();
11270 }
11271 }
11272 }
11273 ASSERT(current_offset == number_of_fields);
11274
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011275 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011276 // Allocate new map.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011277 Object* new_map;
11278 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
11279 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
11280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011281
11282 // Transform the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011283 obj->set_map(Map::cast(new_map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011284 obj->map()->set_instance_descriptors(descriptors);
11285 obj->map()->set_unused_property_fields(unused_property_fields);
11286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011287 obj->set_properties(FixedArray::cast(fields));
11288 ASSERT(obj->IsJSObject());
11289
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011290 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
ager@chromium.org32912102009-01-16 10:38:43 +000011291 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011292 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000011293
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011294 return obj;
11295}
11296
11297
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011298Object* ObjectHashTable::Lookup(JSObject* key) {
11299 // If the object does not have an identity hash, it was never used as a key.
11300 MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
11301 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
11302 int entry = FindEntry(key);
11303 if (entry == kNotFound) return GetHeap()->undefined_value();
11304 return get(EntryToIndex(entry) + 1);
11305}
11306
11307
11308MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
11309 // Make sure the key object has an identity hash code.
11310 int hash;
11311 { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
11312 if (maybe_hash->IsFailure()) return maybe_hash;
11313 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
11314 }
11315 int entry = FindEntry(key);
11316
11317 // Check whether to perform removal operation.
11318 if (value->IsUndefined()) {
11319 if (entry == kNotFound) return this;
11320 RemoveEntry(entry);
11321 return Shrink(key);
11322 }
11323
11324 // Key is already in table, just overwrite value.
11325 if (entry != kNotFound) {
11326 set(EntryToIndex(entry) + 1, value);
11327 return this;
11328 }
11329
11330 // Check whether the hash table should be extended.
11331 Object* obj;
11332 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11333 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11334 }
11335 ObjectHashTable* table = ObjectHashTable::cast(obj);
11336 table->AddEntry(table->FindInsertionEntry(hash), key, value);
11337 return table;
11338}
11339
11340
11341void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
11342 set(EntryToIndex(entry), key);
11343 set(EntryToIndex(entry) + 1, value);
11344 ElementAdded();
11345}
11346
11347
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011348void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
11349 set_null(heap, EntryToIndex(entry));
11350 set_null(heap, EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011351 ElementRemoved();
11352}
11353
11354
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011355#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356// Check if there is a break point at this code position.
11357bool DebugInfo::HasBreakPoint(int code_position) {
11358 // Get the break point info object for this code position.
11359 Object* break_point_info = GetBreakPointInfo(code_position);
11360
11361 // If there is no break point info object or no break points in the break
11362 // point info object there is no break point at this code position.
11363 if (break_point_info->IsUndefined()) return false;
11364 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
11365}
11366
11367
11368// Get the break point info object for this code position.
11369Object* DebugInfo::GetBreakPointInfo(int code_position) {
11370 // Find the index of the break point info object for this code position.
11371 int index = GetBreakPointInfoIndex(code_position);
11372
11373 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011374 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011375 return BreakPointInfo::cast(break_points()->get(index));
11376}
11377
11378
11379// Clear a break point at the specified code position.
11380void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
11381 int code_position,
11382 Handle<Object> break_point_object) {
11383 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11384 if (break_point_info->IsUndefined()) return;
11385 BreakPointInfo::ClearBreakPoint(
11386 Handle<BreakPointInfo>::cast(break_point_info),
11387 break_point_object);
11388}
11389
11390
11391void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
11392 int code_position,
11393 int source_position,
11394 int statement_position,
11395 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011396 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011397 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11398 if (!break_point_info->IsUndefined()) {
11399 BreakPointInfo::SetBreakPoint(
11400 Handle<BreakPointInfo>::cast(break_point_info),
11401 break_point_object);
11402 return;
11403 }
11404
11405 // Adding a new break point for a code position which did not have any
11406 // break points before. Try to find a free slot.
11407 int index = kNoBreakPointInfo;
11408 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11409 if (debug_info->break_points()->get(i)->IsUndefined()) {
11410 index = i;
11411 break;
11412 }
11413 }
11414 if (index == kNoBreakPointInfo) {
11415 // No free slot - extend break point info array.
11416 Handle<FixedArray> old_break_points =
11417 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011418 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011419 isolate->factory()->NewFixedArray(
11420 old_break_points->length() +
11421 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011422
11423 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 for (int i = 0; i < old_break_points->length(); i++) {
11425 new_break_points->set(i, old_break_points->get(i));
11426 }
11427 index = old_break_points->length();
11428 }
11429 ASSERT(index != kNoBreakPointInfo);
11430
11431 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011432 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11433 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11435 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11436 new_break_point_info->
11437 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011438 new_break_point_info->set_break_point_objects(
11439 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011440 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11441 debug_info->break_points()->set(index, *new_break_point_info);
11442}
11443
11444
11445// Get the break point objects for a code position.
11446Object* DebugInfo::GetBreakPointObjects(int code_position) {
11447 Object* break_point_info = GetBreakPointInfo(code_position);
11448 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011449 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011450 }
11451 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11452}
11453
11454
11455// Get the total number of break points.
11456int DebugInfo::GetBreakPointCount() {
11457 if (break_points()->IsUndefined()) return 0;
11458 int count = 0;
11459 for (int i = 0; i < break_points()->length(); i++) {
11460 if (!break_points()->get(i)->IsUndefined()) {
11461 BreakPointInfo* break_point_info =
11462 BreakPointInfo::cast(break_points()->get(i));
11463 count += break_point_info->GetBreakPointCount();
11464 }
11465 }
11466 return count;
11467}
11468
11469
11470Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11471 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011472 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011473 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011474 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11475 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11476 Handle<BreakPointInfo> break_point_info =
11477 Handle<BreakPointInfo>(BreakPointInfo::cast(
11478 debug_info->break_points()->get(i)));
11479 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11480 break_point_object)) {
11481 return *break_point_info;
11482 }
11483 }
11484 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011485 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011486}
11487
11488
11489// Find the index of the break point info object for the specified code
11490// position.
11491int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11492 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11493 for (int i = 0; i < break_points()->length(); i++) {
11494 if (!break_points()->get(i)->IsUndefined()) {
11495 BreakPointInfo* break_point_info =
11496 BreakPointInfo::cast(break_points()->get(i));
11497 if (break_point_info->code_position()->value() == code_position) {
11498 return i;
11499 }
11500 }
11501 }
11502 return kNoBreakPointInfo;
11503}
11504
11505
11506// Remove the specified break point object.
11507void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11508 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011509 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510 // If there are no break points just ignore.
11511 if (break_point_info->break_point_objects()->IsUndefined()) return;
11512 // If there is a single break point clear it if it is the same.
11513 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11514 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011515 break_point_info->set_break_point_objects(
11516 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011517 }
11518 return;
11519 }
11520 // If there are multiple break points shrink the array
11521 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11522 Handle<FixedArray> old_array =
11523 Handle<FixedArray>(
11524 FixedArray::cast(break_point_info->break_point_objects()));
11525 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527 int found_count = 0;
11528 for (int i = 0; i < old_array->length(); i++) {
11529 if (old_array->get(i) == *break_point_object) {
11530 ASSERT(found_count == 0);
11531 found_count++;
11532 } else {
11533 new_array->set(i - found_count, old_array->get(i));
11534 }
11535 }
11536 // If the break point was found in the list change it.
11537 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11538}
11539
11540
11541// Add the specified break point object.
11542void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11543 Handle<Object> break_point_object) {
11544 // If there was no break point objects before just set it.
11545 if (break_point_info->break_point_objects()->IsUndefined()) {
11546 break_point_info->set_break_point_objects(*break_point_object);
11547 return;
11548 }
11549 // If the break point object is the same as before just ignore.
11550 if (break_point_info->break_point_objects() == *break_point_object) return;
11551 // If there was one break point object before replace with array.
11552 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011553 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554 array->set(0, break_point_info->break_point_objects());
11555 array->set(1, *break_point_object);
11556 break_point_info->set_break_point_objects(*array);
11557 return;
11558 }
11559 // If there was more than one break point before extend array.
11560 Handle<FixedArray> old_array =
11561 Handle<FixedArray>(
11562 FixedArray::cast(break_point_info->break_point_objects()));
11563 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011565 for (int i = 0; i < old_array->length(); i++) {
11566 // If the break point was there before just ignore.
11567 if (old_array->get(i) == *break_point_object) return;
11568 new_array->set(i, old_array->get(i));
11569 }
11570 // Add the new break point.
11571 new_array->set(old_array->length(), *break_point_object);
11572 break_point_info->set_break_point_objects(*new_array);
11573}
11574
11575
11576bool BreakPointInfo::HasBreakPointObject(
11577 Handle<BreakPointInfo> break_point_info,
11578 Handle<Object> break_point_object) {
11579 // No break point.
11580 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011581 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011582 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11583 return break_point_info->break_point_objects() == *break_point_object;
11584 }
11585 // Multiple break points.
11586 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11587 for (int i = 0; i < array->length(); i++) {
11588 if (array->get(i) == *break_point_object) {
11589 return true;
11590 }
11591 }
11592 return false;
11593}
11594
11595
11596// Get the number of break points.
11597int BreakPointInfo::GetBreakPointCount() {
11598 // No break point.
11599 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011600 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011601 if (!break_point_objects()->IsFixedArray()) return 1;
11602 // Multiple break points.
11603 return FixedArray::cast(break_point_objects())->length();
11604}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011605#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011606
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011608} } // namespace v8::internal