blob: e35274d0aa72fee02ef44f2142943eeba45a7414 [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) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004640 return array->GetElementsAccessor()->AddJSArrayKeysToFixedArray(array, this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641}
4642
4643
lrn@chromium.org303ada72010-10-27 09:33:13 +00004644MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004645 int len0 = length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004646#ifdef DEBUG
4647 if (FLAG_enable_slow_asserts) {
4648 for (int i = 0; i < len0; i++) {
4649 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4650 }
4651 }
4652#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004653 int len1 = other->length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004654 // Optimize if 'other' is empty.
4655 // We cannot optimize if 'this' is empty, as other may have holes
4656 // or non keys.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657 if (len1 == 0) return this;
4658
4659 // Compute how many elements are not in this.
4660 int extra = 0;
4661 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004662 Object* value = other->get(y);
4663 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664 }
4665
ager@chromium.org5ec48922009-05-05 07:25:34 +00004666 if (extra == 0) return this;
4667
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004668 // Allocate the result
lrn@chromium.org303ada72010-10-27 09:33:13 +00004669 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004670 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004671 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4672 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004673 // Fill in the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004674 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675 FixedArray* result = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004676 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 for (int i = 0; i < len0; i++) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004678 Object* e = get(i);
4679 ASSERT(e->IsString() || e->IsNumber());
4680 result->set(i, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 }
4682 // Fill in the extra keys.
4683 int index = 0;
4684 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004685 Object* value = other->get(y);
4686 if (!value->IsTheHole() && !HasKey(this, value)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004687 Object* e = other->get(y);
4688 ASSERT(e->IsString() || e->IsNumber());
4689 result->set(len0 + index, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004690 index++;
4691 }
4692 }
4693 ASSERT(extra == index);
4694 return result;
4695}
4696
4697
lrn@chromium.org303ada72010-10-27 09:33:13 +00004698MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004699 Heap* heap = GetHeap();
4700 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004701 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004702 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004703 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4704 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004706 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004707 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 int len = length();
4709 if (new_length < len) len = new_length;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004710 result->set_map(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004711 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004712 for (int i = 0; i < len; i++) {
4713 result->set(i, get(i), mode);
4714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 return result;
4716}
4717
4718
4719void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004720 AssertNoAllocation no_gc;
4721 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004722 for (int index = 0; index < len; index++) {
4723 dest->set(dest_pos+index, get(pos+index), mode);
4724 }
4725}
4726
4727
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004728#ifdef DEBUG
4729bool FixedArray::IsEqualTo(FixedArray* other) {
4730 if (length() != other->length()) return false;
4731 for (int i = 0 ; i < length(); ++i) {
4732 if (get(i) != other->get(i)) return false;
4733 }
4734 return true;
4735}
4736#endif
4737
4738
lrn@chromium.org303ada72010-10-27 09:33:13 +00004739MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004740 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004741 if (number_of_descriptors == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004742 return heap->empty_descriptor_array();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004743 }
4744 // Allocate the array of keys.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004745 Object* array;
4746 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004748 if (!maybe_array->ToObject(&array)) return maybe_array;
4749 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004750 // Do not use DescriptorArray::cast on incomplete object.
4751 FixedArray* result = FixedArray::cast(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004752
4753 // Allocate the content array and set it in the descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004754 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004755 heap->AllocateFixedArray(number_of_descriptors << 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004756 if (!maybe_array->ToObject(&array)) return maybe_array;
4757 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004758 result->set(kBitField3StorageIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 result->set(kContentArrayIndex, array);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004760 result->set(kEnumerationIndexIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004761 Smi::FromInt(PropertyDetails::kInitialIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 return result;
4763}
4764
4765
4766void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4767 FixedArray* new_cache) {
4768 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4769 if (HasEnumCache()) {
4770 FixedArray::cast(get(kEnumerationIndexIndex))->
4771 set(kEnumCacheBridgeCacheIndex, new_cache);
4772 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004773 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004774 FixedArray::cast(bridge_storage)->
4775 set(kEnumCacheBridgeCacheIndex, new_cache);
4776 fast_set(FixedArray::cast(bridge_storage),
4777 kEnumCacheBridgeEnumIndex,
4778 get(kEnumerationIndexIndex));
4779 set(kEnumerationIndexIndex, bridge_storage);
4780 }
4781}
4782
4783
lrn@chromium.org303ada72010-10-27 09:33:13 +00004784MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4785 TransitionFlag transition_flag) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004786 // Transitions are only kept when inserting another transition.
4787 // This precondition is not required by this function's implementation, but
4788 // is currently required by the semantics of maps, so we check it.
4789 // Conversely, we filter after replacing, so replacing a transition and
4790 // removing all other transitions is not supported.
4791 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4792 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4793 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004794
4795 // Ensure the key is a symbol.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004796 Object* result;
4797 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4798 if (!maybe_result->ToObject(&result)) return maybe_result;
4799 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004800
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004801 int transitions = 0;
4802 int null_descriptors = 0;
4803 if (remove_transitions) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004804 for (int i = 0; i < number_of_descriptors(); i++) {
4805 if (IsTransition(i)) transitions++;
4806 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004807 }
4808 } else {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004809 for (int i = 0; i < number_of_descriptors(); i++) {
4810 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004811 }
4812 }
4813 int new_size = number_of_descriptors() - transitions - null_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004815 // If key is in descriptor, we replace it in-place when filtering.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004816 // Count a null descriptor for key as inserted, not replaced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004817 int index = Search(descriptor->GetKey());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004818 const bool inserting = (index == kNotFound);
4819 const bool replacing = !inserting;
4820 bool keep_enumeration_index = false;
4821 if (inserting) {
4822 ++new_size;
4823 }
4824 if (replacing) {
4825 // We are replacing an existing descriptor. We keep the enumeration
4826 // index of a visible property.
4827 PropertyType t = PropertyDetails(GetDetails(index)).type();
4828 if (t == CONSTANT_FUNCTION ||
4829 t == FIELD ||
4830 t == CALLBACKS ||
4831 t == INTERCEPTOR) {
4832 keep_enumeration_index = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004833 } else if (remove_transitions) {
4834 // Replaced descriptor has been counted as removed if it is
4835 // a transition that will be replaced. Adjust count in this case.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004836 ++new_size;
4837 }
4838 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004839 { MaybeObject* maybe_result = Allocate(new_size);
4840 if (!maybe_result->ToObject(&result)) return maybe_result;
4841 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004842 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004843 // Set the enumeration index in the descriptors and set the enumeration index
4844 // in the result.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004845 int enumeration_index = NextEnumerationIndex();
4846 if (!descriptor->GetDetails().IsTransition()) {
4847 if (keep_enumeration_index) {
4848 descriptor->SetEnumerationIndex(
4849 PropertyDetails(GetDetails(index)).index());
4850 } else {
4851 descriptor->SetEnumerationIndex(enumeration_index);
4852 ++enumeration_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004854 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004855 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4856
4857 // Copy the descriptors, filtering out transitions and null descriptors,
4858 // and inserting or replacing a descriptor.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004859 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004860 int from_index = 0;
4861 int to_index = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004862
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004863 for (; from_index < number_of_descriptors(); from_index++) {
4864 String* key = GetKey(from_index);
4865 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4866 break;
4867 }
4868 if (IsNullDescriptor(from_index)) continue;
4869 if (remove_transitions && IsTransition(from_index)) continue;
4870 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004871 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004872
4873 new_descriptors->Set(to_index++, descriptor);
4874 if (replacing) from_index++;
4875
4876 for (; from_index < number_of_descriptors(); from_index++) {
4877 if (IsNullDescriptor(from_index)) continue;
4878 if (remove_transitions && IsTransition(from_index)) continue;
4879 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004880 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004881
4882 ASSERT(to_index == new_descriptors->number_of_descriptors());
4883 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004884
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004885 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004886}
4887
4888
lrn@chromium.org303ada72010-10-27 09:33:13 +00004889MaybeObject* DescriptorArray::RemoveTransitions() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004890 // Remove all transitions and null descriptors. Return a copy of the array
4891 // with all transitions removed, or a Failure object if the new array could
4892 // not be allocated.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004893
4894 // Compute the size of the map transition entries to be removed.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004895 int num_removed = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004896 for (int i = 0; i < number_of_descriptors(); i++) {
4897 if (!IsProperty(i)) num_removed++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004898 }
4899
4900 // Allocate the new descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004901 Object* result;
4902 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4903 if (!maybe_result->ToObject(&result)) return maybe_result;
4904 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004905 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4906
4907 // Copy the content.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004908 int next_descriptor = 0;
4909 for (int i = 0; i < number_of_descriptors(); i++) {
4910 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004911 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004912 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004913
4914 return new_descriptors;
4915}
4916
4917
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004918void DescriptorArray::SortUnchecked() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004919 // In-place heap sort.
4920 int len = number_of_descriptors();
4921
4922 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004923 // Index of the last node with children
4924 const int max_parent_index = (len / 2) - 1;
4925 for (int i = max_parent_index; i >= 0; --i) {
4926 int parent_index = i;
4927 const uint32_t parent_hash = GetKey(i)->Hash();
4928 while (parent_index <= max_parent_index) {
4929 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004930 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004931 if (child_index + 1 < len) {
4932 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4933 if (right_child_hash > child_hash) {
4934 child_index++;
4935 child_hash = right_child_hash;
4936 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004937 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004938 if (child_hash <= parent_hash) break;
4939 Swap(parent_index, child_index);
4940 // Now element at child_index could be < its children.
4941 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942 }
4943 }
4944
4945 // Extract elements and create sorted array.
4946 for (int i = len - 1; i > 0; --i) {
4947 // Put max element at the back of the array.
4948 Swap(0, i);
4949 // Sift down the new top element.
4950 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004951 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4952 const int max_parent_index = (i / 2) - 1;
4953 while (parent_index <= max_parent_index) {
4954 int child_index = parent_index * 2 + 1;
4955 uint32_t child_hash = GetKey(child_index)->Hash();
4956 if (child_index + 1 < i) {
4957 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4958 if (right_child_hash > child_hash) {
4959 child_index++;
4960 child_hash = right_child_hash;
4961 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004962 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004963 if (child_hash <= parent_hash) break;
4964 Swap(parent_index, child_index);
4965 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004966 }
4967 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004968}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004970
4971void DescriptorArray::Sort() {
4972 SortUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004973 SLOW_ASSERT(IsSortedNoDuplicates());
4974}
4975
4976
4977int DescriptorArray::BinarySearch(String* name, int low, int high) {
4978 uint32_t hash = name->Hash();
4979
4980 while (low <= high) {
4981 int mid = (low + high) / 2;
4982 String* mid_name = GetKey(mid);
4983 uint32_t mid_hash = mid_name->Hash();
4984
4985 if (mid_hash > hash) {
4986 high = mid - 1;
4987 continue;
4988 }
4989 if (mid_hash < hash) {
4990 low = mid + 1;
4991 continue;
4992 }
4993 // Found an element with the same hash-code.
4994 ASSERT(hash == mid_hash);
4995 // There might be more, so we find the first one and
4996 // check them all to see if we have a match.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004997 if (name == mid_name && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4999 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005000 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 }
5002 break;
5003 }
5004 return kNotFound;
5005}
5006
5007
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005008int DescriptorArray::LinearSearch(String* name, int len) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005009 uint32_t hash = name->Hash();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005010 for (int number = 0; number < len; number++) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005011 String* entry = GetKey(number);
5012 if ((entry->Hash() == hash) &&
5013 name->Equals(entry) &&
5014 !is_null_descriptor(number)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00005015 return number;
5016 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005017 }
5018 return kNotFound;
5019}
5020
5021
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005022MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5023 PretenureFlag pretenure) {
5024 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005025 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005026 pretenure);
5027}
5028
5029
5030MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5031 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5033 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005034 pretenure);
5035}
5036
5037
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005038#ifdef DEBUG
5039bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5040 if (IsEmpty()) return other->IsEmpty();
5041 if (other->IsEmpty()) return false;
5042 if (length() != other->length()) return false;
5043 for (int i = 0; i < length(); ++i) {
5044 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5045 }
5046 return GetContentArray()->IsEqualTo(other->GetContentArray());
5047}
5048#endif
5049
5050
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005051bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005053 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005054}
5055
5056
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005057int String::Utf8Length() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005058 if (IsAsciiRepresentation()) return length();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005059 // Attempt to flatten before accessing the string. It probably
5060 // doesn't make Utf8Length faster, but it is very likely that
5061 // the string will be accessed later (for example by WriteUtf8)
5062 // so it's still a good idea.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005063 Heap* heap = GetHeap();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005064 TryFlatten();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 Access<StringInputBuffer> buffer(
5066 heap->isolate()->objects_string_input_buffer());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005067 buffer->Reset(0, this);
5068 int result = 0;
5069 while (buffer->has_more())
5070 result += unibrow::Utf8::Length(buffer->GetNext());
5071 return result;
5072}
5073
5074
ager@chromium.org7c537e22008-10-16 08:43:32 +00005075Vector<const char> String::ToAsciiVector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005076 ASSERT(IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005077 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005078
5079 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005080 int length = this->length();
5081 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005082 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005083 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005084 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005085 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005086 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005087 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005088 }
5089 if (string_tag == kSeqStringTag) {
5090 SeqAsciiString* seq = SeqAsciiString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005091 char* start = seq->GetChars();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005092 return Vector<const char>(start + offset, length);
5093 }
5094 ASSERT(string_tag == kExternalStringTag);
5095 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
5096 const char* start = ext->resource()->data();
5097 return Vector<const char>(start + offset, length);
5098}
5099
5100
5101Vector<const uc16> String::ToUC16Vector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005102 ASSERT(IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005103 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005104
5105 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005106 int length = this->length();
5107 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005108 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005109 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005110 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005111 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005112 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005113 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005114 }
5115 if (string_tag == kSeqStringTag) {
5116 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005117 return Vector<const uc16>(seq->GetChars() + offset, length);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005118 }
5119 ASSERT(string_tag == kExternalStringTag);
5120 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
5121 const uc16* start =
5122 reinterpret_cast<const uc16*>(ext->resource()->data());
5123 return Vector<const uc16>(start + offset, length);
5124}
5125
5126
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005127SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5128 RobustnessFlag robust_flag,
5129 int offset,
5130 int length,
5131 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005132 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
5133 return SmartPointer<char>(NULL);
5134 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005135 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005136
5137 // Negative length means the to the end of the string.
5138 if (length < 0) length = kMaxInt - offset;
5139
5140 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 Access<StringInputBuffer> buffer(
5142 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005143 buffer->Reset(offset, this);
5144 int character_position = offset;
5145 int utf8_bytes = 0;
5146 while (buffer->has_more()) {
5147 uint16_t character = buffer->GetNext();
5148 if (character_position < offset + length) {
5149 utf8_bytes += unibrow::Utf8::Length(character);
5150 }
5151 character_position++;
5152 }
5153
5154 if (length_return) {
5155 *length_return = utf8_bytes;
5156 }
5157
5158 char* result = NewArray<char>(utf8_bytes + 1);
5159
5160 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5161 buffer->Rewind();
5162 buffer->Seek(offset);
5163 character_position = offset;
5164 int utf8_byte_position = 0;
5165 while (buffer->has_more()) {
5166 uint16_t character = buffer->GetNext();
5167 if (character_position < offset + length) {
5168 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5169 character = ' ';
5170 }
5171 utf8_byte_position +=
5172 unibrow::Utf8::Encode(result + utf8_byte_position, character);
5173 }
5174 character_position++;
5175 }
5176 result[utf8_byte_position] = 0;
5177 return SmartPointer<char>(result);
5178}
5179
5180
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00005181SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5182 RobustnessFlag robust_flag,
5183 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005184 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5185}
5186
5187
5188const uc16* String::GetTwoByteData() {
5189 return GetTwoByteData(0);
5190}
5191
5192
5193const uc16* String::GetTwoByteData(unsigned start) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005194 ASSERT(!IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005195 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005196 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00005197 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 case kExternalStringTag:
5199 return ExternalTwoByteString::cast(this)->
5200 ExternalTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201 case kConsStringTag:
5202 UNREACHABLE();
5203 return NULL;
5204 }
5205 UNREACHABLE();
5206 return NULL;
5207}
5208
5209
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005210SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005211 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005212 return SmartPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005213 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005214 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005215
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 Access<StringInputBuffer> buffer(
5217 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218 buffer->Reset(this);
5219
5220 uc16* result = NewArray<uc16>(length() + 1);
5221
5222 int i = 0;
5223 while (buffer->has_more()) {
5224 uint16_t character = buffer->GetNext();
5225 result[i++] = character;
5226 }
5227 result[i] = 0;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00005228 return SmartPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229}
5230
5231
ager@chromium.org7c537e22008-10-16 08:43:32 +00005232const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005233 return reinterpret_cast<uc16*>(
5234 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5235}
5236
5237
ager@chromium.org7c537e22008-10-16 08:43:32 +00005238void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00005239 unsigned* offset_ptr,
5240 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005241 unsigned chars_read = 0;
5242 unsigned offset = *offset_ptr;
5243 while (chars_read < max_chars) {
5244 uint16_t c = *reinterpret_cast<uint16_t*>(
5245 reinterpret_cast<char*>(this) -
5246 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5247 if (c <= kMaxAsciiCharCode) {
5248 // Fast case for ASCII characters. Cursor is an input output argument.
5249 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5250 rbb->util_buffer,
5251 rbb->capacity,
5252 rbb->cursor)) {
5253 break;
5254 }
5255 } else {
5256 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5257 rbb->util_buffer,
5258 rbb->capacity,
5259 rbb->cursor)) {
5260 break;
5261 }
5262 }
5263 offset++;
5264 chars_read++;
5265 }
5266 *offset_ptr = offset;
5267 rbb->remaining += chars_read;
5268}
5269
5270
ager@chromium.org7c537e22008-10-16 08:43:32 +00005271const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5272 unsigned* remaining,
5273 unsigned* offset_ptr,
5274 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005275 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5276 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5277 *remaining = max_chars;
5278 *offset_ptr += max_chars;
5279 return b;
5280}
5281
5282
5283// This will iterate unless the block of string data spans two 'halves' of
5284// a ConsString, in which case it will recurse. Since the block of string
5285// data to be read has a maximum size this limits the maximum recursion
5286// depth to something sane. Since C++ does not have tail call recursion
5287// elimination, the iteration must be explicit. Since this is not an
5288// -IntoBuffer method it can delegate to one of the efficient
5289// *AsciiStringReadBlock routines.
5290const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5291 unsigned* offset_ptr,
5292 unsigned max_chars) {
5293 ConsString* current = this;
5294 unsigned offset = *offset_ptr;
5295 int offset_correction = 0;
5296
5297 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005298 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005299 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005300 if (left_length > offset &&
5301 (max_chars <= left_length - offset ||
5302 (rbb->capacity <= left_length - offset &&
5303 (max_chars = left_length - offset, true)))) { // comma operator!
5304 // Left hand side only - iterate unless we have reached the bottom of
5305 // the cons tree. The assignment on the left of the comma operator is
5306 // in order to make use of the fact that the -IntoBuffer routines can
5307 // produce at most 'capacity' characters. This enables us to postpone
5308 // the point where we switch to the -IntoBuffer routines (below) in order
5309 // to maximize the chances of delegating a big chunk of work to the
5310 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005311 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005312 current = ConsString::cast(left);
5313 continue;
5314 } else {
5315 const unibrow::byte* answer =
5316 String::ReadBlock(left, rbb, &offset, max_chars);
5317 *offset_ptr = offset + offset_correction;
5318 return answer;
5319 }
5320 } else if (left_length <= offset) {
5321 // Right hand side only - iterate unless we have reached the bottom of
5322 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00005323 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 offset -= left_length;
5325 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005326 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 current = ConsString::cast(right);
5328 continue;
5329 } else {
5330 const unibrow::byte* answer =
5331 String::ReadBlock(right, rbb, &offset, max_chars);
5332 *offset_ptr = offset + offset_correction;
5333 return answer;
5334 }
5335 } else {
5336 // The block to be read spans two sides of the ConsString, so we call the
5337 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5338 // are able to assemble data from several part strings because they use
5339 // the util_buffer to store their data and never return direct pointers
5340 // to their storage. We don't try to read more than the buffer capacity
5341 // here or we can get too much recursion.
5342 ASSERT(rbb->remaining == 0);
5343 ASSERT(rbb->cursor == 0);
5344 current->ConsStringReadBlockIntoBuffer(
5345 rbb,
5346 &offset,
5347 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5348 *offset_ptr = offset + offset_correction;
5349 return rbb->util_buffer;
5350 }
5351 }
5352}
5353
5354
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005355uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5356 ASSERT(index >= 0 && index < length());
5357 return resource()->data()[index];
5358}
5359
5360
5361const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5362 unsigned* remaining,
5363 unsigned* offset_ptr,
5364 unsigned max_chars) {
5365 // Cast const char* to unibrow::byte* (signedness difference).
5366 const unibrow::byte* b =
5367 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
5368 *remaining = max_chars;
5369 *offset_ptr += max_chars;
5370 return b;
5371}
5372
5373
5374const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5375 unsigned start) {
5376 return resource()->data() + start;
5377}
5378
5379
5380uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5381 ASSERT(index >= 0 && index < length());
5382 return resource()->data()[index];
5383}
5384
5385
5386void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5387 ReadBlockBuffer* rbb,
5388 unsigned* offset_ptr,
5389 unsigned max_chars) {
5390 unsigned chars_read = 0;
5391 unsigned offset = *offset_ptr;
5392 const uint16_t* data = resource()->data();
5393 while (chars_read < max_chars) {
5394 uint16_t c = data[offset];
5395 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00005396 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5398 rbb->util_buffer,
5399 rbb->capacity,
5400 rbb->cursor))
5401 break;
5402 } else {
5403 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5404 rbb->util_buffer,
5405 rbb->capacity,
5406 rbb->cursor))
5407 break;
5408 }
5409 offset++;
5410 chars_read++;
5411 }
5412 *offset_ptr = offset;
5413 rbb->remaining += chars_read;
5414}
5415
5416
ager@chromium.org7c537e22008-10-16 08:43:32 +00005417void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418 unsigned* offset_ptr,
5419 unsigned max_chars) {
5420 unsigned capacity = rbb->capacity - rbb->cursor;
5421 if (max_chars > capacity) max_chars = capacity;
5422 memcpy(rbb->util_buffer + rbb->cursor,
5423 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5424 *offset_ptr * kCharSize,
5425 max_chars);
5426 rbb->remaining += max_chars;
5427 *offset_ptr += max_chars;
5428 rbb->cursor += max_chars;
5429}
5430
5431
5432void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5433 ReadBlockBuffer* rbb,
5434 unsigned* offset_ptr,
5435 unsigned max_chars) {
5436 unsigned capacity = rbb->capacity - rbb->cursor;
5437 if (max_chars > capacity) max_chars = capacity;
5438 memcpy(rbb->util_buffer + rbb->cursor,
5439 resource()->data() + *offset_ptr,
5440 max_chars);
5441 rbb->remaining += max_chars;
5442 *offset_ptr += max_chars;
5443 rbb->cursor += max_chars;
5444}
5445
5446
5447// This method determines the type of string involved and then copies
5448// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5449// where they can be found. The pointer is not necessarily valid across a GC
5450// (see AsciiStringReadBlock).
5451const unibrow::byte* String::ReadBlock(String* input,
5452 ReadBlockBuffer* rbb,
5453 unsigned* offset_ptr,
5454 unsigned max_chars) {
5455 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5456 if (max_chars == 0) {
5457 rbb->remaining = 0;
5458 return NULL;
5459 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005460 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005462 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005463 SeqAsciiString* str = SeqAsciiString::cast(input);
5464 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5465 offset_ptr,
5466 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005468 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5469 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5470 offset_ptr,
5471 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005472 return rbb->util_buffer;
5473 }
5474 case kConsStringTag:
5475 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5476 offset_ptr,
5477 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005478 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005479 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005480 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5481 &rbb->remaining,
5482 offset_ptr,
5483 max_chars);
5484 } else {
5485 ExternalTwoByteString::cast(input)->
5486 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5487 offset_ptr,
5488 max_chars);
5489 return rbb->util_buffer;
5490 }
5491 default:
5492 break;
5493 }
5494
5495 UNREACHABLE();
5496 return 0;
5497}
5498
5499
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005500void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005501 Isolate* isolate = Isolate::Current();
5502 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005503 while (current != NULL) {
5504 current->PostGarbageCollection();
5505 current = current->prev_;
5506 }
5507}
5508
5509
5510// Reserve space for statics needing saving and restoring.
5511int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005512 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005513}
5514
5515
5516// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005517char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005518 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5519 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005520 return to + ArchiveSpacePerThread();
5521}
5522
5523
5524// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005525char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005526 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005527 return from + ArchiveSpacePerThread();
5528}
5529
5530
5531char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5532 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5533 Iterate(v, top);
5534 return thread_storage + ArchiveSpacePerThread();
5535}
5536
5537
5538void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005539 Isolate* isolate = Isolate::Current();
5540 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005541}
5542
5543
5544void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5545 Relocatable* current = top;
5546 while (current != NULL) {
5547 current->IterateInstance(v);
5548 current = current->prev_;
5549 }
5550}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005551
5552
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005553FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5554 : Relocatable(isolate),
5555 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005556 length_(str->length()) {
5557 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005558}
5559
5560
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005561FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5562 : Relocatable(isolate),
5563 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005564 is_ascii_(true),
5565 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005566 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005567
5568
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005569void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005570 if (str_ == NULL) return;
5571 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005572 ASSERT(str->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00005573 is_ascii_ = str->IsAsciiRepresentation();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005574 if (is_ascii_) {
5575 start_ = str->ToAsciiVector().start();
5576 } else {
5577 start_ = str->ToUC16Vector().start();
5578 }
5579}
5580
5581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005582void StringInputBuffer::Seek(unsigned pos) {
5583 Reset(pos, input_);
5584}
5585
5586
5587void SafeStringInputBuffer::Seek(unsigned pos) {
5588 Reset(pos, input_);
5589}
5590
5591
5592// This method determines the type of string involved and then copies
5593// a whole chunk of characters into a buffer. It can be used with strings
5594// that have been glued together to form a ConsString and which must cooperate
5595// to fill up a buffer.
5596void String::ReadBlockIntoBuffer(String* input,
5597 ReadBlockBuffer* rbb,
5598 unsigned* offset_ptr,
5599 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005600 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601 if (max_chars == 0) return;
5602
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005603 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005604 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005605 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005606 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 offset_ptr,
5608 max_chars);
5609 return;
5610 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005611 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005612 offset_ptr,
5613 max_chars);
5614 return;
5615 }
5616 case kConsStringTag:
5617 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5618 offset_ptr,
5619 max_chars);
5620 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005621 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005622 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005623 ExternalAsciiString::cast(input)->
5624 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5625 } else {
5626 ExternalTwoByteString::cast(input)->
5627 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5628 offset_ptr,
5629 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005630 }
5631 return;
5632 default:
5633 break;
5634 }
5635
5636 UNREACHABLE();
5637 return;
5638}
5639
5640
5641const unibrow::byte* String::ReadBlock(String* input,
5642 unibrow::byte* util_buffer,
5643 unsigned capacity,
5644 unsigned* remaining,
5645 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005646 ASSERT(*offset_ptr <= (unsigned)input->length());
5647 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005648 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5649 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005650 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 *remaining = rbb.remaining;
5652 return answer;
5653}
5654
5655
5656const unibrow::byte* String::ReadBlock(String** raw_input,
5657 unibrow::byte* util_buffer,
5658 unsigned capacity,
5659 unsigned* remaining,
5660 unsigned* offset_ptr) {
5661 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005662 ASSERT(*offset_ptr <= (unsigned)input->length());
5663 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 if (chars > capacity) chars = capacity;
5665 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5666 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005667 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005668 *remaining = rbb.remaining;
5669 return rbb.util_buffer;
5670}
5671
5672
5673// This will iterate unless the block of string data spans two 'halves' of
5674// a ConsString, in which case it will recurse. Since the block of string
5675// data to be read has a maximum size this limits the maximum recursion
5676// depth to something sane. Since C++ does not have tail call recursion
5677// elimination, the iteration must be explicit.
5678void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5679 unsigned* offset_ptr,
5680 unsigned max_chars) {
5681 ConsString* current = this;
5682 unsigned offset = *offset_ptr;
5683 int offset_correction = 0;
5684
5685 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005686 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005687 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005688 if (left_length > offset &&
5689 max_chars <= left_length - offset) {
5690 // Left hand side only - iterate unless we have reached the bottom of
5691 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005692 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005693 current = ConsString::cast(left);
5694 continue;
5695 } else {
5696 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5697 *offset_ptr = offset + offset_correction;
5698 return;
5699 }
5700 } else if (left_length <= offset) {
5701 // Right hand side only - iterate unless we have reached the bottom of
5702 // the cons tree.
5703 offset -= left_length;
5704 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005705 String* right = current->second();
5706 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005707 current = ConsString::cast(right);
5708 continue;
5709 } else {
5710 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5711 *offset_ptr = offset + offset_correction;
5712 return;
5713 }
5714 } else {
5715 // The block to be read spans two sides of the ConsString, so we recurse.
5716 // First recurse on the left.
5717 max_chars -= left_length - offset;
5718 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5719 // We may have reached the max or there may not have been enough space
5720 // in the buffer for the characters in the left hand side.
5721 if (offset == left_length) {
5722 // Recurse on the right.
5723 String* right = String::cast(current->second());
5724 offset -= left_length;
5725 offset_correction += left_length;
5726 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5727 }
5728 *offset_ptr = offset + offset_correction;
5729 return;
5730 }
5731 }
5732}
5733
5734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005735uint16_t ConsString::ConsStringGet(int index) {
5736 ASSERT(index >= 0 && index < this->length());
5737
5738 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00005739 if (second()->length() == 0) {
5740 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005741 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742 }
5743
5744 String* string = String::cast(this);
5745
5746 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005747 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005748 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005749 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005750 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005751 string = left;
5752 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005753 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005754 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005755 }
5756 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005757 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005758 }
5759 }
5760
5761 UNREACHABLE();
5762 return 0;
5763}
5764
5765
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005766template <typename sinkchar>
5767void String::WriteToFlat(String* src,
5768 sinkchar* sink,
5769 int f,
5770 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005771 String* source = src;
5772 int from = f;
5773 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005774 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005775 ASSERT(0 <= from && from <= to && to <= source->length());
5776 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005777 case kAsciiStringTag | kExternalStringTag: {
5778 CopyChars(sink,
5779 ExternalAsciiString::cast(source)->resource()->data() + from,
5780 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005781 return;
5782 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005783 case kTwoByteStringTag | kExternalStringTag: {
5784 const uc16* data =
5785 ExternalTwoByteString::cast(source)->resource()->data();
5786 CopyChars(sink,
5787 data + from,
5788 to - from);
5789 return;
5790 }
5791 case kAsciiStringTag | kSeqStringTag: {
5792 CopyChars(sink,
5793 SeqAsciiString::cast(source)->GetChars() + from,
5794 to - from);
5795 return;
5796 }
5797 case kTwoByteStringTag | kSeqStringTag: {
5798 CopyChars(sink,
5799 SeqTwoByteString::cast(source)->GetChars() + from,
5800 to - from);
5801 return;
5802 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005803 case kAsciiStringTag | kConsStringTag:
5804 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005805 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005806 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005807 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005808 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005809 // Right hand side is longer. Recurse over left.
5810 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005811 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005812 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005813 from = 0;
5814 } else {
5815 from -= boundary;
5816 }
5817 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005818 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005819 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005820 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005821 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005822 String* second = cons_string->second();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005823 WriteToFlat(second,
5824 sink + boundary - from,
5825 0,
5826 to - boundary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005827 to = boundary;
5828 }
5829 source = first;
5830 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005831 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005832 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005833 }
5834 }
5835}
5836
5837
ager@chromium.org7c537e22008-10-16 08:43:32 +00005838template <typename IteratorA, typename IteratorB>
5839static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5840 // General slow case check. We know that the ia and ib iterators
5841 // have the same length.
5842 while (ia->has_more()) {
5843 uc32 ca = ia->GetNext();
5844 uc32 cb = ib->GetNext();
5845 if (ca != cb)
5846 return false;
5847 }
5848 return true;
5849}
5850
5851
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005852// Compares the contents of two strings by reading and comparing
5853// int-sized blocks of characters.
5854template <typename Char>
5855static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5856 int length = a.length();
5857 ASSERT_EQ(length, b.length());
5858 const Char* pa = a.start();
5859 const Char* pb = b.start();
5860 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00005861#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005862 // If this architecture isn't comfortable reading unaligned ints
5863 // then we have to check that the strings are aligned before
5864 // comparing them blockwise.
5865 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5866 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5867 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005868 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005869#endif
5870 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5871 int endpoint = length - kStepSize;
5872 // Compare blocks until we reach near the end of the string.
5873 for (; i <= endpoint; i += kStepSize) {
5874 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5875 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5876 if (wa != wb) {
5877 return false;
5878 }
5879 }
ager@chromium.org9085a012009-05-11 19:22:57 +00005880#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005881 }
5882#endif
5883 // Compare the remaining characters that didn't fit into a block.
5884 for (; i < length; i++) {
5885 if (a[i] != b[i]) {
5886 return false;
5887 }
5888 }
5889 return true;
5890}
5891
5892
ager@chromium.org7c537e22008-10-16 08:43:32 +00005893template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005894static inline bool CompareStringContentsPartial(Isolate* isolate,
5895 IteratorA* ia,
5896 String* b) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005897 if (b->IsFlat()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005898 if (b->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005899 VectorIterator<char> ib(b->ToAsciiVector());
5900 return CompareStringContents(ia, &ib);
5901 } else {
ager@chromium.org9085a012009-05-11 19:22:57 +00005902 VectorIterator<uc16> ib(b->ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005903 return CompareStringContents(ia, &ib);
5904 }
5905 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005906 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5907 return CompareStringContents(ia,
5908 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005909 }
5910}
5911
5912
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005913bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005915 int len = length();
5916 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917 if (len == 0) return true;
5918
5919 // Fast check: if hash code is computed for both strings
5920 // a fast negative check can be performed.
5921 if (HasHashCode() && other->HasHashCode()) {
5922 if (Hash() != other->Hash()) return false;
5923 }
5924
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005925 // We know the strings are both non-empty. Compare the first chars
5926 // before we try to flatten the strings.
5927 if (this->Get(0) != other->Get(0)) return false;
5928
5929 String* lhs = this->TryFlattenGetString();
5930 String* rhs = other->TryFlattenGetString();
5931
5932 if (StringShape(lhs).IsSequentialAscii() &&
5933 StringShape(rhs).IsSequentialAscii()) {
5934 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5935 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005936 return CompareRawStringContents(Vector<const char>(str1, len),
5937 Vector<const char>(str2, len));
5938 }
5939
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005940 Isolate* isolate = GetIsolate();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005941 if (lhs->IsFlat()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00005942 if (lhs->IsAsciiRepresentation()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005943 Vector<const char> vec1 = lhs->ToAsciiVector();
5944 if (rhs->IsFlat()) {
5945 if (rhs->IsAsciiRepresentation()) {
5946 Vector<const char> vec2 = rhs->ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005947 return CompareRawStringContents(vec1, vec2);
5948 } else {
5949 VectorIterator<char> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005950 VectorIterator<uc16> ib(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005951 return CompareStringContents(&buf1, &ib);
5952 }
5953 } else {
5954 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005955 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5956 return CompareStringContents(&buf1,
5957 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005958 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005959 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005960 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5961 if (rhs->IsFlat()) {
5962 if (rhs->IsAsciiRepresentation()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005963 VectorIterator<uc16> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005964 VectorIterator<char> ib(rhs->ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005965 return CompareStringContents(&buf1, &ib);
5966 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005967 Vector<const uc16> vec2(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005968 return CompareRawStringContents(vec1, vec2);
5969 }
5970 } else {
5971 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005972 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5973 return CompareStringContents(&buf1,
5974 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005975 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005976 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005977 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5979 return CompareStringContentsPartial(isolate,
5980 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005981 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982}
5983
5984
5985bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005986 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005987
5988 Map* map = this->map();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005989 Heap* heap = map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005990 if (map == heap->string_map()) {
5991 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005993 } else if (map == heap->ascii_string_map()) {
5994 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 return true;
5996 }
5997 // Rest cannot be marked as undetectable
5998 return false;
5999}
6000
6001
6002bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006003 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006004 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00006005 Access<UnicodeCache::Utf8Decoder>
6006 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 decoder->Reset(str.start(), str.length());
6008 int i;
6009 for (i = 0; i < slen && decoder->has_more(); i++) {
6010 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006011 if (Get(i) != r) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006012 }
6013 return i == slen && !decoder->has_more();
6014}
6015
6016
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006017bool String::IsAsciiEqualTo(Vector<const char> str) {
6018 int slen = length();
6019 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006020 if (IsFlat() && IsAsciiRepresentation()) {
6021 return CompareChars(ToAsciiVector().start(), str.start(), slen) == 0;
6022 }
6023 for (int i = 0; i < slen; i++) {
6024 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006025 }
6026 return true;
6027}
6028
6029
6030bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6031 int slen = length();
6032 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00006033 if (IsFlat() && IsTwoByteRepresentation()) {
6034 return CompareChars(ToUC16Vector().start(), str.start(), slen) == 0;
6035 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00006036 for (int i = 0; i < slen; i++) {
6037 if (Get(i) != str[i]) return false;
6038 }
6039 return true;
6040}
6041
6042
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006043uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006044 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006045 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006046
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006047 const int len = length();
6048
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006049 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00006050 uint32_t field = 0;
6051 if (StringShape(this).IsSequentialAscii()) {
6052 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
6053 } else if (StringShape(this).IsSequentialTwoByte()) {
6054 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
6055 } else {
6056 StringInputBuffer buffer(this);
6057 field = ComputeHashField(&buffer, len);
6058 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006059
6060 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006061 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062
6063 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006064 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00006065 uint32_t result = field >> kHashShift;
6066 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6067 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068}
6069
6070
6071bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6072 uint32_t* index,
6073 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006074 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 uc32 ch = buffer->GetNext();
6076
6077 // If the string begins with a '0' character, it must only consist
6078 // of it to be a legal array index.
6079 if (ch == '0') {
6080 *index = 0;
6081 return length == 1;
6082 }
6083
6084 // Convert string to uint32 array index; character by character.
6085 int d = ch - '0';
6086 if (d < 0 || d > 9) return false;
6087 uint32_t result = d;
6088 while (buffer->has_more()) {
6089 d = buffer->GetNext() - '0';
6090 if (d < 0 || d > 9) return false;
6091 // Check that the new result is below the 32 bit limit.
6092 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6093 result = (result * 10) + d;
6094 }
6095
6096 *index = result;
6097 return true;
6098}
6099
6100
6101bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006102 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006103 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006104 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006105 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006106 // Isolate the array index form the full hash field.
6107 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006108 return true;
6109 } else {
6110 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006111 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006112 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006113}
6114
6115
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006116uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006117 // For array indexes mix the length into the hash as an array index could
6118 // be zero.
6119 ASSERT(length > 0);
6120 ASSERT(length <= String::kMaxArrayIndexSize);
6121 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6122 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006123
6124 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006125 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006126
6127 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6128 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6129 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006130 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006131}
6132
6133
ager@chromium.org7c537e22008-10-16 08:43:32 +00006134uint32_t StringHasher::GetHashField() {
6135 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006136 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006137 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00006138 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00006139 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006140 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006141 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006142 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006143 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006144}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006145
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00006147uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
6148 int length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006149 StringHasher hasher(length);
6150
6151 // Very long strings have a trivial hash that doesn't inspect the
6152 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006153 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006154 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006155 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006156
6157 // Do the iterative array index computation as long as there is a
6158 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006159 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006160 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006161 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006162
6163 // Process the remaining characters without updating the array
6164 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006165 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006166 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006167 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00006168
6169 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006170}
6171
6172
lrn@chromium.org303ada72010-10-27 09:33:13 +00006173MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006174 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006175 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006176 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006177 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178}
6179
6180
6181void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006183 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006184 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185 }
6186}
6187
6188
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006189void Map::CreateBackPointers() {
6190 DescriptorArray* descriptors = instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006191 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006192 if (descriptors->GetType(i) == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006193 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006194 descriptors->GetType(i) == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006195 // Get target.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006196 Map* target = Map::cast(descriptors->GetValue(i));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006197#ifdef DEBUG
6198 // Verify target.
6199 Object* source_prototype = prototype();
6200 Object* target_prototype = target->prototype();
6201 ASSERT(source_prototype->IsJSObject() ||
6202 source_prototype->IsMap() ||
6203 source_prototype->IsNull());
6204 ASSERT(target_prototype->IsJSObject() ||
6205 target_prototype->IsNull());
6206 ASSERT(source_prototype->IsMap() ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00006207 source_prototype == target_prototype);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006208#endif
6209 // Point target back to source. set_prototype() will not let us set
6210 // the prototype to a map, as we do here.
6211 *RawField(target, kPrototypeOffset) = this;
6212 }
6213 }
6214}
6215
6216
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006217void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006218 // Live DescriptorArray objects will be marked, so we must use
6219 // low-level accessors to get and modify their data.
6220 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00006221 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6222 if (d->IsEmpty()) return;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006223 Smi* NullDescriptorDetails =
6224 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
6225 FixedArray* contents = reinterpret_cast<FixedArray*>(
6226 d->get(DescriptorArray::kContentArrayIndex));
6227 ASSERT(contents->length() >= 2);
6228 for (int i = 0; i < contents->length(); i += 2) {
6229 // If the pair (value, details) is a map transition,
6230 // check if the target is live. If not, null the descriptor.
6231 // Also drop the back pointer for that map transition, so that this
6232 // map is not reached again by following a back pointer from a
6233 // non-live object.
6234 PropertyDetails details(Smi::cast(contents->get(i + 1)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006235 if (details.type() == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006236 details.type() == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00006237 details.type() == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006238 Map* target = reinterpret_cast<Map*>(contents->get(i));
6239 ASSERT(target->IsHeapObject());
6240 if (!target->IsMarked()) {
6241 ASSERT(target->IsMap());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006242 contents->set_unchecked(i + 1, NullDescriptorDetails);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006243 contents->set_null_unchecked(heap, i);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00006244 ASSERT(target->prototype() == this ||
6245 target->prototype() == real_prototype);
6246 // Getter prototype() is read-only, set_prototype() has side effects.
6247 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6248 }
6249 }
6250 }
6251}
6252
6253
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00006254int Map::Hash() {
6255 // For performance reasons we only hash the 3 most variable fields of a map:
6256 // constructor, prototype and bit_field2.
6257
6258 // Shift away the tag.
6259 int hash = (static_cast<uint32_t>(
6260 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6261
6262 // XOR-ing the prototype and constructor directly yields too many zero bits
6263 // when the two pointers are close (which is fairly common).
6264 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6265 hash ^= (static_cast<uint32_t>(
6266 reinterpret_cast<uintptr_t>(prototype())) << 2);
6267
6268 return hash ^ (hash >> 16) ^ bit_field2();
6269}
6270
6271
6272bool Map::EquivalentToForNormalization(Map* other,
6273 PropertyNormalizationMode mode) {
6274 return
6275 constructor() == other->constructor() &&
6276 prototype() == other->prototype() &&
6277 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6278 0 :
6279 other->inobject_properties()) &&
6280 instance_type() == other->instance_type() &&
6281 bit_field() == other->bit_field() &&
6282 bit_field2() == other->bit_field2() &&
6283 (bit_field3() & ~(1<<Map::kIsShared)) ==
6284 (other->bit_field3() & ~(1<<Map::kIsShared));
6285}
6286
6287
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006288void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6289 // Iterate over all fields in the body but take care in dealing with
6290 // the code entry.
6291 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6292 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6293 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6294}
6295
6296
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006297void JSFunction::MarkForLazyRecompilation() {
6298 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006299 ASSERT(shared()->allows_lazy_compilation() ||
6300 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006301 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006302 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006303}
6304
6305
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006306bool JSFunction::IsInlineable() {
6307 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006308 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006309 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00006310 if (!shared_info->script()->IsScript()) return false;
6311 if (shared_info->optimization_disabled()) return false;
6312 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006313 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6314 // If we never ran this (unlikely) then lets try to optimize it.
6315 if (code->kind() != Code::FUNCTION) return true;
6316 return code->optimizable();
6317}
6318
6319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006320Object* JSFunction::SetInstancePrototype(Object* value) {
6321 ASSERT(value->IsJSObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006322 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006323 if (has_initial_map()) {
6324 initial_map()->set_prototype(value);
6325 } else {
6326 // Put the value in the initial map field until an initial map is
6327 // needed. At that point, a new initial map is created and the
6328 // prototype is put into the initial map where it belongs.
6329 set_prototype_or_initial_map(value);
6330 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006331 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006332 return value;
6333}
6334
6335
lrn@chromium.org303ada72010-10-27 09:33:13 +00006336MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006337 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006338 Object* construct_prototype = value;
6339
6340 // If the value is not a JSObject, store the value in the map's
6341 // constructor field so it can be accessed. Also, set the prototype
6342 // used for constructing objects to the original object prototype.
6343 // See ECMA-262 13.2.2.
6344 if (!value->IsJSObject()) {
6345 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006346 // Remove map transitions because they point to maps with a
6347 // different prototype.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006348 Object* new_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006349 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006350 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00006351 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006352 Map* new_map = Map::cast(new_object);
6353 Heap* heap = new_map->heap();
6354 set_map(new_map);
6355 new_map->set_constructor(value);
6356 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006357 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006358 heap->isolate()->context()->global_context()->
6359 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360 } else {
6361 map()->set_non_instance_prototype(false);
6362 }
6363
6364 return SetInstancePrototype(construct_prototype);
6365}
6366
6367
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006368Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 Context* global_context = context()->global_context();
6370 Map* no_prototype_map = shared()->strict_mode()
6371 ? global_context->strict_mode_function_without_prototype_map()
6372 : global_context->function_without_prototype_map();
6373
6374 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00006375 // Be idempotent.
6376 return this;
6377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006378
6379 ASSERT(!shared()->strict_mode() ||
6380 map() == global_context->strict_mode_function_map());
6381 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
6382
6383 set_map(no_prototype_map);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006384 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006385 return this;
6386}
6387
6388
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006389Object* JSFunction::SetInstanceClassName(String* name) {
6390 shared()->set_instance_class_name(name);
6391 return this;
6392}
6393
6394
whesse@chromium.org023421e2010-12-21 12:19:12 +00006395void JSFunction::PrintName(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006396 SmartPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006397 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006398}
6399
6400
ager@chromium.org236ad962008-09-25 09:45:57 +00006401Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6402 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6403}
6404
6405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006406MaybeObject* Oddball::Initialize(const char* to_string,
6407 Object* to_number,
6408 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006409 Object* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006410 { MaybeObject* maybe_symbol =
6411 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006412 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006414 set_to_string(String::cast(symbol));
6415 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417 return this;
6418}
6419
6420
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006421String* SharedFunctionInfo::DebugName() {
6422 Object* n = name();
6423 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6424 return String::cast(n);
6425}
6426
6427
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428bool SharedFunctionInfo::HasSourceCode() {
6429 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006430 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006431}
6432
6433
6434Object* SharedFunctionInfo::GetSourceCode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006435 Isolate* isolate = GetIsolate();
6436 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6437 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006438 Object* source = Script::cast(script())->source();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006439 return *SubString(Handle<String>(String::cast(source), isolate),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006440 start_position(), end_position());
6441}
6442
6443
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006444int SharedFunctionInfo::SourceSize() {
6445 return end_position() - start_position();
6446}
6447
6448
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006449int SharedFunctionInfo::CalculateInstanceSize() {
6450 int instance_size =
6451 JSObject::kHeaderSize +
6452 expected_nof_properties() * kPointerSize;
6453 if (instance_size > JSObject::kMaxInstanceSize) {
6454 instance_size = JSObject::kMaxInstanceSize;
6455 }
6456 return instance_size;
6457}
6458
6459
6460int SharedFunctionInfo::CalculateInObjectProperties() {
6461 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6462}
6463
6464
ager@chromium.org5c838252010-02-19 08:53:10 +00006465bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6466 // Check the basic conditions for generating inline constructor code.
6467 if (!FLAG_inline_new
6468 || !has_only_simple_this_property_assignments()
6469 || this_property_assignments_count() == 0) {
6470 return false;
6471 }
6472
6473 // If the prototype is null inline constructors cause no problems.
6474 if (!prototype->IsJSObject()) {
6475 ASSERT(prototype->IsNull());
6476 return true;
6477 }
6478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006479 Heap* heap = GetHeap();
6480
ager@chromium.org5c838252010-02-19 08:53:10 +00006481 // Traverse the proposed prototype chain looking for setters for properties of
6482 // the same names as are set by the inline constructor.
6483 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006484 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00006485 obj = obj->GetPrototype()) {
6486 JSObject* js_object = JSObject::cast(obj);
6487 for (int i = 0; i < this_property_assignments_count(); i++) {
6488 LookupResult result;
6489 String* name = GetThisPropertyAssignmentName(i);
6490 js_object->LocalLookupRealNamedProperty(name, &result);
6491 if (result.IsProperty() && result.type() == CALLBACKS) {
6492 return false;
6493 }
6494 }
6495 }
6496
6497 return true;
6498}
6499
6500
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00006501void SharedFunctionInfo::ForbidInlineConstructor() {
6502 set_compiler_hints(BooleanBit::set(compiler_hints(),
6503 kHasOnlySimpleThisPropertyAssignments,
6504 false));
6505}
6506
6507
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006508void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006509 bool only_simple_this_property_assignments,
6510 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006511 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006512 kHasOnlySimpleThisPropertyAssignments,
6513 only_simple_this_property_assignments));
6514 set_this_property_assignments(assignments);
6515 set_this_property_assignments_count(assignments->length() / 3);
6516}
6517
6518
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006519void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006521 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006522 kHasOnlySimpleThisPropertyAssignments,
6523 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006524 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006525 set_this_property_assignments_count(0);
6526}
6527
6528
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006529String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6530 Object* obj = this_property_assignments();
6531 ASSERT(obj->IsFixedArray());
6532 ASSERT(index < this_property_assignments_count());
6533 obj = FixedArray::cast(obj)->get(index * 3);
6534 ASSERT(obj->IsString());
6535 return String::cast(obj);
6536}
6537
6538
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006539bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6540 Object* obj = this_property_assignments();
6541 ASSERT(obj->IsFixedArray());
6542 ASSERT(index < this_property_assignments_count());
6543 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6544 return Smi::cast(obj)->value() != -1;
6545}
6546
6547
6548int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6549 ASSERT(IsThisPropertyAssignmentArgument(index));
6550 Object* obj =
6551 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6552 return Smi::cast(obj)->value();
6553}
6554
6555
6556Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6557 ASSERT(!IsThisPropertyAssignmentArgument(index));
6558 Object* obj =
6559 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6560 return obj;
6561}
6562
6563
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564// Support function for printing the source code to a StringStream
6565// without any allocation in the heap.
6566void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6567 int max_length) {
6568 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006569 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 accumulator->Add("<No Source>");
6571 return;
6572 }
6573
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006574 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006575 // Don't use String::cast because we don't want more assertion errors while
6576 // we are already creating a stack dump.
6577 String* script_source =
6578 reinterpret_cast<String*>(Script::cast(script())->source());
6579
6580 if (!script_source->LooksValid()) {
6581 accumulator->Add("<Invalid Source>");
6582 return;
6583 }
6584
6585 if (!is_toplevel()) {
6586 accumulator->Add("function ");
6587 Object* name = this->name();
6588 if (name->IsString() && String::cast(name)->length() > 0) {
6589 accumulator->PrintName(name);
6590 }
6591 }
6592
6593 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006594 if (len <= max_length || max_length < 0) {
6595 accumulator->Put(script_source, start_position(), end_position());
6596 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006597 accumulator->Put(script_source,
6598 start_position(),
6599 start_position() + max_length);
6600 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 }
6602}
6603
6604
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006605static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6606 if (code->instruction_size() != recompiled->instruction_size()) return false;
6607 ByteArray* code_relocation = code->relocation_info();
6608 ByteArray* recompiled_relocation = recompiled->relocation_info();
6609 int length = code_relocation->length();
6610 if (length != recompiled_relocation->length()) return false;
6611 int compare = memcmp(code_relocation->GetDataStartAddress(),
6612 recompiled_relocation->GetDataStartAddress(),
6613 length);
6614 return compare == 0;
6615}
6616
6617
6618void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6619 ASSERT(!has_deoptimization_support());
6620 AssertNoAllocation no_allocation;
6621 Code* code = this->code();
6622 if (IsCodeEquivalent(code, recompiled)) {
6623 // Copy the deoptimization data from the recompiled code.
6624 code->set_deoptimization_data(recompiled->deoptimization_data());
6625 code->set_has_deoptimization_support(true);
6626 } else {
6627 // TODO(3025757): In case the recompiled isn't equivalent to the
6628 // old code, we have to replace it. We should try to avoid this
6629 // altogether because it flushes valuable type feedback by
6630 // effectively resetting all IC state.
6631 set_code(recompiled);
6632 }
6633 ASSERT(has_deoptimization_support());
6634}
6635
6636
ager@chromium.orgea91cc52011-05-23 06:06:11 +00006637void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6638 // Disable optimization for the shared function info and mark the
6639 // code as non-optimizable. The marker on the shared function info
6640 // is there because we flush non-optimized code thereby loosing the
6641 // non-optimizable information for the code. When the code is
6642 // regenerated and set on the shared function info it is marked as
6643 // non-optimizable if optimization is disabled for the shared
6644 // function info.
6645 set_optimization_disabled(true);
6646 // Code should be the lazy compilation stub or else unoptimized. If the
6647 // latter, disable optimization for the code too.
6648 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6649 if (code()->kind() == Code::FUNCTION) {
6650 code()->set_optimizable(false);
6651 }
6652 if (FLAG_trace_opt) {
6653 PrintF("[disabled optimization for: ");
6654 function->PrintName();
6655 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6656 }
6657}
6658
6659
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006660bool SharedFunctionInfo::VerifyBailoutId(int id) {
6661 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6662 // we are always bailing out on ARM.
6663
6664 ASSERT(id != AstNode::kNoNumber);
6665 Code* unoptimized = code();
6666 DeoptimizationOutputData* data =
6667 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6668 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6669 USE(ignore);
6670 return true; // Return true if there was no ASSERT.
6671}
6672
6673
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006674void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6675 ASSERT(!IsInobjectSlackTrackingInProgress());
6676
6677 // Only initiate the tracking the first time.
6678 if (live_objects_may_exist()) return;
6679 set_live_objects_may_exist(true);
6680
6681 // No tracking during the snapshot construction phase.
6682 if (Serializer::enabled()) return;
6683
6684 if (map->unused_property_fields() == 0) return;
6685
6686 // Nonzero counter is a leftover from the previous attempt interrupted
6687 // by GC, keep it.
6688 if (construction_count() == 0) {
6689 set_construction_count(kGenerousAllocationCount);
6690 }
6691 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006693 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006694 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006695 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006696}
6697
6698
6699// Called from GC, hence reinterpret_cast and unchecked accessors.
6700void SharedFunctionInfo::DetachInitialMap() {
6701 Map* map = reinterpret_cast<Map*>(initial_map());
6702
6703 // Make the map remember to restore the link if it survives the GC.
6704 map->set_bit_field2(
6705 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6706
6707 // Undo state changes made by StartInobjectTracking (except the
6708 // construction_count). This way if the initial map does not survive the GC
6709 // then StartInobjectTracking will be called again the next time the
6710 // constructor is called. The countdown will continue and (possibly after
6711 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6713 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006714 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006715 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006716 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006717 // It is safe to clear the flag: it will be set again if the map is live.
6718 set_live_objects_may_exist(false);
6719}
6720
6721
6722// Called from GC, hence reinterpret_cast and unchecked accessors.
6723void SharedFunctionInfo::AttachInitialMap(Map* map) {
6724 map->set_bit_field2(
6725 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6726
6727 // Resume inobject slack tracking.
6728 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006729 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006730 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006731 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006732 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006733 // The map survived the gc, so there may be objects referencing it.
6734 set_live_objects_may_exist(true);
6735}
6736
6737
6738static void GetMinInobjectSlack(Map* map, void* data) {
6739 int slack = map->unused_property_fields();
6740 if (*reinterpret_cast<int*>(data) > slack) {
6741 *reinterpret_cast<int*>(data) = slack;
6742 }
6743}
6744
6745
6746static void ShrinkInstanceSize(Map* map, void* data) {
6747 int slack = *reinterpret_cast<int*>(data);
6748 map->set_inobject_properties(map->inobject_properties() - slack);
6749 map->set_unused_property_fields(map->unused_property_fields() - slack);
6750 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6751
6752 // Visitor id might depend on the instance size, recalculate it.
6753 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6754}
6755
6756
6757void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6758 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6759 Map* map = Map::cast(initial_map());
6760
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006761 Heap* heap = map->heap();
6762 set_initial_map(heap->undefined_value());
6763 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006764 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006765 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006766 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006767
6768 int slack = map->unused_property_fields();
6769 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6770 if (slack != 0) {
6771 // Resize the initial map and all maps in its transition tree.
6772 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00006773
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006774 // Give the correct expected_nof_properties to initial maps created later.
6775 ASSERT(expected_nof_properties() >= slack);
6776 set_expected_nof_properties(expected_nof_properties() - slack);
6777 }
6778}
6779
6780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006781void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006782 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006783 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6784 Object* old_target = target;
6785 VisitPointer(&target);
6786 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006787}
6788
6789
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006790void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6791 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6792 Object* old_code = code;
6793 VisitPointer(&code);
6794 if (code != old_code) {
6795 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6796 }
6797}
6798
6799
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006800void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6801 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6802 Object* cell = rinfo->target_cell();
6803 Object* old_cell = cell;
6804 VisitPointer(&cell);
6805 if (cell != old_cell) {
6806 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6807 }
6808}
6809
6810
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00006812 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6813 rinfo->IsPatchedReturnSequence()) ||
6814 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6815 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006816 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6817 Object* old_target = target;
6818 VisitPointer(&target);
6819 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820}
6821
6822
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006823void Code::InvalidateRelocation() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006824 set_relocation_info(heap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006825}
6826
6827
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006828void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006829 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6830 it.rinfo()->apply(delta);
6831 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006832 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833}
6834
6835
6836void Code::CopyFrom(const CodeDesc& desc) {
6837 // copy code
6838 memmove(instruction_start(), desc.buffer, desc.instr_size);
6839
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840 // copy reloc info
6841 memmove(relocation_start(),
6842 desc.buffer + desc.buffer_size - desc.reloc_size,
6843 desc.reloc_size);
6844
6845 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006846 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00006848 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006849 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006851 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006852 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006853 RelocInfo::Mode mode = it.rinfo()->rmode();
6854 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006855 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856 it.rinfo()->set_target_object(*p);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006857 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006858 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006859 it.rinfo()->set_target_cell(*cell);
ager@chromium.org236ad962008-09-25 09:45:57 +00006860 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006861 // rewrite code handles in inline cache targets to direct
6862 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006863 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006864 Code* code = Code::cast(*p);
6865 it.rinfo()->set_target_address(code->instruction_start());
6866 } else {
6867 it.rinfo()->apply(delta);
6868 }
6869 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006870 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006871}
6872
6873
6874// Locate the source position which is closest to the address in the code. This
6875// is using the source position information embedded in the relocation info.
6876// The position returned is relative to the beginning of the script where the
6877// source for this function is found.
6878int Code::SourcePosition(Address pc) {
6879 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00006880 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006881 // Run through all the relocation info to find the best matching source
6882 // position. All the code needs to be considered as the sequence of the
6883 // instructions in the code does not necessarily follow the same order as the
6884 // source.
6885 RelocIterator it(this, RelocInfo::kPositionMask);
6886 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006887 // Only look at positions after the current pc.
6888 if (it.rinfo()->pc() < pc) {
6889 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006890
6891 int dist = static_cast<int>(pc - it.rinfo()->pc());
6892 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00006893 // If this position is closer than the current candidate or if it has the
6894 // same distance as the current candidate and the position is higher then
6895 // this position is the new candidate.
6896 if ((dist < distance) ||
6897 (dist == distance && pos > position)) {
6898 position = pos;
6899 distance = dist;
6900 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006901 }
6902 it.next();
6903 }
6904 return position;
6905}
6906
6907
6908// Same as Code::SourcePosition above except it only looks for statement
6909// positions.
6910int Code::SourceStatementPosition(Address pc) {
6911 // First find the position as close as possible using all position
6912 // information.
6913 int position = SourcePosition(pc);
6914 // Now find the closest statement position before the position.
6915 int statement_position = 0;
6916 RelocIterator it(this, RelocInfo::kPositionMask);
6917 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006918 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006919 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920 if (statement_position < p && p <= position) {
6921 statement_position = p;
6922 }
6923 }
6924 it.next();
6925 }
6926 return statement_position;
6927}
6928
6929
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006930SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006931 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006932 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006933}
6934
6935
6936void Code::SetNoStackCheckTable() {
6937 // Indicate the absence of a stack-check table by a table start after the
6938 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006939 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006940}
6941
6942
6943Map* Code::FindFirstMap() {
6944 ASSERT(is_inline_cache_stub());
6945 AssertNoAllocation no_allocation;
6946 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6947 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6948 RelocInfo* info = it.rinfo();
6949 Object* object = info->target_object();
6950 if (object->IsMap()) return Map::cast(object);
6951 }
6952 return NULL;
6953}
6954
6955
ricow@chromium.org4f693d62011-07-04 14:01:31 +00006956#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006957
whesse@chromium.org023421e2010-12-21 12:19:12 +00006958void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006959 disasm::NameConverter converter;
6960 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006961 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006962 if (0 == deopt_count) return;
6963
whesse@chromium.org023421e2010-12-21 12:19:12 +00006964 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006965 for (int i = 0; i < deopt_count; i++) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006966 PrintF(out, "%6d %6d %6d",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006967 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006968
6969 if (!FLAG_print_code_verbose) continue;
6970 // Print details of the frame translation.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006971 int translation_index = TranslationIndex(i)->value();
6972 TranslationIterator iterator(TranslationByteArray(), translation_index);
6973 Translation::Opcode opcode =
6974 static_cast<Translation::Opcode>(iterator.Next());
6975 ASSERT(Translation::BEGIN == opcode);
6976 int frame_count = iterator.Next();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006977 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6978 frame_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006979
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00006980 while (iterator.HasNext() &&
6981 Translation::BEGIN !=
6982 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
6983 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
6984
6985 switch (opcode) {
6986 case Translation::BEGIN:
6987 UNREACHABLE();
6988 break;
6989
6990 case Translation::FRAME: {
6991 int ast_id = iterator.Next();
6992 int function_id = iterator.Next();
6993 JSFunction* function =
6994 JSFunction::cast(LiteralArray()->get(function_id));
6995 unsigned height = iterator.Next();
6996 PrintF(out, "{ast_id=%d, \nfunction=", ast_id);
6997 function->PrintName(out);
6998 PrintF(out, ", height=%u}", height);
6999 break;
7000 }
7001
7002 case Translation::DUPLICATE:
7003 break;
7004
7005 case Translation::REGISTER: {
7006 int reg_code = iterator.Next();
7007 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7008 break;
7009 }
7010
7011 case Translation::INT32_REGISTER: {
7012 int reg_code = iterator.Next();
7013 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7014 break;
7015 }
7016
7017 case Translation::DOUBLE_REGISTER: {
7018 int reg_code = iterator.Next();
7019 PrintF(out, "{input=%s}",
7020 DoubleRegister::AllocationIndexToString(reg_code));
7021 break;
7022 }
7023
7024 case Translation::STACK_SLOT: {
7025 int input_slot_index = iterator.Next();
7026 PrintF(out, "{input=%d}", input_slot_index);
7027 break;
7028 }
7029
7030 case Translation::INT32_STACK_SLOT: {
7031 int input_slot_index = iterator.Next();
7032 PrintF(out, "{input=%d}", input_slot_index);
7033 break;
7034 }
7035
7036 case Translation::DOUBLE_STACK_SLOT: {
7037 int input_slot_index = iterator.Next();
7038 PrintF(out, "{input=%d}", input_slot_index);
7039 break;
7040 }
7041
7042 case Translation::LITERAL: {
7043 unsigned literal_index = iterator.Next();
7044 PrintF(out, "{literal_id=%u}", literal_index);
7045 break;
7046 }
7047
7048 case Translation::ARGUMENTS_OBJECT:
7049 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007050 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00007051 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007052 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007053 }
7054}
7055
7056
whesse@chromium.org023421e2010-12-21 12:19:12 +00007057void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7058 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007059 this->DeoptPoints());
7060 if (this->DeoptPoints() == 0) return;
7061
7062 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7063 for (int i = 0; i < this->DeoptPoints(); i++) {
7064 int pc_and_state = this->PcAndState(i)->value();
7065 PrintF("%6d %8d %s\n",
7066 this->AstId(i)->value(),
7067 FullCodeGenerator::PcField::decode(pc_and_state),
7068 FullCodeGenerator::State2String(
7069 FullCodeGenerator::StateField::decode(pc_and_state)));
7070 }
7071}
7072
whesse@chromium.org7b260152011-06-20 15:33:18 +00007073
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007074// Identify kind of code.
7075const char* Code::Kind2String(Kind kind) {
7076 switch (kind) {
7077 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007078 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007079 case STUB: return "STUB";
7080 case BUILTIN: return "BUILTIN";
7081 case LOAD_IC: return "LOAD_IC";
7082 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7083 case STORE_IC: return "STORE_IC";
7084 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7085 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00007086 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00007087 case UNARY_OP_IC: return "UNARY_OP_IC";
7088 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007089 case COMPARE_IC: return "COMPARE_IC";
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007090 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007091 }
7092 UNREACHABLE();
7093 return NULL;
7094}
mads.s.ager31e71382008-08-13 09:32:07 +00007095
7096
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00007097const char* Code::ICState2String(InlineCacheState state) {
7098 switch (state) {
7099 case UNINITIALIZED: return "UNINITIALIZED";
7100 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7101 case MONOMORPHIC: return "MONOMORPHIC";
7102 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7103 case MEGAMORPHIC: return "MEGAMORPHIC";
7104 case DEBUG_BREAK: return "DEBUG_BREAK";
7105 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7106 }
7107 UNREACHABLE();
7108 return NULL;
7109}
7110
7111
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007112const char* Code::PropertyType2String(PropertyType type) {
7113 switch (type) {
7114 case NORMAL: return "NORMAL";
7115 case FIELD: return "FIELD";
7116 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7117 case CALLBACKS: return "CALLBACKS";
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00007118 case HANDLER: return "HANDLER";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007119 case INTERCEPTOR: return "INTERCEPTOR";
7120 case MAP_TRANSITION: return "MAP_TRANSITION";
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007121 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007122 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7123 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7124 }
7125 UNREACHABLE();
7126 return NULL;
7127}
7128
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007129
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007130void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7131 const char* name = NULL;
7132 switch (kind) {
7133 case CALL_IC:
7134 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7135 name = "STRING_INDEX_OUT_OF_BOUNDS";
7136 }
7137 break;
7138 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00007139 case KEYED_STORE_IC:
7140 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007141 name = "STRICT";
7142 }
7143 break;
7144 default:
7145 break;
7146 }
7147 if (name != NULL) {
7148 PrintF(out, "extra_ic_state = %s\n", name);
7149 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007150 PrintF(out, "extra_ic_state = %d\n", extra);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007151 }
7152}
7153
7154
whesse@chromium.org023421e2010-12-21 12:19:12 +00007155void Code::Disassemble(const char* name, FILE* out) {
7156 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007157 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007158 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00007159 PrintExtraICState(out, kind(), extra_ic_state());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007160 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007161 if (ic_state() == MONOMORPHIC) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007162 PrintF(out, "type = %s\n", PropertyType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007163 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00007164 if (is_call_stub() || is_keyed_call_stub()) {
7165 PrintF(out, "argc = %d\n", arguments_count());
7166 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007167 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007168 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007169 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007170 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007171 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007172 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007173 }
mads.s.ager31e71382008-08-13 09:32:07 +00007174
whesse@chromium.org023421e2010-12-21 12:19:12 +00007175 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7176 Disassembler::Decode(out, this);
7177 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00007178
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007179 if (kind() == FUNCTION) {
7180 DeoptimizationOutputData* data =
7181 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007182 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007183 } else if (kind() == OPTIMIZED_FUNCTION) {
7184 DeoptimizationInputData* data =
7185 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007186 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007187 }
7188 PrintF("\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007189
7190 if (kind() == OPTIMIZED_FUNCTION) {
7191 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007192 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007193 for (unsigned i = 0; i < table.length(); i++) {
7194 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007195 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007196 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00007197 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007198 SafepointEntry entry = table.GetEntry(i);
7199 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7200 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007201 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00007202 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007203 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007204 if (entry.argument_count() > 0) {
7205 PrintF(out, " argc: %d", entry.argument_count());
7206 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007207 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007208 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007209 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007210 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007211 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007212 // If there is no stack check table, the "table start" will at or after
7213 // (due to alignment) the end of the instruction stream.
7214 if (static_cast<int>(offset) < instruction_size()) {
7215 unsigned* address =
7216 reinterpret_cast<unsigned*>(instruction_start() + offset);
7217 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00007218 PrintF(out, "Stack checks (size = %u)\n", length);
7219 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007220 for (unsigned i = 0; i < length; ++i) {
7221 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00007222 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007223 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00007224 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007225 }
7226 }
7227
mads.s.ager31e71382008-08-13 09:32:07 +00007228 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00007229 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7230 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00007231}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00007232#endif // ENABLE_DISASSEMBLER
7233
7234
whesse@chromium.org7b260152011-06-20 15:33:18 +00007235static void CopyFastElementsToFast(FixedArray* source,
7236 FixedArray* destination,
7237 WriteBarrierMode mode) {
7238 uint32_t count = static_cast<uint32_t>(source->length());
7239 for (uint32_t i = 0; i < count; ++i) {
7240 destination->set(i, source->get(i), mode);
7241 }
7242}
7243
7244
7245static void CopySlowElementsToFast(NumberDictionary* source,
7246 FixedArray* destination,
7247 WriteBarrierMode mode) {
7248 for (int i = 0; i < source->Capacity(); ++i) {
7249 Object* key = source->KeyAt(i);
7250 if (key->IsNumber()) {
7251 uint32_t entry = static_cast<uint32_t>(key->Number());
7252 destination->set(entry, source->ValueAt(i), mode);
7253 }
7254 }
7255}
7256
7257
lrn@chromium.org303ada72010-10-27 09:33:13 +00007258MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7259 int length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007260 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00007261 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007262 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007263
whesse@chromium.org7b260152011-06-20 15:33:18 +00007264 // Allocate a new fast elements backing store.
7265 FixedArray* new_elements = NULL;
7266 { Object* object;
7267 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
7268 if (!maybe->ToObject(&object)) return maybe;
7269 new_elements = FixedArray::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007270 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007271
whesse@chromium.org7b260152011-06-20 15:33:18 +00007272 // Find the new map to use for this object if there is a map change.
7273 Map* new_map = NULL;
7274 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
7275 Object* object;
7276 MaybeObject* maybe = map()->GetFastElementsMap();
7277 if (!maybe->ToObject(&object)) return maybe;
7278 new_map = Map::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007279 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007280
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007281 switch (GetElementsKind()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007282 case FAST_ELEMENTS: {
7283 AssertNoAllocation no_gc;
7284 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007285 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
7286 set_map(new_map);
7287 set_elements(new_elements);
7288 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007289 }
7290 case DICTIONARY_ELEMENTS: {
7291 AssertNoAllocation no_gc;
7292 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007293 CopySlowElementsToFast(NumberDictionary::cast(elements()),
7294 new_elements,
7295 mode);
7296 set_map(new_map);
7297 set_elements(new_elements);
7298 break;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007299 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007300 case NON_STRICT_ARGUMENTS_ELEMENTS: {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007301 AssertNoAllocation no_gc;
7302 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007303 // The object's map and the parameter map are unchanged, the unaliased
7304 // arguments are copied to the new backing store.
7305 FixedArray* parameter_map = FixedArray::cast(elements());
7306 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7307 if (arguments->IsDictionary()) {
7308 CopySlowElementsToFast(NumberDictionary::cast(arguments),
7309 new_elements,
7310 mode);
7311 } else {
7312 CopyFastElementsToFast(arguments, new_elements, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007313 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007314 parameter_map->set(1, new_elements);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007315 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007316 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 case FAST_DOUBLE_ELEMENTS: {
7318 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7319 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7320 // Fill out the new array with this content and array holes.
7321 for (uint32_t i = 0; i < old_length; i++) {
7322 if (!old_elements->is_the_hole(i)) {
7323 Object* obj;
7324 // Objects must be allocated in the old object space, since the
7325 // overall number of HeapNumbers needed for the conversion might
7326 // exceed the capacity of new space, and we would fail repeatedly
7327 // trying to convert the FixedDoubleArray.
7328 MaybeObject* maybe_value_object =
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00007329 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
7330 TENURED);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007331 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7332 // Force write barrier. It's not worth trying to exploit
7333 // elems->GetWriteBarrierMode(), since it requires an
7334 // AssertNoAllocation stack object that would have to be positioned
7335 // after the HeapNumber allocation anyway.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007336 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007337 }
7338 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007339 set_map(new_map);
7340 set_elements(new_elements);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007341 break;
7342 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007343 case EXTERNAL_BYTE_ELEMENTS:
7344 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7345 case EXTERNAL_SHORT_ELEMENTS:
7346 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7347 case EXTERNAL_INT_ELEMENTS:
7348 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7349 case EXTERNAL_FLOAT_ELEMENTS:
7350 case EXTERNAL_DOUBLE_ELEMENTS:
7351 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007352 UNREACHABLE();
7353 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007355
whesse@chromium.org7b260152011-06-20 15:33:18 +00007356 // Update the length if necessary.
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007357 if (IsJSArray()) {
7358 JSArray::cast(this)->set_length(Smi::FromInt(length));
7359 }
7360
whesse@chromium.org7b260152011-06-20 15:33:18 +00007361 return new_elements;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007362}
7363
7364
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007365MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7366 int capacity,
7367 int length) {
7368 Heap* heap = GetHeap();
7369 // We should never end in here with a pixel or external array.
7370 ASSERT(!HasExternalArrayElements());
7371
7372 Object* obj;
7373 { MaybeObject* maybe_obj =
7374 heap->AllocateUninitializedFixedDoubleArray(capacity);
7375 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7376 }
7377 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
7378
7379 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
7380 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7381 }
7382 Map* new_map = Map::cast(obj);
7383
7384 AssertNoAllocation no_gc;
7385 switch (GetElementsKind()) {
7386 case FAST_ELEMENTS: {
7387 elems->Initialize(FixedArray::cast(elements()));
7388 break;
7389 }
7390 case FAST_DOUBLE_ELEMENTS: {
7391 elems->Initialize(FixedDoubleArray::cast(elements()));
7392 break;
7393 }
7394 case DICTIONARY_ELEMENTS: {
7395 elems->Initialize(NumberDictionary::cast(elements()));
7396 break;
7397 }
7398 default:
7399 UNREACHABLE();
7400 break;
7401 }
7402
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007403 ASSERT(new_map->has_fast_double_elements());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007404 set_map(new_map);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007405 ASSERT(elems->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007406 set_elements(elems);
7407
7408 if (IsJSArray()) {
7409 JSArray::cast(this)->set_length(Smi::FromInt(length));
7410 }
7411
7412 return this;
7413}
7414
7415
lrn@chromium.org303ada72010-10-27 09:33:13 +00007416MaybeObject* JSObject::SetSlowElements(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00007417 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007418 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007419
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420 uint32_t new_length = static_cast<uint32_t>(len->Number());
7421
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007422 switch (GetElementsKind()) {
7423 case FAST_ELEMENTS: {
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007424 case FAST_DOUBLE_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007425 // Make sure we never try to shrink dense arrays into sparse arrays.
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007426 ASSERT(static_cast<uint32_t>(
7427 FixedArrayBase::cast(elements())->length()) <= new_length);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007428 MaybeObject* result = NormalizeElements();
7429 if (result->IsFailure()) return result;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007430
7431 // Update length for JSArrays.
7432 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7433 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007435 case DICTIONARY_ELEMENTS: {
7436 if (IsJSArray()) {
7437 uint32_t old_length =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007438 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007439 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7440 JSArray::cast(this)->set_length(len);
7441 }
7442 break;
7443 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007444 case NON_STRICT_ARGUMENTS_ELEMENTS:
7445 UNIMPLEMENTED();
7446 break;
7447 case EXTERNAL_BYTE_ELEMENTS:
7448 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7449 case EXTERNAL_SHORT_ELEMENTS:
7450 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7451 case EXTERNAL_INT_ELEMENTS:
7452 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7453 case EXTERNAL_FLOAT_ELEMENTS:
7454 case EXTERNAL_DOUBLE_ELEMENTS:
7455 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007456 UNREACHABLE();
7457 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007458 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007459 return this;
7460}
7461
7462
lrn@chromium.org303ada72010-10-27 09:33:13 +00007463MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007464 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007466 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467 FixedArray* new_elements;
7468 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007469 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007471 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007472 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007473 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7474 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007475 new_elements = FixedArray::cast(obj);
7476 }
7477 set_elements(new_elements);
7478 return this;
7479}
7480
7481
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007482void JSArray::Expand(int required_size) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007483 Handle<JSArray> self(this);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007484 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007485 int old_size = old_backing->length();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00007486 int new_size = required_size > old_size ? required_size : old_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007487 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00007488 // Can't use this any more now because we may have had a GC!
7489 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7490 self->SetContent(*new_backing);
7491}
7492
7493
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007494static Failure* ArrayLengthRangeError(Heap* heap) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007495 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007496 return heap->isolate()->Throw(
7497 *FACTORY->NewRangeError("invalid_array_length",
7498 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007499}
7500
7501
lrn@chromium.org303ada72010-10-27 09:33:13 +00007502MaybeObject* JSObject::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00007503 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00007504 ASSERT(AllowsSetElementsLength());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007505
lrn@chromium.org303ada72010-10-27 09:33:13 +00007506 MaybeObject* maybe_smi_length = len->ToSmi();
7507 Object* smi_length = Smi::FromInt(0);
7508 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007509 const int value = Smi::cast(smi_length)->value();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007510 if (value < 0) return ArrayLengthRangeError(GetHeap());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007511 JSObject::ElementsKind elements_kind = GetElementsKind();
7512 switch (elements_kind) {
7513 case FAST_ELEMENTS:
7514 case FAST_DOUBLE_ELEMENTS: {
7515 int old_capacity = FixedArrayBase::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007516 if (value <= old_capacity) {
7517 if (IsJSArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007518 Object* obj;
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007519 if (elements_kind == FAST_ELEMENTS) {
7520 MaybeObject* maybe_obj = EnsureWritableFastElements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00007521 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7522 }
ager@chromium.org04921a82011-06-27 13:21:41 +00007523 if (2 * value <= old_capacity) {
7524 // If more than half the elements won't be used, trim the array.
7525 if (value == 0) {
7526 initialize_elements();
7527 } else {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007528 Address filler_start;
7529 int filler_size;
7530 if (GetElementsKind() == FAST_ELEMENTS) {
7531 FixedArray* fast_elements = FixedArray::cast(elements());
7532 fast_elements->set_length(value);
7533 filler_start = fast_elements->address() +
7534 FixedArray::OffsetOfElementAt(value);
7535 filler_size = (old_capacity - value) * kPointerSize;
7536 } else {
7537 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7538 FixedDoubleArray* fast_double_elements =
7539 FixedDoubleArray::cast(elements());
7540 fast_double_elements->set_length(value);
7541 filler_start = fast_double_elements->address() +
7542 FixedDoubleArray::OffsetOfElementAt(value);
7543 filler_size = (old_capacity - value) * kDoubleSize;
7544 }
ager@chromium.org04921a82011-06-27 13:21:41 +00007545 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
7546 }
7547 } else {
7548 // Otherwise, fill the unused tail with holes.
7549 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007550 if (GetElementsKind() == FAST_ELEMENTS) {
7551 FixedArray* fast_elements = FixedArray::cast(elements());
7552 for (int i = value; i < old_length; i++) {
7553 fast_elements->set_the_hole(i);
7554 }
7555 } else {
7556 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7557 FixedDoubleArray* fast_double_elements =
7558 FixedDoubleArray::cast(elements());
7559 for (int i = value; i < old_length; i++) {
7560 fast_double_elements->set_the_hole(i);
7561 }
ager@chromium.org04921a82011-06-27 13:21:41 +00007562 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007563 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007564 JSArray::cast(this)->set_length(Smi::cast(smi_length));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007565 }
7566 return this;
7567 }
7568 int min = NewElementsCapacity(old_capacity);
7569 int new_capacity = value > min ? value : min;
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007570 if (!ShouldConvertToSlowElements(new_capacity)) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +00007571 MaybeObject* result;
7572 if (GetElementsKind() == FAST_ELEMENTS) {
7573 result = SetFastElementsCapacityAndLength(new_capacity, value);
7574 } else {
7575 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7576 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
7577 value);
7578 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007579 if (result->IsFailure()) return result;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007580 return this;
7581 }
7582 break;
7583 }
7584 case DICTIONARY_ELEMENTS: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007585 if (IsJSArray()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007586 if (value == 0) {
7587 // If the length of a slow array is reset to zero, we clear
7588 // the array and flush backing storage. This has the added
7589 // benefit that the array returns to fast mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007590 Object* obj;
7591 { MaybeObject* maybe_obj = ResetElements();
7592 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7593 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007594 } else {
7595 // Remove deleted elements.
7596 uint32_t old_length =
7597 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7598 element_dictionary()->RemoveNumberEntries(value, old_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007599 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007600 JSArray::cast(this)->set_length(Smi::cast(smi_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007601 }
7602 return this;
7603 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007604 case NON_STRICT_ARGUMENTS_ELEMENTS:
7605 case EXTERNAL_BYTE_ELEMENTS:
7606 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7607 case EXTERNAL_SHORT_ELEMENTS:
7608 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7609 case EXTERNAL_INT_ELEMENTS:
7610 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7611 case EXTERNAL_FLOAT_ELEMENTS:
7612 case EXTERNAL_DOUBLE_ELEMENTS:
7613 case EXTERNAL_PIXEL_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007614 UNREACHABLE();
7615 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007616 }
7617 }
7618
7619 // General slow case.
7620 if (len->IsNumber()) {
7621 uint32_t length;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007622 if (len->ToArrayIndex(&length)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007623 return SetSlowElements(len);
7624 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007625 return ArrayLengthRangeError(GetHeap());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007626 }
7627 }
7628
7629 // len is not a number so make the array size one and
7630 // set only element to len.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007631 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007632 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007633 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7634 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007635 FixedArray::cast(obj)->set(0, len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007636 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007637 set_elements(FixedArray::cast(obj));
7638 return this;
7639}
7640
7641
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007642Object* Map::GetPrototypeTransition(Object* prototype) {
7643 FixedArray* cache = prototype_transitions();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007644 int number_of_transitions = NumberOfProtoTransitions();
7645 const int proto_offset =
7646 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7647 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7648 const int step = kProtoTransitionElementsPerEntry;
7649 for (int i = 0; i < number_of_transitions; i++) {
7650 if (cache->get(proto_offset + i * step) == prototype) {
7651 Object* map = cache->get(map_offset + i * step);
7652 ASSERT(map->IsMap());
7653 return map;
7654 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007655 }
7656 return NULL;
7657}
7658
7659
7660MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007661 ASSERT(map->IsMap());
7662 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007663 // Don't cache prototype transition if this map is shared.
7664 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7665
7666 FixedArray* cache = prototype_transitions();
7667
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007668 const int step = kProtoTransitionElementsPerEntry;
7669 const int header = kProtoTransitionHeaderSize;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007670
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007671 int capacity = (cache->length() - header) / step;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007672
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007673 int transitions = NumberOfProtoTransitions() + 1;
7674
7675 if (transitions > capacity) {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007676 if (capacity > kMaxCachedPrototypeTransitions) return this;
7677
7678 FixedArray* new_cache;
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007679 // Grow array by factor 2 over and above what we need.
7680 { MaybeObject* maybe_cache =
7681 heap()->AllocateFixedArray(transitions * 2 * step + header);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007682 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7683 }
7684
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007685 for (int i = 0; i < capacity * step; i++) {
7686 new_cache->set(i + header, cache->get(i + header));
7687 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007688 cache = new_cache;
7689 set_prototype_transitions(cache);
7690 }
7691
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007692 int last = transitions - 1;
7693
7694 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7695 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7696 SetNumberOfProtoTransitions(transitions);
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007697
7698 return cache;
7699}
7700
7701
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007702MaybeObject* JSReceiver::SetPrototype(Object* value,
7703 bool skip_hidden_prototypes) {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007704#ifdef DEBUG
7705 int size = Size();
7706#endif
7707
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007708 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00007709 // Silently ignore the change if value is not a JSObject or null.
7710 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007711 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00007712
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007713 // From 8.6.2 Object Internal Methods
7714 // ...
7715 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7716 // [[Prototype]] internal properties of the object may not be modified.
7717 // ...
7718 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7719 // or [[Extensible]] must not violate the invariants defined in the preceding
7720 // paragraph.
7721 if (!this->map()->is_extensible()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007722 HandleScope scope(heap->isolate());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007723 Handle<Object> handle(this, heap->isolate());
7724 return heap->isolate()->Throw(
7725 *FACTORY->NewTypeError("non_extensible_proto",
7726 HandleVector<Object>(&handle, 1)));
7727 }
7728
ager@chromium.org5c838252010-02-19 08:53:10 +00007729 // Before we can set the prototype we need to be sure
7730 // prototype cycles are prevented.
7731 // It is sufficient to validate that the receiver is not in the new prototype
7732 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007733 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007734 if (JSObject::cast(pt) == this) {
7735 // Cycle detected.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00007736 HandleScope scope(heap->isolate());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007737 return heap->isolate()->Throw(
7738 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00007739 }
7740 }
7741
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007742 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00007743
7744 if (skip_hidden_prototypes) {
7745 // Find the first object in the chain whose prototype object is not
7746 // hidden and set the new prototype on that object.
7747 Object* current_proto = real_receiver->GetPrototype();
7748 while (current_proto->IsJSObject() &&
7749 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7750 real_receiver = JSObject::cast(current_proto);
7751 current_proto = current_proto->GetPrototype();
7752 }
7753 }
7754
7755 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007756 Map* map = real_receiver->map();
7757
7758 // Nothing to do if prototype is already set.
7759 if (map->prototype() == value) return value;
7760
7761 Object* new_map = map->GetPrototypeTransition(value);
7762 if (new_map == NULL) {
7763 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7764 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7765 }
7766
7767 { MaybeObject* maybe_new_cache =
7768 map->PutPrototypeTransition(value, Map::cast(new_map));
7769 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7770 }
7771
7772 Map::cast(new_map)->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007773 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007774 ASSERT(Map::cast(new_map)->prototype() == value);
ager@chromium.org5c838252010-02-19 08:53:10 +00007775 real_receiver->set_map(Map::cast(new_map));
7776
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007777 heap->ClearInstanceofCache();
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00007778 ASSERT(size == Size());
ager@chromium.org5c838252010-02-19 08:53:10 +00007779 return value;
7780}
7781
7782
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007783bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007784 switch (GetElementsKind()) {
7785 case FAST_ELEMENTS: {
7786 uint32_t length = IsJSArray() ?
7787 static_cast<uint32_t>
7788 (Smi::cast(JSArray::cast(this)->length())->value()) :
7789 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7790 if ((index < length) &&
7791 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7792 return true;
7793 }
7794 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007795 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007796 case FAST_DOUBLE_ELEMENTS: {
7797 uint32_t length = IsJSArray() ?
7798 static_cast<uint32_t>
7799 (Smi::cast(JSArray::cast(this)->length())->value()) :
7800 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7801 if ((index < length) &&
7802 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7803 return true;
7804 }
7805 break;
7806 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007807 case EXTERNAL_PIXEL_ELEMENTS: {
7808 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007809 if (index < static_cast<uint32_t>(pixels->length())) {
7810 return true;
7811 }
7812 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007813 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007814 case EXTERNAL_BYTE_ELEMENTS:
7815 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7816 case EXTERNAL_SHORT_ELEMENTS:
7817 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7818 case EXTERNAL_INT_ELEMENTS:
7819 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007820 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007821 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007822 ExternalArray* array = ExternalArray::cast(elements());
7823 if (index < static_cast<uint32_t>(array->length())) {
7824 return true;
7825 }
7826 break;
7827 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007828 case DICTIONARY_ELEMENTS: {
7829 if (element_dictionary()->FindEntry(index)
7830 != NumberDictionary::kNotFound) {
7831 return true;
7832 }
7833 break;
7834 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007835 case NON_STRICT_ARGUMENTS_ELEMENTS:
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007836 UNREACHABLE();
7837 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007838 }
7839
7840 // Handle [] on String objects.
7841 if (this->IsStringObjectWithCharacterAt(index)) return true;
7842
7843 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007844 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007845 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7846}
7847
7848
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007849bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007850 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007851 // Make sure that the top context does not change when doing
7852 // callbacks or interceptor calls.
7853 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007854 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007855 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007856 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007858 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007859 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007860 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007861 v8::IndexedPropertyQuery query =
7862 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007863 LOG(isolate,
7864 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007865 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007866 {
7867 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007868 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869 result = query(index, info);
7870 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007871 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007872 ASSERT(result->IsInt32());
7873 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007874 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007875 } else if (!interceptor->getter()->IsUndefined()) {
7876 v8::IndexedPropertyGetter getter =
7877 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878 LOG(isolate,
7879 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007880 v8::Handle<v8::Value> result;
7881 {
7882 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007883 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007884 result = getter(index, info);
7885 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007886 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 }
7888 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7889}
7890
7891
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007892JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007893 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007894 if (IsAccessCheckNeeded()) {
7895 Heap* heap = GetHeap();
7896 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7897 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7898 return UNDEFINED_ELEMENT;
7899 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007900 }
7901
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007902 if (IsJSGlobalProxy()) {
7903 Object* proto = GetPrototype();
7904 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7905 ASSERT(proto->IsJSGlobalObject());
7906 return JSObject::cast(proto)->HasLocalElement(index);
7907 }
7908
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007909 // Check for lookup interceptor
7910 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007911 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7912 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007913 }
7914
7915 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007916 if (this->IsStringObjectWithCharacterAt(index)) {
7917 return STRING_CHARACTER_ELEMENT;
7918 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007919
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007920 switch (GetElementsKind()) {
7921 case FAST_ELEMENTS: {
7922 uint32_t length = IsJSArray() ?
7923 static_cast<uint32_t>
7924 (Smi::cast(JSArray::cast(this)->length())->value()) :
7925 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007926 if ((index < length) &&
7927 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7928 return FAST_ELEMENT;
7929 }
7930 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007931 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00007932 case FAST_DOUBLE_ELEMENTS: {
7933 uint32_t length = IsJSArray() ?
7934 static_cast<uint32_t>
7935 (Smi::cast(JSArray::cast(this)->length())->value()) :
7936 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7937 if ((index < length) &&
7938 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7939 return FAST_ELEMENT;
7940 }
7941 break;
7942 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007943 case EXTERNAL_PIXEL_ELEMENTS: {
7944 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007945 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7946 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007947 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007948 case EXTERNAL_BYTE_ELEMENTS:
7949 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7950 case EXTERNAL_SHORT_ELEMENTS:
7951 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7952 case EXTERNAL_INT_ELEMENTS:
7953 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007954 case EXTERNAL_FLOAT_ELEMENTS:
7955 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007956 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007957 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7958 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00007959 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007960 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007961 if (element_dictionary()->FindEntry(index) !=
whesse@chromium.org7b260152011-06-20 15:33:18 +00007962 NumberDictionary::kNotFound) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007963 return DICTIONARY_ELEMENT;
7964 }
7965 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007966 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00007967 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7968 // Aliased parameters and non-aliased elements in a fast backing store
7969 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
7970 // backing store behave as DICTIONARY_ELEMENT.
7971 FixedArray* parameter_map = FixedArray::cast(elements());
7972 uint32_t length = parameter_map->length();
7973 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00007974 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00007975 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
7976 // If not aliased, check the arguments.
7977 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7978 if (arguments->IsDictionary()) {
7979 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
7980 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
7981 return DICTIONARY_ELEMENT;
7982 }
7983 } else {
7984 length = arguments->length();
7985 probe = (index < length) ? arguments->get(index) : NULL;
7986 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
7987 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007988 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00007989 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007990 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007991
7992 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007993}
7994
7995
whesse@chromium.org7b260152011-06-20 15:33:18 +00007996bool JSObject::HasElementInElements(FixedArray* elements,
7997 ElementsKind kind,
7998 uint32_t index) {
7999 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8000 if (kind == FAST_ELEMENTS) {
8001 int length = IsJSArray()
8002 ? Smi::cast(JSArray::cast(this)->length())->value()
8003 : elements->length();
8004 if (index < static_cast<uint32_t>(length) &&
8005 !elements->get(index)->IsTheHole()) {
8006 return true;
8007 }
8008 } else {
8009 if (NumberDictionary::cast(elements)->FindEntry(index) !=
8010 NumberDictionary::kNotFound) {
8011 return true;
8012 }
8013 }
8014 return false;
8015}
8016
8017
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008018bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008019 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008020 if (IsAccessCheckNeeded()) {
8021 Heap* heap = GetHeap();
8022 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8023 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8024 return false;
8025 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008026 }
8027
8028 // Check for lookup interceptor
8029 if (HasIndexedInterceptor()) {
8030 return HasElementWithInterceptor(receiver, index);
8031 }
8032
whesse@chromium.org7b260152011-06-20 15:33:18 +00008033 ElementsKind kind = GetElementsKind();
8034 switch (kind) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008035 case FAST_ELEMENTS: {
8036 uint32_t length = IsJSArray() ?
8037 static_cast<uint32_t>
8038 (Smi::cast(JSArray::cast(this)->length())->value()) :
8039 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8040 if ((index < length) &&
8041 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8042 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008043 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00008044 case FAST_DOUBLE_ELEMENTS: {
8045 uint32_t length = IsJSArray() ?
8046 static_cast<uint32_t>
8047 (Smi::cast(JSArray::cast(this)->length())->value()) :
8048 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8049 if ((index < length) &&
8050 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8051 break;
8052 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008053 case EXTERNAL_PIXEL_ELEMENTS: {
8054 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008055 if (index < static_cast<uint32_t>(pixels->length())) {
8056 return true;
8057 }
8058 break;
8059 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008060 case EXTERNAL_BYTE_ELEMENTS:
8061 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8062 case EXTERNAL_SHORT_ELEMENTS:
8063 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8064 case EXTERNAL_INT_ELEMENTS:
8065 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008066 case EXTERNAL_FLOAT_ELEMENTS:
8067 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008068 ExternalArray* array = ExternalArray::cast(elements());
8069 if (index < static_cast<uint32_t>(array->length())) {
8070 return true;
8071 }
8072 break;
8073 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008074 case DICTIONARY_ELEMENTS: {
8075 if (element_dictionary()->FindEntry(index)
8076 != NumberDictionary::kNotFound) {
8077 return true;
8078 }
8079 break;
8080 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008081 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8082 FixedArray* parameter_map = FixedArray::cast(elements());
8083 uint32_t length = parameter_map->length();
8084 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00008085 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008086 if (probe != NULL && !probe->IsTheHole()) return true;
8087
8088 // Not a mapped parameter, check the arguments.
8089 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8090 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8091 if (HasElementInElements(arguments, kind, index)) return true;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008092 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008094 }
8095
8096 // Handle [] on String objects.
8097 if (this->IsStringObjectWithCharacterAt(index)) return true;
8098
8099 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008100 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8102}
8103
8104
lrn@chromium.org303ada72010-10-27 09:33:13 +00008105MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008106 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008107 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008108 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008110 // Make sure that the top context does not change when doing
8111 // callbacks or interceptor calls.
8112 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008113 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008114 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8115 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008116 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008117 if (!interceptor->setter()->IsUndefined()) {
8118 v8::IndexedPropertySetter setter =
8119 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008120 LOG(isolate,
8121 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8122 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008123 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008124 v8::Handle<v8::Value> result;
8125 {
8126 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008127 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008128 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8129 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008130 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008131 if (!result.IsEmpty()) return *value_handle;
8132 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008133 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008134 this_handle->SetElementWithoutInterceptor(index,
8135 *value_handle,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008136 strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008137 check_prototype);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008138 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008139 return raw_result;
8140}
8141
8142
lrn@chromium.org303ada72010-10-27 09:33:13 +00008143MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8144 Object* structure,
8145 uint32_t index,
8146 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008147 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00008148 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008149
8150 // api style callbacks.
8151 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008152 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008153 Object* fun_obj = data->getter();
8154 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008155 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008156 Handle<JSObject> self(JSObject::cast(receiver));
8157 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008158 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008159 Handle<String> key = isolate->factory()->NumberToString(number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008160 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8161 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008162 v8::AccessorInfo info(args.end());
8163 v8::Handle<v8::Value> result;
8164 {
8165 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008166 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008167 result = call_fun(v8::Utils::ToLocal(key), info);
8168 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008169 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8170 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008171 return *v8::Utils::OpenHandle(*result);
8172 }
8173
8174 // __defineGetter__ callback
8175 if (structure->IsFixedArray()) {
8176 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
8177 if (getter->IsJSFunction()) {
8178 return Object::GetPropertyWithDefinedGetter(receiver,
8179 JSFunction::cast(getter));
8180 }
8181 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008182 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008183 }
8184
8185 UNREACHABLE();
8186 return NULL;
8187}
8188
8189
lrn@chromium.org303ada72010-10-27 09:33:13 +00008190MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8191 uint32_t index,
8192 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008193 JSObject* holder,
8194 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008195 Isolate* isolate = GetIsolate();
8196 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008197
8198 // We should never get here to initialize a const with the hole
8199 // value since a const declaration would conflict with the setter.
8200 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008201 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008202
8203 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00008204 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008205 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00008206 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008207
8208 if (structure->IsAccessorInfo()) {
8209 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008210 Handle<JSObject> self(this);
8211 Handle<JSObject> holder_handle(JSObject::cast(holder));
8212 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008213 Object* call_obj = data->setter();
8214 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8215 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008216 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8217 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008218 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8219 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008220 v8::AccessorInfo info(args.end());
8221 {
8222 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008223 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008224 call_fun(v8::Utils::ToLocal(key),
8225 v8::Utils::ToLocal(value_handle),
8226 info);
8227 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008229 return *value_handle;
8230 }
8231
8232 if (structure->IsFixedArray()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008233 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008234 if (setter->IsJSFunction()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008235 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008236 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008237 if (strict_mode == kNonStrictMode) {
8238 return value;
8239 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 Handle<Object> holder_handle(holder, isolate);
8241 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008242 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008243 return isolate->Throw(
8244 *isolate->factory()->NewTypeError("no_setter_in_callback",
8245 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00008246 }
8247 }
8248
8249 UNREACHABLE();
8250 return NULL;
8251}
8252
8253
whesse@chromium.org7b260152011-06-20 15:33:18 +00008254bool JSObject::HasFastArgumentsElements() {
8255 Heap* heap = GetHeap();
8256 if (!elements()->IsFixedArray()) return false;
8257 FixedArray* elements = FixedArray::cast(this->elements());
8258 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8259 return false;
8260 }
8261 FixedArray* arguments = FixedArray::cast(elements->get(1));
8262 return !arguments->IsDictionary();
8263}
8264
8265
8266bool JSObject::HasDictionaryArgumentsElements() {
8267 Heap* heap = GetHeap();
8268 if (!elements()->IsFixedArray()) return false;
8269 FixedArray* elements = FixedArray::cast(this->elements());
8270 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8271 return false;
8272 }
8273 FixedArray* arguments = FixedArray::cast(elements->get(1));
8274 return arguments->IsDictionary();
8275}
8276
8277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278// Adding n elements in fast case is O(n*n).
8279// Note: revisit design to have dual undefined values to capture absent
8280// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008281MaybeObject* JSObject::SetFastElement(uint32_t index,
8282 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008283 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008284 bool check_prototype) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008285 ASSERT(HasFastElements() || HasFastArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008286
whesse@chromium.org7b260152011-06-20 15:33:18 +00008287 FixedArray* backing_store = FixedArray::cast(elements());
8288 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
8289 backing_store = FixedArray::cast(backing_store->get(1));
8290 } else {
8291 Object* writable;
8292 MaybeObject* maybe = EnsureWritableFastElements();
8293 if (!maybe->ToObject(&writable)) return maybe;
8294 backing_store = FixedArray::cast(writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008295 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008296 uint32_t length = static_cast<uint32_t>(backing_store->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008297
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008298 if (check_prototype &&
whesse@chromium.org7b260152011-06-20 15:33:18 +00008299 (index >= length || backing_store->get(index)->IsTheHole())) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008300 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00008301 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8302 value,
8303 &found,
8304 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008305 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008306 }
8307
ager@chromium.org04921a82011-06-27 13:21:41 +00008308 // Check whether there is extra space in fixed array.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008309 if (index < length) {
8310 backing_store->set(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311 if (IsJSArray()) {
8312 // Update the length of the array if needed.
8313 uint32_t array_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008314 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 if (index >= array_length) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008316 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317 }
8318 }
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00008319 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320 }
8321
8322 // Allow gap in fast case.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008323 if ((index - length) < kMaxGap) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 // Try allocating extra space.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008325 int new_capacity = NewElementsCapacity(index + 1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008326 if (!ShouldConvertToSlowElements(new_capacity)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008327 ASSERT(static_cast<uint32_t>(new_capacity) > index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008328 Object* new_elements;
8329 MaybeObject* maybe =
8330 SetFastElementsCapacityAndLength(new_capacity, index + 1);
8331 if (!maybe->ToObject(&new_elements)) return maybe;
8332 FixedArray::cast(new_elements)->set(index, value);
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00008333 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008334 }
8335 }
8336
8337 // Otherwise default to slow case.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008338 MaybeObject* result = NormalizeElements();
8339 if (result->IsFailure()) return result;
8340 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8341}
8342
8343
8344MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
8345 Object* value,
8346 StrictModeFlag strict_mode,
8347 bool check_prototype) {
8348 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
8349 Isolate* isolate = GetIsolate();
8350 Heap* heap = isolate->heap();
8351
8352 // Insert element in the dictionary.
8353 FixedArray* elements = FixedArray::cast(this->elements());
8354 bool is_arguments =
8355 (elements->map() == heap->non_strict_arguments_elements_map());
8356 NumberDictionary* dictionary = NULL;
8357 if (is_arguments) {
8358 dictionary = NumberDictionary::cast(elements->get(1));
8359 } else {
8360 dictionary = NumberDictionary::cast(elements);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008361 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008362
8363 int entry = dictionary->FindEntry(index);
8364 if (entry != NumberDictionary::kNotFound) {
8365 Object* element = dictionary->ValueAt(entry);
8366 PropertyDetails details = dictionary->DetailsAt(entry);
8367 if (details.type() == CALLBACKS) {
8368 return SetElementWithCallback(element, index, value, this, strict_mode);
8369 } else {
8370 dictionary->UpdateMaxNumberKey(index);
8371 // If put fails in strict mode, throw an exception.
8372 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008373 Handle<Object> holder(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00008374 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008375 Handle<Object> args[2] = { number, holder };
8376 Handle<Object> error =
8377 isolate->factory()->NewTypeError("strict_read_only_property",
8378 HandleVector(args, 2));
8379 return isolate->Throw(*error);
8380 }
8381 }
8382 } else {
8383 // Index not already used. Look for an accessor in the prototype chain.
8384 if (check_prototype) {
8385 bool found;
8386 MaybeObject* result =
8387 SetElementWithCallbackSetterInPrototypes(
8388 index, value, &found, strict_mode);
8389 if (found) return result;
8390 }
8391 // When we set the is_extensible flag to false we always force the
8392 // element into dictionary mode (and force them to stay there).
8393 if (!map()->is_extensible()) {
8394 if (strict_mode == kNonStrictMode) {
8395 return isolate->heap()->undefined_value();
8396 } else {
8397 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8398 Handle<String> name = isolate->factory()->NumberToString(number);
8399 Handle<Object> args[1] = { name };
8400 Handle<Object> error =
8401 isolate->factory()->NewTypeError("object_not_extensible",
8402 HandleVector(args, 1));
8403 return isolate->Throw(*error);
8404 }
8405 }
8406 Object* new_dictionary;
8407 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
8408 if (!maybe->ToObject(&new_dictionary)) return maybe;
8409 if (dictionary != NumberDictionary::cast(new_dictionary)) {
8410 if (is_arguments) {
8411 elements->set(1, new_dictionary);
8412 } else {
8413 set_elements(HeapObject::cast(new_dictionary));
8414 }
8415 dictionary = NumberDictionary::cast(new_dictionary);
8416 }
8417 }
8418
8419 // Update the array length if this JSObject is an array.
8420 if (IsJSArray()) {
8421 MaybeObject* result =
8422 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
8423 if (result->IsFailure()) return result;
8424 }
8425
8426 // Attempt to put this object back in fast case.
8427 if (ShouldConvertToFastElements()) {
8428 uint32_t new_length = 0;
8429 if (IsJSArray()) {
8430 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
8431 } else {
8432 new_length = dictionary->max_number_key() + 1;
8433 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008434 MaybeObject* result = CanConvertToFastDoubleElements()
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008435 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
8436 : SetFastElementsCapacityAndLength(new_length, new_length);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008437 if (result->IsFailure()) return result;
8438#ifdef DEBUG
8439 if (FLAG_trace_normalization) {
8440 PrintF("Object elements are fast case again:\n");
8441 Print();
8442 }
8443#endif
8444 }
8445 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446}
8447
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00008448
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008449MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8450 uint32_t index,
8451 Object* value,
8452 StrictModeFlag strict_mode,
8453 bool check_prototype) {
8454 ASSERT(HasFastDoubleElements());
8455
8456 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8457 uint32_t elms_length = static_cast<uint32_t>(elms->length());
8458
8459 // If storing to an element that isn't in the array, pass the store request
8460 // up the prototype chain before storing in the receiver's elements.
8461 if (check_prototype &&
8462 (index >= elms_length || elms->is_the_hole(index))) {
8463 bool found;
8464 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8465 value,
8466 &found,
8467 strict_mode);
8468 if (found) return result;
8469 }
8470
8471 // If the value object is not a heap number, switch to fast elements and try
8472 // again.
8473 bool value_is_smi = value->IsSmi();
8474 if (!value->IsNumber()) {
8475 Object* obj;
8476 uint32_t length = elms_length;
8477 if (IsJSArray()) {
8478 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8479 }
8480 MaybeObject* maybe_obj =
8481 SetFastElementsCapacityAndLength(elms_length, length);
8482 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8483 return SetFastElement(index, value, strict_mode, check_prototype);
8484 }
8485
8486 double double_value = value_is_smi
8487 ? static_cast<double>(Smi::cast(value)->value())
8488 : HeapNumber::cast(value)->value();
8489
8490 // Check whether there is extra space in the fixed array.
8491 if (index < elms_length) {
8492 elms->set(index, double_value);
8493 if (IsJSArray()) {
8494 // Update the length of the array if needed.
8495 uint32_t array_length = 0;
8496 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8497 if (index >= array_length) {
8498 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
8499 }
8500 }
8501 return value;
8502 }
8503
8504 // Allow gap in fast case.
8505 if ((index - elms_length) < kMaxGap) {
8506 // Try allocating extra space.
8507 int new_capacity = NewElementsCapacity(index+1);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00008508 if (!ShouldConvertToSlowElements(new_capacity)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008509 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8510 Object* obj;
8511 { MaybeObject* maybe_obj =
8512 SetFastDoubleElementsCapacityAndLength(new_capacity,
8513 index + 1);
8514 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8515 }
8516 FixedDoubleArray::cast(elements())->set(index, double_value);
8517 return value;
8518 }
8519 }
8520
8521 // Otherwise default to slow case.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008522 ASSERT(HasFastDoubleElements());
8523 ASSERT(map()->has_fast_double_elements());
8524 ASSERT(elements()->IsFixedDoubleArray());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008525 Object* obj;
8526 { MaybeObject* maybe_obj = NormalizeElements();
8527 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8528 }
8529 ASSERT(HasDictionaryElements());
8530 return SetElement(index, value, strict_mode, check_prototype);
8531}
8532
8533
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008534MaybeObject* JSObject::SetElement(uint32_t index,
8535 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008536 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008537 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008539 if (IsAccessCheckNeeded()) {
8540 Heap* heap = GetHeap();
8541 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008542 HandleScope scope(heap->isolate());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008543 Handle<Object> value_handle(value);
8544 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8545 return *value_handle;
8546 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008547 }
8548
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008549 if (IsJSGlobalProxy()) {
8550 Object* proto = GetPrototype();
8551 if (proto->IsNull()) return value;
8552 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008553 return JSObject::cast(proto)->SetElement(index,
8554 value,
8555 strict_mode,
8556 check_prototype);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008557 }
8558
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 // Check for lookup interceptor
8560 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008561 return SetElementWithInterceptor(index,
8562 value,
8563 strict_mode,
8564 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008565 }
8566
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008567 return SetElementWithoutInterceptor(index,
8568 value,
8569 strict_mode,
8570 check_prototype);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008571}
8572
8573
lrn@chromium.org303ada72010-10-27 09:33:13 +00008574MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008575 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008576 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00008577 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008578 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008579 switch (GetElementsKind()) {
8580 case FAST_ELEMENTS:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008581 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008582 case FAST_DOUBLE_ELEMENTS:
8583 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008584 case EXTERNAL_PIXEL_ELEMENTS: {
8585 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008586 return pixels->SetValue(index, value);
8587 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008588 case EXTERNAL_BYTE_ELEMENTS: {
8589 ExternalByteArray* array = ExternalByteArray::cast(elements());
8590 return array->SetValue(index, value);
8591 }
8592 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8593 ExternalUnsignedByteArray* array =
8594 ExternalUnsignedByteArray::cast(elements());
8595 return array->SetValue(index, value);
8596 }
8597 case EXTERNAL_SHORT_ELEMENTS: {
8598 ExternalShortArray* array = ExternalShortArray::cast(elements());
8599 return array->SetValue(index, value);
8600 }
8601 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8602 ExternalUnsignedShortArray* array =
8603 ExternalUnsignedShortArray::cast(elements());
8604 return array->SetValue(index, value);
8605 }
8606 case EXTERNAL_INT_ELEMENTS: {
8607 ExternalIntArray* array = ExternalIntArray::cast(elements());
8608 return array->SetValue(index, value);
8609 }
8610 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8611 ExternalUnsignedIntArray* array =
8612 ExternalUnsignedIntArray::cast(elements());
8613 return array->SetValue(index, value);
8614 }
8615 case EXTERNAL_FLOAT_ELEMENTS: {
8616 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8617 return array->SetValue(index, value);
8618 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008619 case EXTERNAL_DOUBLE_ELEMENTS: {
8620 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8621 return array->SetValue(index, value);
8622 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008623 case DICTIONARY_ELEMENTS:
8624 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8625 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8626 FixedArray* parameter_map = FixedArray::cast(elements());
8627 uint32_t length = parameter_map->length();
8628 Object* probe =
whesse@chromium.orgdf8c03c2011-06-21 14:36:03 +00008629 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008630 if (probe != NULL && !probe->IsTheHole()) {
8631 Context* context = Context::cast(parameter_map->get(0));
8632 int context_index = Smi::cast(probe)->value();
8633 ASSERT(!context->get(context_index)->IsTheHole());
8634 context->set(context_index, value);
8635 return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008636 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008637 // Object is not mapped, defer to the arguments.
8638 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8639 if (arguments->IsDictionary()) {
8640 return SetDictionaryElement(index, value, strict_mode,
8641 check_prototype);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008642 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008643 return SetFastElement(index, value, strict_mode, check_prototype);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008644 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008645 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008646 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008647 }
8648 // All possible cases have been handled above. Add a return to avoid the
8649 // complaints from the compiler.
8650 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008651 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008652}
8653
8654
lrn@chromium.org303ada72010-10-27 09:33:13 +00008655MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8656 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008657 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008658 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008659 // Check to see if we need to update the length. For now, we make
8660 // sure that the length stays within 32-bits (unsigned).
8661 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008662 Object* len;
8663 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008664 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008665 if (!maybe_len->ToObject(&len)) return maybe_len;
8666 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 set_length(len);
8668 }
8669 return value;
8670}
8671
8672
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00008673MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008674 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008675 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008676 // Make sure that the top context does not change when doing
8677 // callbacks or interceptor calls.
8678 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008679 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008680 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8681 Handle<Object> this_handle(receiver, isolate);
8682 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008684 v8::IndexedPropertyGetter getter =
8685 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008686 LOG(isolate,
8687 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8688 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008689 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690 v8::Handle<v8::Value> result;
8691 {
8692 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008693 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008694 result = getter(index, info);
8695 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8698 }
8699
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008700 Heap* heap = holder_handle->GetHeap();
8701 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
8702 MaybeObject* raw_result = handler->GetWithReceiver(*holder_handle,
8703 *this_handle,
8704 index);
8705 if (raw_result != heap->the_hole_value()) return raw_result;
8706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008707 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008708
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008709 Object* pt = holder_handle->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008710 if (pt == heap->null_value()) return heap->undefined_value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00008711 return pt->GetElementWithReceiver(*this_handle, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712}
8713
8714
8715bool JSObject::HasDenseElements() {
8716 int capacity = 0;
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008717 int used = 0;
8718 GetElementsCapacityAndUsage(&capacity, &used);
8719 return (capacity == 0) || (used > (capacity / 2));
8720}
8721
8722
8723void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
8724 *capacity = 0;
8725 *used = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008726
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008727 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
8728 FixedArray* backing_store = NULL;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008729 switch (GetElementsKind()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008730 case NON_STRICT_ARGUMENTS_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008731 backing_store_base =
8732 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
8733 backing_store = FixedArray::cast(backing_store_base);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008734 if (backing_store->IsDictionary()) {
8735 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008736 *capacity = dictionary->Capacity();
8737 *used = dictionary->NumberOfElements();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008738 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008739 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00008740 // Fall through.
8741 case FAST_ELEMENTS:
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008742 backing_store = FixedArray::cast(backing_store_base);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008743 *capacity = backing_store->length();
8744 for (int i = 0; i < *capacity; ++i) {
8745 if (!backing_store->get(i)->IsTheHole()) ++(*used);
whesse@chromium.org7b260152011-06-20 15:33:18 +00008746 }
8747 break;
8748 case DICTIONARY_ELEMENTS: {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008749 NumberDictionary* dictionary =
8750 NumberDictionary::cast(FixedArray::cast(elements()));
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008751 *capacity = dictionary->Capacity();
8752 *used = dictionary->NumberOfElements();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008753 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008754 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008755 case FAST_DOUBLE_ELEMENTS: {
8756 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008757 *capacity = elms->length();
8758 for (int i = 0; i < *capacity; i++) {
8759 if (!elms->is_the_hole(i)) ++(*used);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008760 }
8761 break;
8762 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008763 case EXTERNAL_BYTE_ELEMENTS:
8764 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8765 case EXTERNAL_SHORT_ELEMENTS:
8766 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8767 case EXTERNAL_INT_ELEMENTS:
8768 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008769 case EXTERNAL_FLOAT_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008770 case EXTERNAL_DOUBLE_ELEMENTS:
8771 case EXTERNAL_PIXEL_ELEMENTS:
8772 // External arrays are considered 100% used.
8773 ExternalArray* external_array = ExternalArray::cast(elements());
8774 *capacity = external_array->length();
8775 *used = external_array->length();
8776 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008777 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008778}
8779
8780
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008781bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008782 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
8783 kMaxUncheckedFastElementsLength);
8784 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
8785 (new_capacity <= kMaxUncheckedFastElementsLength &&
8786 GetHeap()->InNewSpace(this))) {
8787 return false;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008788 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008789 // If the fast-case backing storage takes up roughly three times as
8790 // much space (in machine words) as a dictionary backing storage
8791 // would, the object should have slow elements.
8792 int old_capacity = 0;
8793 int used_elements = 0;
8794 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
8795 int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
8796 NumberDictionary::kEntrySize;
8797 return 3 * dictionary_size <= new_capacity;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798}
8799
8800
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008801bool JSObject::ShouldConvertToFastElements() {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008802 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008803 // If the elements are sparse, we should not go back to fast case.
8804 if (!HasDenseElements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008805 // An object requiring access checks is never allowed to have fast
8806 // elements. If it had fast elements we would skip security checks.
8807 if (IsAccessCheckNeeded()) return false;
whesse@chromium.org7b260152011-06-20 15:33:18 +00008808
8809 FixedArray* elements = FixedArray::cast(this->elements());
8810 NumberDictionary* dictionary = NULL;
8811 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
8812 dictionary = NumberDictionary::cast(elements->get(1));
8813 } else {
8814 dictionary = NumberDictionary::cast(elements);
8815 }
8816 // If an element has been added at a very high index in the elements
8817 // dictionary, we cannot go back to fast case.
8818 if (dictionary->requires_slow_elements()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819 // If the dictionary backing storage takes up roughly half as much
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008820 // space (in machine words) as a fast-case backing storage would,
8821 // the object should have fast elements.
8822 uint32_t array_size = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008823 if (IsJSArray()) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008824 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 } else {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008826 array_size = dictionary->max_number_key();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008827 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008828 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
8829 NumberDictionary::kEntrySize;
8830 return 2 * dictionary_size >= array_size;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008831}
8832
8833
ricow@chromium.org2c99e282011-07-28 09:15:17 +00008834bool JSObject::CanConvertToFastDoubleElements() {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008835 if (FLAG_unbox_double_arrays) {
8836 ASSERT(HasDictionaryElements());
8837 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8838 for (int i = 0; i < dictionary->Capacity(); i++) {
8839 Object* key = dictionary->KeyAt(i);
8840 if (key->IsNumber()) {
8841 if (!dictionary->ValueAt(i)->IsNumber()) return false;
8842 }
8843 }
8844 return true;
8845 } else {
8846 return false;
8847 }
8848}
8849
8850
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008851// Certain compilers request function template instantiation when they
8852// see the definition of the other template functions in the
8853// class. This requires us to have the template functions put
8854// together, so even though this function belongs in objects-debug.cc,
8855// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +00008856#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008857template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +00008858void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008859 int capacity = HashTable<Shape, Key>::Capacity();
8860 for (int i = 0; i < capacity; i++) {
8861 Object* k = HashTable<Shape, Key>::KeyAt(i);
8862 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008863 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008864 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008865 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008866 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008867 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008868 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008869 PrintF(out, ": ");
8870 ValueAt(i)->ShortPrint(out);
8871 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008872 }
8873 }
8874}
8875#endif
8876
8877
8878template<typename Shape, typename Key>
8879void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008880 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008881 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008882 AssertNoAllocation no_gc;
8883 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008885 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8886 if (Dictionary<Shape, Key>::IsKey(k)) {
8887 elements->set(pos++, ValueAt(i), mode);
8888 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889 }
8890 ASSERT(pos == elements->length());
8891}
8892
8893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008894InterceptorInfo* JSObject::GetNamedInterceptor() {
8895 ASSERT(map()->has_named_interceptor());
8896 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008897 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008899 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008900 return InterceptorInfo::cast(result);
8901}
8902
8903
8904InterceptorInfo* JSObject::GetIndexedInterceptor() {
8905 ASSERT(map()->has_indexed_interceptor());
8906 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008907 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008908 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008909 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008910 return InterceptorInfo::cast(result);
8911}
8912
8913
lrn@chromium.org303ada72010-10-27 09:33:13 +00008914MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008915 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008916 String* name,
8917 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918 // Check local property in holder, ignore interceptor.
8919 LookupResult result;
8920 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008921 if (result.IsProperty()) {
8922 return GetProperty(receiver, &result, name, attributes);
8923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008924 // Continue searching via the prototype chain.
8925 Object* pt = GetPrototype();
8926 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008927 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008928 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8929}
8930
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008931
lrn@chromium.org303ada72010-10-27 09:33:13 +00008932MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008933 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008934 String* name,
8935 PropertyAttributes* attributes) {
8936 // Check local property in holder, ignore interceptor.
8937 LookupResult result;
8938 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008939 if (result.IsProperty()) {
8940 return GetProperty(receiver, &result, name, attributes);
8941 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008942 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008943}
8944
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008945
lrn@chromium.org303ada72010-10-27 09:33:13 +00008946MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008947 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00008948 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008949 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008950 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008951 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008952 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008953 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008954 Handle<JSObject> holder_handle(this);
8955 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008956
8957 if (!interceptor->getter()->IsUndefined()) {
8958 v8::NamedPropertyGetter getter =
8959 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008960 LOG(isolate,
8961 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8962 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008963 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 v8::Handle<v8::Value> result;
8965 {
8966 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008968 result = getter(v8::Utils::ToLocal(name_handle), info);
8969 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008970 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008971 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008973 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 }
8975 }
8976
lrn@chromium.org303ada72010-10-27 09:33:13 +00008977 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008978 *receiver_handle,
8979 *name_handle,
8980 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008981 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00008982 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008983}
8984
8985
8986bool JSObject::HasRealNamedProperty(String* key) {
8987 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008988 if (IsAccessCheckNeeded()) {
8989 Heap* heap = GetHeap();
8990 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8991 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8992 return false;
8993 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994 }
8995
8996 LookupResult result;
8997 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008998 return result.IsProperty() && (result.type() != INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008999}
9000
9001
9002bool JSObject::HasRealElementProperty(uint32_t index) {
9003 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009004 if (IsAccessCheckNeeded()) {
9005 Heap* heap = GetHeap();
9006 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9007 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9008 return false;
9009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009010 }
9011
9012 // Handle [] on String objects.
9013 if (this->IsStringObjectWithCharacterAt(index)) return true;
9014
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009015 switch (GetElementsKind()) {
9016 case FAST_ELEMENTS: {
9017 uint32_t length = IsJSArray() ?
9018 static_cast<uint32_t>(
9019 Smi::cast(JSArray::cast(this)->length())->value()) :
9020 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9021 return (index < length) &&
9022 !FixedArray::cast(elements())->get(index)->IsTheHole();
9023 }
ricow@chromium.org9fa09672011-07-25 11:05:35 +00009024 case FAST_DOUBLE_ELEMENTS: {
9025 uint32_t length = IsJSArray() ?
9026 static_cast<uint32_t>(
9027 Smi::cast(JSArray::cast(this)->length())->value()) :
9028 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9029 return (index < length) &&
9030 !FixedDoubleArray::cast(elements())->is_the_hole(index);
9031 break;
9032 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009033 case EXTERNAL_PIXEL_ELEMENTS: {
9034 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009035 return index < static_cast<uint32_t>(pixels->length());
9036 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009037 case EXTERNAL_BYTE_ELEMENTS:
9038 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9039 case EXTERNAL_SHORT_ELEMENTS:
9040 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9041 case EXTERNAL_INT_ELEMENTS:
9042 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009043 case EXTERNAL_FLOAT_ELEMENTS:
9044 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009045 ExternalArray* array = ExternalArray::cast(elements());
9046 return index < static_cast<uint32_t>(array->length());
9047 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009048 case DICTIONARY_ELEMENTS: {
9049 return element_dictionary()->FindEntry(index)
9050 != NumberDictionary::kNotFound;
9051 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009052 case NON_STRICT_ARGUMENTS_ELEMENTS:
9053 UNIMPLEMENTED();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009054 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009055 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009056 // All possibilities have been handled above already.
9057 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009058 return GetHeap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059}
9060
9061
9062bool JSObject::HasRealNamedCallbackProperty(String* key) {
9063 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009064 if (IsAccessCheckNeeded()) {
9065 Heap* heap = GetHeap();
9066 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9067 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9068 return false;
9069 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 }
9071
9072 LookupResult result;
9073 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00009074 return result.IsProperty() && (result.type() == CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009075}
9076
9077
9078int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
9079 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009080 DescriptorArray* descs = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009081 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009082 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009083 PropertyDetails details(descs->GetDetails(i));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009084 if (details.IsProperty() && (details.attributes() & filter) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009085 result++;
9086 }
9087 }
9088 return result;
9089 } else {
9090 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9091 }
9092}
9093
9094
9095int JSObject::NumberOfEnumProperties() {
9096 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
9097}
9098
9099
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009100void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009101 Object* temp = get(i);
9102 set(i, get(j));
9103 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009104 if (this != numbers) {
9105 temp = numbers->get(i);
9106 numbers->set(i, numbers->get(j));
9107 numbers->set(j, temp);
9108 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109}
9110
9111
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009112static void InsertionSortPairs(FixedArray* content,
9113 FixedArray* numbers,
9114 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009115 for (int i = 1; i < len; i++) {
9116 int j = i;
9117 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009118 (NumberToUint32(numbers->get(j - 1)) >
9119 NumberToUint32(numbers->get(j)))) {
9120 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009121 j--;
9122 }
9123 }
9124}
9125
9126
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009127void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009129 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130
9131 // Bottom-up max-heap construction.
9132 for (int i = 1; i < len; ++i) {
9133 int child_index = i;
9134 while (child_index > 0) {
9135 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009136 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9137 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009139 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140 } else {
9141 break;
9142 }
9143 child_index = parent_index;
9144 }
9145 }
9146
9147 // Extract elements and create sorted array.
9148 for (int i = len - 1; i > 0; --i) {
9149 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009150 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009151 // Sift down the new top element.
9152 int parent_index = 0;
9153 while (true) {
9154 int child_index = ((parent_index + 1) << 1) - 1;
9155 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009156 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
9157 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
9158 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 if (child_index + 1 >= i || child1_value > child2_value) {
9160 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009161 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 parent_index = child_index;
9163 } else {
9164 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009165 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166 parent_index = child_index + 1;
9167 }
9168 }
9169 }
9170}
9171
9172
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009173// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9174void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9175 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009176 // For small arrays, simply use insertion sort.
9177 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009178 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179 return;
9180 }
9181 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009182 uint32_t min_index = NumberToUint32(numbers->get(0));
9183 uint32_t max_index = min_index;
9184 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009186 if (NumberToUint32(numbers->get(i)) < min_index) {
9187 min_index = NumberToUint32(numbers->get(i));
9188 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9189 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009190 }
9191 }
9192 if (max_index - min_index + 1 == len) {
9193 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009194 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009195 // avoid hanging in case they are not.
9196 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009197 uint32_t p;
9198 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009199 // While the current element at i is not at its correct position p,
9200 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009201 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009203 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009204 }
9205 }
9206 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009207 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009208 return;
9209 }
9210}
9211
9212
9213// Fill in the names of local properties into the supplied storage. The main
9214// purpose of this function is to provide reflection information for the object
9215// mirrors.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009216void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009217 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009218 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009219 DescriptorArray* descs = map()->instance_descriptors();
9220 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9221 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009222 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009223 ASSERT(storage->length() >= index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009224 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009225 property_dictionary()->CopyKeysTo(storage,
9226 index,
9227 StringDictionary::UNSORTED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009228 }
9229}
9230
9231
9232int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9233 return GetLocalElementKeys(NULL, filter);
9234}
9235
9236
9237int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009238 // Fast case for objects with no elements.
9239 if (!IsJSValue() && HasFastElements()) {
9240 uint32_t length = IsJSArray() ?
9241 static_cast<uint32_t>(
9242 Smi::cast(JSArray::cast(this)->length())->value()) :
9243 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9244 if (length == 0) return 0;
9245 }
9246 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009247 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9248}
9249
9250
9251int JSObject::GetLocalElementKeys(FixedArray* storage,
9252 PropertyAttributes filter) {
9253 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009254 switch (GetElementsKind()) {
9255 case FAST_ELEMENTS: {
9256 int length = IsJSArray() ?
9257 Smi::cast(JSArray::cast(this)->length())->value() :
9258 FixedArray::cast(elements())->length();
9259 for (int i = 0; i < length; i++) {
9260 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9261 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009262 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009263 }
9264 counter++;
9265 }
9266 }
9267 ASSERT(!storage || storage->length() >= counter);
9268 break;
9269 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +00009270 case FAST_DOUBLE_ELEMENTS: {
9271 int length = IsJSArray() ?
9272 Smi::cast(JSArray::cast(this)->length())->value() :
9273 FixedDoubleArray::cast(elements())->length();
9274 for (int i = 0; i < length; i++) {
9275 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
9276 if (storage != NULL) {
9277 storage->set(counter, Smi::FromInt(i));
9278 }
9279 counter++;
9280 }
9281 }
9282 ASSERT(!storage || storage->length() >= counter);
9283 break;
9284 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009285 case EXTERNAL_PIXEL_ELEMENTS: {
9286 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009287 while (counter < length) {
9288 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009289 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009290 }
9291 counter++;
9292 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009293 ASSERT(!storage || storage->length() >= counter);
9294 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009295 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009296 case EXTERNAL_BYTE_ELEMENTS:
9297 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9298 case EXTERNAL_SHORT_ELEMENTS:
9299 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9300 case EXTERNAL_INT_ELEMENTS:
9301 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009302 case EXTERNAL_FLOAT_ELEMENTS:
9303 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00009304 int length = ExternalArray::cast(elements())->length();
9305 while (counter < length) {
9306 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009307 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +00009308 }
9309 counter++;
9310 }
9311 ASSERT(!storage || storage->length() >= counter);
9312 break;
9313 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009314 case DICTIONARY_ELEMENTS: {
9315 if (storage != NULL) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009316 element_dictionary()->CopyKeysTo(storage,
9317 filter,
9318 NumberDictionary::SORTED);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009319 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009320 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009321 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009322 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009323 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9324 FixedArray* parameter_map = FixedArray::cast(elements());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009325 int mapped_length = parameter_map->length() - 2;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009326 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9327 if (arguments->IsDictionary()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009328 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
9329 // will insert in storage starting at index 0.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009330 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009331 if (storage != NULL) {
9332 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
9333 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009334 counter += dictionary->NumberOfElementsFilterAttributes(filter);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009335 for (int i = 0; i < mapped_length; ++i) {
9336 if (!parameter_map->get(i + 2)->IsTheHole()) {
9337 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
whesse@chromium.org7b260152011-06-20 15:33:18 +00009338 ++counter;
9339 }
9340 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009341 if (storage != NULL) storage->SortPairs(storage, counter);
9342
9343 } else {
9344 int backing_length = arguments->length();
9345 int i = 0;
9346 for (; i < mapped_length; ++i) {
9347 if (!parameter_map->get(i + 2)->IsTheHole()) {
9348 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9349 ++counter;
9350 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
9351 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9352 ++counter;
9353 }
9354 }
9355 for (; i < backing_length; ++i) {
9356 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9357 ++counter;
9358 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00009359 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009360 break;
whesse@chromium.org7b260152011-06-20 15:33:18 +00009361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362 }
9363
9364 if (this->IsJSValue()) {
9365 Object* val = JSValue::cast(this)->value();
9366 if (val->IsString()) {
9367 String* str = String::cast(val);
9368 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009369 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009370 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371 }
9372 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009373 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009374 }
9375 }
9376 ASSERT(!storage || storage->length() == counter);
9377 return counter;
9378}
9379
9380
9381int JSObject::GetEnumElementKeys(FixedArray* storage) {
9382 return GetLocalElementKeys(storage,
9383 static_cast<PropertyAttributes>(DONT_ENUM));
9384}
9385
9386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009387// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009388class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009390 explicit StringKey(String* string) :
9391 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009392 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009393
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009394 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009395 // We know that all entries in a hash table had their hash keys created.
9396 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009397 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009398 return false;
9399 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009400 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009401 }
9402
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009403 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009404
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009405 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009406
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009407 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009408
9409 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009410 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411};
9412
ager@chromium.org381abbb2009-02-25 13:23:22 +00009413
9414// StringSharedKeys are used as keys in the eval cache.
9415class StringSharedKey : public HashTableKey {
9416 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009417 StringSharedKey(String* source,
9418 SharedFunctionInfo* shared,
9419 StrictModeFlag strict_mode)
9420 : source_(source),
9421 shared_(shared),
9422 strict_mode_(strict_mode) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009423
9424 bool IsMatch(Object* other) {
9425 if (!other->IsFixedArray()) return false;
9426 FixedArray* pair = FixedArray::cast(other);
9427 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9428 if (shared != shared_) return false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009429 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9430 Smi::cast(pair->get(2))->value());
9431 if (strict_mode != strict_mode_) return false;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009432 String* source = String::cast(pair->get(1));
9433 return source->Equals(source_);
9434 }
9435
ager@chromium.org381abbb2009-02-25 13:23:22 +00009436 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009437 SharedFunctionInfo* shared,
9438 StrictModeFlag strict_mode) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00009439 uint32_t hash = source->Hash();
9440 if (shared->HasSourceCode()) {
9441 // Instead of using the SharedFunctionInfo pointer in the hash
9442 // code computation, we use a combination of the hash of the
9443 // script source code and the start and end positions. We do
9444 // this to ensure that the cache entries can survive garbage
9445 // collection.
9446 Script* script = Script::cast(shared->script());
9447 hash ^= String::cast(script->source())->Hash();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009448 if (strict_mode == kStrictMode) hash ^= 0x8000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009449 hash += shared->start_position();
9450 }
9451 return hash;
9452 }
9453
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009454 uint32_t Hash() {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009455 return StringSharedHashHelper(source_, shared_, strict_mode_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009456 }
9457
9458 uint32_t HashForObject(Object* obj) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00009459 FixedArray* pair = FixedArray::cast(obj);
9460 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9461 String* source = String::cast(pair->get(1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009462 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9463 Smi::cast(pair->get(2))->value());
9464 return StringSharedHashHelper(source, shared, strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009465 }
9466
lrn@chromium.org303ada72010-10-27 09:33:13 +00009467 MUST_USE_RESULT MaybeObject* AsObject() {
9468 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009469 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009470 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9471 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009472 FixedArray* pair = FixedArray::cast(obj);
9473 pair->set(0, shared_);
9474 pair->set(1, source_);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009475 pair->set(2, Smi::FromInt(strict_mode_));
ager@chromium.org381abbb2009-02-25 13:23:22 +00009476 return pair;
9477 }
9478
ager@chromium.org381abbb2009-02-25 13:23:22 +00009479 private:
9480 String* source_;
9481 SharedFunctionInfo* shared_;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009482 StrictModeFlag strict_mode_;
ager@chromium.org381abbb2009-02-25 13:23:22 +00009483};
9484
9485
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009486// RegExpKey carries the source and flags of a regular expression as key.
9487class RegExpKey : public HashTableKey {
9488 public:
9489 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009490 : string_(string),
9491 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009492
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00009493 // Rather than storing the key in the hash table, a pointer to the
9494 // stored value is stored where the key should be. IsMatch then
9495 // compares the search key to the found object, rather than comparing
9496 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009497 bool IsMatch(Object* obj) {
9498 FixedArray* val = FixedArray::cast(obj);
9499 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9500 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9501 }
9502
9503 uint32_t Hash() { return RegExpHash(string_, flags_); }
9504
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009505 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009506 // Plain hash maps, which is where regexp keys are used, don't
9507 // use this function.
9508 UNREACHABLE();
9509 return NULL;
9510 }
9511
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009512 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009513 FixedArray* val = FixedArray::cast(obj);
9514 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9515 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9516 }
9517
9518 static uint32_t RegExpHash(String* string, Smi* flags) {
9519 return string->Hash() + flags->value();
9520 }
9521
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009522 String* string_;
9523 Smi* flags_;
9524};
9525
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009526// Utf8SymbolKey carries a vector of chars as key.
9527class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009528 public:
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009529 explicit Utf8SymbolKey(Vector<const char> string)
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009530 : string_(string), hash_field_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009531
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009532 bool IsMatch(Object* string) {
9533 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009534 }
9535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009536 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009537 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009538 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9539 static_cast<unsigned>(string_.length()));
9540 chars_ = buffer.Length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009541 hash_field_ = String::ComputeHashField(&buffer, chars_);
9542 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00009543 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9544 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009545 }
9546
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009547 uint32_t HashForObject(Object* other) {
9548 return String::cast(other)->Hash();
9549 }
9550
lrn@chromium.org303ada72010-10-27 09:33:13 +00009551 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009552 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009553 return Isolate::Current()->heap()->AllocateSymbol(
9554 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009555 }
9556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009557 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009558 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009559 int chars_; // Caches the number of characters when computing the hash code.
9560};
9561
9562
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009563template <typename Char>
9564class SequentialSymbolKey : public HashTableKey {
9565 public:
9566 explicit SequentialSymbolKey(Vector<const Char> string)
9567 : string_(string), hash_field_(0) { }
9568
9569 uint32_t Hash() {
9570 StringHasher hasher(string_.length());
9571
9572 // Very long strings have a trivial hash that doesn't inspect the
9573 // string contents.
9574 if (hasher.has_trivial_hash()) {
9575 hash_field_ = hasher.GetHashField();
9576 } else {
9577 int i = 0;
9578 // Do the iterative array index computation as long as there is a
9579 // chance this is an array index.
9580 while (i < string_.length() && hasher.is_array_index()) {
9581 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9582 i++;
9583 }
9584
9585 // Process the remaining characters without updating the array
9586 // index.
9587 while (i < string_.length()) {
9588 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9589 i++;
9590 }
9591 hash_field_ = hasher.GetHashField();
9592 }
9593
9594 uint32_t result = hash_field_ >> String::kHashShift;
9595 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9596 return result;
9597 }
9598
9599
9600 uint32_t HashForObject(Object* other) {
9601 return String::cast(other)->Hash();
9602 }
9603
9604 Vector<const Char> string_;
9605 uint32_t hash_field_;
9606};
9607
9608
9609
9610class AsciiSymbolKey : public SequentialSymbolKey<char> {
9611 public:
9612 explicit AsciiSymbolKey(Vector<const char> str)
9613 : SequentialSymbolKey<char>(str) { }
9614
9615 bool IsMatch(Object* string) {
9616 return String::cast(string)->IsAsciiEqualTo(string_);
9617 }
9618
9619 MaybeObject* AsObject() {
9620 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009622 }
9623};
9624
9625
danno@chromium.org40cb8782011-05-25 07:58:50 +00009626class SubStringAsciiSymbolKey : public HashTableKey {
9627 public:
9628 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9629 int from,
9630 int length)
9631 : string_(string), from_(from), length_(length) { }
9632
9633 uint32_t Hash() {
9634 ASSERT(length_ >= 0);
9635 ASSERT(from_ + length_ <= string_->length());
9636 StringHasher hasher(length_);
9637
9638 // Very long strings have a trivial hash that doesn't inspect the
9639 // string contents.
9640 if (hasher.has_trivial_hash()) {
9641 hash_field_ = hasher.GetHashField();
9642 } else {
9643 int i = 0;
9644 // Do the iterative array index computation as long as there is a
9645 // chance this is an array index.
9646 while (i < length_ && hasher.is_array_index()) {
9647 hasher.AddCharacter(static_cast<uc32>(
9648 string_->SeqAsciiStringGet(i + from_)));
9649 i++;
9650 }
9651
9652 // Process the remaining characters without updating the array
9653 // index.
9654 while (i < length_) {
9655 hasher.AddCharacterNoIndex(static_cast<uc32>(
9656 string_->SeqAsciiStringGet(i + from_)));
9657 i++;
9658 }
9659 hash_field_ = hasher.GetHashField();
9660 }
9661
9662 uint32_t result = hash_field_ >> String::kHashShift;
9663 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9664 return result;
9665 }
9666
9667
9668 uint32_t HashForObject(Object* other) {
9669 return String::cast(other)->Hash();
9670 }
9671
9672 bool IsMatch(Object* string) {
9673 Vector<const char> chars(string_->GetChars() + from_, length_);
9674 return String::cast(string)->IsAsciiEqualTo(chars);
9675 }
9676
9677 MaybeObject* AsObject() {
9678 if (hash_field_ == 0) Hash();
9679 Vector<const char> chars(string_->GetChars() + from_, length_);
9680 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
9681 }
9682
9683 private:
9684 Handle<SeqAsciiString> string_;
9685 int from_;
9686 int length_;
9687 uint32_t hash_field_;
9688};
9689
9690
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009691class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
9692 public:
9693 explicit TwoByteSymbolKey(Vector<const uc16> str)
9694 : SequentialSymbolKey<uc16>(str) { }
9695
9696 bool IsMatch(Object* string) {
9697 return String::cast(string)->IsTwoByteEqualTo(string_);
9698 }
9699
9700 MaybeObject* AsObject() {
9701 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009702 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009703 }
9704};
9705
9706
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009707// SymbolKey carries a string/symbol object as key.
9708class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009709 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009710 explicit SymbolKey(String* string)
9711 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009712
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009713 bool IsMatch(Object* string) {
9714 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009715 }
9716
9717 uint32_t Hash() { return string_->Hash(); }
9718
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009719 uint32_t HashForObject(Object* other) {
9720 return String::cast(other)->Hash();
9721 }
9722
lrn@chromium.org303ada72010-10-27 09:33:13 +00009723 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00009724 // Attempt to flatten the string, so that symbols will most often
9725 // be flat strings.
9726 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009727 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009729 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009730 if (map != NULL) {
9731 string_->set_map(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009732 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009733 return string_;
9734 }
9735 // Otherwise allocate a new symbol.
9736 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009737 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009738 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009739 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009740 }
9741
9742 static uint32_t StringHash(Object* obj) {
9743 return String::cast(obj)->Hash();
9744 }
9745
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009746 String* string_;
9747};
9748
9749
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009750template<typename Shape, typename Key>
9751void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009752 IteratePointers(v, 0, kElementsStartOffset);
9753}
9754
9755
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009756template<typename Shape, typename Key>
9757void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009758 IteratePointers(v,
9759 kElementsStartOffset,
9760 kHeaderSize + length() * kPointerSize);
9761}
9762
9763
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009764template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009765MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9766 PretenureFlag pretenure) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00009767 int capacity = ComputeCapacity(at_least_space_for);
9768 if (capacity > HashTable::kMaxCapacity) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009769 return Failure::OutOfMemoryException();
9770 }
9771
lrn@chromium.org303ada72010-10-27 09:33:13 +00009772 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9774 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009775 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009776 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009777 HashTable::cast(obj)->SetNumberOfElements(0);
9778 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9779 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780 return obj;
9781}
9782
9783
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009784// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +00009785int StringDictionary::FindEntry(String* key) {
9786 if (!key->IsSymbol()) {
9787 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9788 }
9789
9790 // Optimized for symbol key. Knowledge of the key type allows:
9791 // 1. Move the check if the key is a symbol out of the loop.
9792 // 2. Avoid comparing hash codes in symbol to symbol comparision.
9793 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9794 // In case of positive result the dictionary key may be replaced by
9795 // the symbol with minimal performance penalty. It gives a chance to
9796 // perform further lookups in code stubs (and significant performance boost
9797 // a certain style of code).
9798
9799 // EnsureCapacity will guarantee the hash table is never full.
9800 uint32_t capacity = Capacity();
9801 uint32_t entry = FirstProbe(key->Hash(), capacity);
9802 uint32_t count = 1;
9803
9804 while (true) {
9805 int index = EntryToIndex(entry);
9806 Object* element = get(index);
9807 if (element->IsUndefined()) break; // Empty entry.
9808 if (key == element) return entry;
9809 if (!element->IsSymbol() &&
9810 !element->IsNull() &&
9811 String::cast(element)->Equals(key)) {
9812 // Replace a non-symbol key by the equivalent symbol for faster further
9813 // lookups.
9814 set(index, key);
9815 return entry;
9816 }
9817 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9818 entry = NextProbe(entry, count++, capacity);
9819 }
9820 return kNotFound;
9821}
9822
9823
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009824template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +00009825MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
9826 ASSERT(NumberOfElements() < new_table->Capacity());
9827
9828 AssertNoAllocation no_gc;
9829 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
9830
9831 // Copy prefix to new array.
9832 for (int i = kPrefixStartIndex;
9833 i < kPrefixStartIndex + Shape::kPrefixSize;
9834 i++) {
9835 new_table->set(i, get(i), mode);
9836 }
9837
9838 // Rehash the elements.
9839 int capacity = Capacity();
9840 for (int i = 0; i < capacity; i++) {
9841 uint32_t from_index = EntryToIndex(i);
9842 Object* k = get(from_index);
9843 if (IsKey(k)) {
9844 uint32_t hash = Shape::HashForObject(key, k);
9845 uint32_t insertion_index =
9846 EntryToIndex(new_table->FindInsertionEntry(hash));
9847 for (int j = 0; j < Shape::kEntrySize; j++) {
9848 new_table->set(insertion_index + j, get(from_index + j), mode);
9849 }
9850 }
9851 }
9852 new_table->SetNumberOfElements(NumberOfElements());
9853 new_table->SetNumberOfDeletedElements(0);
9854 return new_table;
9855}
9856
9857
9858template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009859MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009860 int capacity = Capacity();
9861 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009862 int nod = NumberOfDeletedElements();
9863 // Return if:
9864 // 50% is still free after adding n elements and
9865 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009866 if (nod <= (capacity - nof) >> 1) {
9867 int needed_free = nof >> 1;
9868 if (nof + needed_free <= capacity) return this;
9869 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009870
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009871 const int kMinCapacityForPretenure = 256;
9872 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009873 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009874 Object* obj;
9875 { MaybeObject* maybe_obj =
9876 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9877 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9878 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009879
ager@chromium.org04921a82011-06-27 13:21:41 +00009880 return Rehash(HashTable::cast(obj), key);
9881}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009882
ager@chromium.org04921a82011-06-27 13:21:41 +00009883
9884template<typename Shape, typename Key>
9885MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
9886 int capacity = Capacity();
9887 int nof = NumberOfElements();
9888
9889 // Shrink to fit the number of elements if only a quarter of the
9890 // capacity is filled with elements.
9891 if (nof > (capacity >> 2)) return this;
9892 // Allocate a new dictionary with room for at least the current
9893 // number of elements. The allocation method will make sure that
9894 // there is extra room in the dictionary for additions. Don't go
9895 // lower than room for 16 elements.
9896 int at_least_room_for = nof;
9897 if (at_least_room_for < 16) return this;
9898
9899 const int kMinCapacityForPretenure = 256;
9900 bool pretenure =
9901 (at_least_room_for > kMinCapacityForPretenure) &&
9902 !GetHeap()->InNewSpace(this);
9903 Object* obj;
9904 { MaybeObject* maybe_obj =
9905 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
9906 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009907 }
ager@chromium.org04921a82011-06-27 13:21:41 +00009908
9909 return Rehash(HashTable::cast(obj), key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910}
9911
9912
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009913template<typename Shape, typename Key>
9914uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009916 uint32_t entry = FirstProbe(hash, capacity);
9917 uint32_t count = 1;
9918 // EnsureCapacity will guarantee the hash table is never full.
9919 while (true) {
9920 Object* element = KeyAt(entry);
9921 if (element->IsUndefined() || element->IsNull()) break;
9922 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009924 return entry;
9925}
9926
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009927// Force instantiation of template instances class.
9928// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009929
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009930template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009931
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009932template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009934template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009935
vegorov@chromium.org7943d462011-08-01 11:41:52 +00009936template class HashTable<ObjectHashTableShape, JSObject*>;
9937
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009938template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009939
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009940template class Dictionary<NumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009941
lrn@chromium.org303ada72010-10-27 09:33:13 +00009942template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009943 int);
9944
lrn@chromium.org303ada72010-10-27 09:33:13 +00009945template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009946 int);
9947
lrn@chromium.org303ada72010-10-27 09:33:13 +00009948template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009949 uint32_t, Object*);
9950
9951template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9952 Object*);
9953
9954template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9955 Object*);
9956
9957template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009958 FixedArray*,
9959 PropertyAttributes,
9960 Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009961
9962template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9963 int, JSObject::DeleteMode);
9964
9965template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
9966 int, JSObject::DeleteMode);
9967
ager@chromium.org04921a82011-06-27 13:21:41 +00009968template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
9969 String*);
9970
9971template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
9972 uint32_t);
9973
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009974template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009975 FixedArray*,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009976 int,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00009977 Dictionary<StringDictionaryShape, String*>::SortMode);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009978
9979template int
9980Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
9981 PropertyAttributes);
9982
lrn@chromium.org303ada72010-10-27 09:33:13 +00009983template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009984 String*, Object*, PropertyDetails);
9985
lrn@chromium.org303ada72010-10-27 09:33:13 +00009986template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009987Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
9988
9989template int
9990Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
9991 PropertyAttributes);
9992
lrn@chromium.org303ada72010-10-27 09:33:13 +00009993template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009994 uint32_t, Object*, PropertyDetails);
9995
lrn@chromium.org303ada72010-10-27 09:33:13 +00009996template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
9997 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009998
lrn@chromium.org303ada72010-10-27 09:33:13 +00009999template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10000 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010001
lrn@chromium.org303ada72010-10-27 09:33:13 +000010002template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010003 uint32_t, Object*, PropertyDetails, uint32_t);
10004
lrn@chromium.org303ada72010-10-27 09:33:13 +000010005template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010006 String*, Object*, PropertyDetails, uint32_t);
10007
10008template
10009int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
10010
10011template
10012int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010013
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010014template
10015int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
10016
10017
ager@chromium.org5ec48922009-05-05 07:25:34 +000010018// Collates undefined and unexisting elements below limit from position
10019// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010020MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010021 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010022 // Must stay in dictionary mode, either because of requires_slow_elements,
10023 // or because we are not going to sort (and therefore compact) all of the
10024 // elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010025 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010026 HeapNumber* result_double = NULL;
10027 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10028 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010029 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010030 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010031 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10032 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010033 result_double = HeapNumber::cast(new_double);
10034 }
10035
lrn@chromium.org303ada72010-10-27 09:33:13 +000010036 Object* obj;
10037 { MaybeObject* maybe_obj =
10038 NumberDictionary::Allocate(dict->NumberOfElements());
10039 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10040 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010041 NumberDictionary* new_dict = NumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010042
10043 AssertNoAllocation no_alloc;
10044
ager@chromium.org5ec48922009-05-05 07:25:34 +000010045 uint32_t pos = 0;
10046 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000010047 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010048 for (int i = 0; i < capacity; i++) {
10049 Object* k = dict->KeyAt(i);
10050 if (dict->IsKey(k)) {
10051 ASSERT(k->IsNumber());
10052 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10053 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10054 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10055 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010056 PropertyDetails details = dict->DetailsAt(i);
10057 if (details.type() == CALLBACKS) {
10058 // Bail out and do the sorting of undefineds and array holes in JS.
10059 return Smi::FromInt(-1);
10060 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010061 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010062 // In the following we assert that adding the entry to the new dictionary
10063 // does not cause GC. This is the case because we made sure to allocate
10064 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +000010065 if (key < limit) {
10066 if (value->IsUndefined()) {
10067 undefs++;
10068 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010069 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10070 // Adding an entry with the key beyond smi-range requires
10071 // allocation. Bailout.
10072 return Smi::FromInt(-1);
10073 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010074 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010075 pos++;
10076 }
10077 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010078 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10079 // Adding an entry with the key beyond smi-range requires
10080 // allocation. Bailout.
10081 return Smi::FromInt(-1);
10082 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010083 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010084 }
10085 }
10086 }
10087
10088 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010089 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010090 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010091 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010092 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10093 // Adding an entry with the key beyond smi-range requires
10094 // allocation. Bailout.
10095 return Smi::FromInt(-1);
10096 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010097 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +000010098 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010099 pos++;
10100 undefs--;
10101 }
10102
10103 set_elements(new_dict);
10104
10105 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10106 return Smi::FromInt(static_cast<int>(result));
10107 }
10108
10109 ASSERT_NE(NULL, result_double);
10110 result_double->set_value(static_cast<double>(result));
10111 return result_double;
10112}
10113
10114
10115// Collects all defined (non-hole) and non-undefined (array) elements at
10116// the start of the elements array.
10117// If the object is in dictionary mode, it is converted to fast elements
10118// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010119MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010120 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010122 Heap* heap = GetHeap();
10123
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010124 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010125 // Convert to fast elements containing only the existing properties.
10126 // Ordering is irrelevant, since we are going to sort anyway.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010127 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +000010128 if (IsJSArray() || dict->requires_slow_elements() ||
10129 dict->max_number_key() >= limit) {
10130 return PrepareSlowElementsForSort(limit);
10131 }
10132 // Convert to fast elements.
10133
lrn@chromium.org303ada72010-10-27 09:33:13 +000010134 Object* obj;
10135 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
10136 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10137 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010138 Map* new_map = Map::cast(obj);
10139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010140 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010141 Object* new_array;
10142 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010144 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
10145 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010146 FixedArray* fast_elements = FixedArray::cast(new_array);
10147 dict->CopyValuesTo(fast_elements);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010148
10149 set_map(new_map);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010150 set_elements(fast_elements);
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010151 } else if (!HasFastDoubleElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010152 Object* obj;
10153 { MaybeObject* maybe_obj = EnsureWritableFastElements();
10154 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10155 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010156 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010157 ASSERT(HasFastElements() || HasFastDoubleElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010158
10159 // Collect holes at the end, undefined before that and the rest at the
10160 // start, and return the number of non-hole, non-undefined values.
10161
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010162 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
10163 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010164 if (limit > elements_length) {
10165 limit = elements_length ;
10166 }
10167 if (limit == 0) {
10168 return Smi::FromInt(0);
10169 }
10170
10171 HeapNumber* result_double = NULL;
10172 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10173 // Pessimistically allocate space for return value before
10174 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010175 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010176 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010177 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10178 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010179 result_double = HeapNumber::cast(new_double);
10180 }
10181
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010182 uint32_t result = 0;
10183 if (elements_base->map() == heap->fixed_double_array_map()) {
10184 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
10185 // Split elements into defined and the_hole, in that order.
10186 unsigned int holes = limit;
10187 // Assume most arrays contain no holes and undefined values, so minimize the
10188 // number of stores of non-undefined, non-the-hole values.
10189 for (unsigned int i = 0; i < holes; i++) {
10190 if (elements->is_the_hole(i)) {
10191 holes--;
10192 } else {
10193 continue;
10194 }
10195 // Position i needs to be filled.
10196 while (holes > i) {
10197 if (elements->is_the_hole(holes)) {
10198 holes--;
10199 } else {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010200 elements->set(i, elements->get_scalar(holes));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010201 break;
10202 }
10203 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010204 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010205 result = holes;
10206 while (holes < limit) {
10207 elements->set_the_hole(holes);
10208 holes++;
10209 }
10210 } else {
10211 FixedArray* elements = FixedArray::cast(elements_base);
10212 AssertNoAllocation no_alloc;
10213
10214 // Split elements into defined, undefined and the_hole, in that order. Only
10215 // count locations for undefined and the hole, and fill them afterwards.
10216 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
10217 unsigned int undefs = limit;
10218 unsigned int holes = limit;
10219 // Assume most arrays contain no holes and undefined values, so minimize the
10220 // number of stores of non-undefined, non-the-hole values.
10221 for (unsigned int i = 0; i < undefs; i++) {
10222 Object* current = elements->get(i);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010223 if (current->IsTheHole()) {
10224 holes--;
10225 undefs--;
10226 } else if (current->IsUndefined()) {
10227 undefs--;
10228 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010229 continue;
10230 }
10231 // Position i needs to be filled.
10232 while (undefs > i) {
10233 current = elements->get(undefs);
10234 if (current->IsTheHole()) {
10235 holes--;
10236 undefs--;
10237 } else if (current->IsUndefined()) {
10238 undefs--;
10239 } else {
10240 elements->set(i, current, write_barrier);
10241 break;
10242 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010243 }
10244 }
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010245 result = undefs;
10246 while (undefs < holes) {
10247 elements->set_undefined(undefs);
10248 undefs++;
10249 }
10250 while (holes < limit) {
10251 elements->set_the_hole(holes);
10252 holes++;
10253 }
ager@chromium.org5ec48922009-05-05 07:25:34 +000010254 }
10255
10256 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10257 return Smi::FromInt(static_cast<int>(result));
10258 }
10259 ASSERT_NE(NULL, result_double);
10260 result_double->set_value(static_cast<double>(result));
10261 return result_double;
10262}
10263
10264
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010265Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010266 uint8_t clamped_value = 0;
10267 if (index < static_cast<uint32_t>(length())) {
10268 if (value->IsSmi()) {
10269 int int_value = Smi::cast(value)->value();
10270 if (int_value < 0) {
10271 clamped_value = 0;
10272 } else if (int_value > 255) {
10273 clamped_value = 255;
10274 } else {
10275 clamped_value = static_cast<uint8_t>(int_value);
10276 }
10277 } else if (value->IsHeapNumber()) {
10278 double double_value = HeapNumber::cast(value)->value();
10279 if (!(double_value > 0)) {
10280 // NaN and less than zero clamp to zero.
10281 clamped_value = 0;
10282 } else if (double_value > 255) {
10283 // Greater than 255 clamp to 255.
10284 clamped_value = 255;
10285 } else {
10286 // Other doubles are rounded to the nearest integer.
10287 clamped_value = static_cast<uint8_t>(double_value + 0.5);
10288 }
10289 } else {
10290 // Clamp undefined to zero (default). All other types have been
10291 // converted to a number type further up in the call chain.
10292 ASSERT(value->IsUndefined());
10293 }
10294 set(index, clamped_value);
10295 }
10296 return Smi::FromInt(clamped_value);
10297}
10298
10299
ager@chromium.org3811b432009-10-28 14:53:37 +000010300template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010301static MaybeObject* ExternalArrayIntSetter(Heap* heap,
10302 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010303 uint32_t index,
10304 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010305 ValueType cast_value = 0;
10306 if (index < static_cast<uint32_t>(receiver->length())) {
10307 if (value->IsSmi()) {
10308 int int_value = Smi::cast(value)->value();
10309 cast_value = static_cast<ValueType>(int_value);
10310 } else if (value->IsHeapNumber()) {
10311 double double_value = HeapNumber::cast(value)->value();
10312 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10313 } else {
10314 // Clamp undefined to zero (default). All other types have been
10315 // converted to a number type further up in the call chain.
10316 ASSERT(value->IsUndefined());
10317 }
10318 receiver->set(index, cast_value);
10319 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010320 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010321}
10322
10323
lrn@chromium.org303ada72010-10-27 09:33:13 +000010324MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010325 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010327}
10328
10329
lrn@chromium.org303ada72010-10-27 09:33:13 +000010330MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10331 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010332 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010334}
10335
10336
lrn@chromium.org303ada72010-10-27 09:33:13 +000010337MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10338 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010339 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010340 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010341}
10342
10343
lrn@chromium.org303ada72010-10-27 09:33:13 +000010344MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10345 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010346 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010347 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010348}
10349
10350
lrn@chromium.org303ada72010-10-27 09:33:13 +000010351MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010352 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010353 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010354}
10355
10356
lrn@chromium.org303ada72010-10-27 09:33:13 +000010357MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010358 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010359 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010360 if (index < static_cast<uint32_t>(length())) {
10361 if (value->IsSmi()) {
10362 int int_value = Smi::cast(value)->value();
10363 cast_value = static_cast<uint32_t>(int_value);
10364 } else if (value->IsHeapNumber()) {
10365 double double_value = HeapNumber::cast(value)->value();
10366 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10367 } else {
10368 // Clamp undefined to zero (default). All other types have been
10369 // converted to a number type further up in the call chain.
10370 ASSERT(value->IsUndefined());
10371 }
10372 set(index, cast_value);
10373 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010374 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010375}
10376
10377
lrn@chromium.org303ada72010-10-27 09:33:13 +000010378MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +000010379 float cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010380 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +000010381 if (index < static_cast<uint32_t>(length())) {
10382 if (value->IsSmi()) {
10383 int int_value = Smi::cast(value)->value();
10384 cast_value = static_cast<float>(int_value);
10385 } else if (value->IsHeapNumber()) {
10386 double double_value = HeapNumber::cast(value)->value();
10387 cast_value = static_cast<float>(double_value);
10388 } else {
10389 // Clamp undefined to zero (default). All other types have been
10390 // converted to a number type further up in the call chain.
10391 ASSERT(value->IsUndefined());
10392 }
10393 set(index, cast_value);
10394 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010395 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +000010396}
10397
10398
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010399MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
10400 double double_value = 0;
10401 Heap* heap = GetHeap();
10402 if (index < static_cast<uint32_t>(length())) {
10403 if (value->IsSmi()) {
10404 int int_value = Smi::cast(value)->value();
10405 double_value = static_cast<double>(int_value);
10406 } else if (value->IsHeapNumber()) {
10407 double_value = HeapNumber::cast(value)->value();
10408 } else {
10409 // Clamp undefined to zero (default). All other types have been
10410 // converted to a number type further up in the call chain.
10411 ASSERT(value->IsUndefined());
10412 }
10413 set(index, double_value);
10414 }
10415 return heap->AllocateHeapNumber(double_value);
10416}
10417
10418
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010419JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010420 ASSERT(!HasFastProperties());
10421 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010422 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010423}
10424
10425
lrn@chromium.org303ada72010-10-27 09:33:13 +000010426MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010427 ASSERT(!HasFastProperties());
10428 int entry = property_dictionary()->FindEntry(name);
10429 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010430 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010431 Object* cell;
10432 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010433 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010434 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10435 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010436 PropertyDetails details(NONE, NORMAL);
10437 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010438 Object* dictionary;
10439 { MaybeObject* maybe_dictionary =
10440 property_dictionary()->Add(name, cell, details);
10441 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10442 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010443 set_properties(StringDictionary::cast(dictionary));
10444 return cell;
10445 } else {
10446 Object* value = property_dictionary()->ValueAt(entry);
10447 ASSERT(value->IsJSGlobalPropertyCell());
10448 return value;
10449 }
10450}
10451
10452
lrn@chromium.org303ada72010-10-27 09:33:13 +000010453MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010454 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 return LookupKey(&key, s);
10456}
10457
10458
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010459// This class is used for looking up two character strings in the symbol table.
10460// If we don't have a hit we don't want to waste much time so we unroll the
10461// string hash calculation loop here for speed. Doesn't work if the two
10462// characters form a decimal integer, since such strings have a different hash
10463// algorithm.
10464class TwoCharHashTableKey : public HashTableKey {
10465 public:
10466 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
10467 : c1_(c1), c2_(c2) {
10468 // Char 1.
10469 uint32_t hash = c1 + (c1 << 10);
10470 hash ^= hash >> 6;
10471 // Char 2.
10472 hash += c2;
10473 hash += hash << 10;
10474 hash ^= hash >> 6;
10475 // GetHash.
10476 hash += hash << 3;
10477 hash ^= hash >> 11;
10478 hash += hash << 15;
10479 if (hash == 0) hash = 27;
10480#ifdef DEBUG
10481 StringHasher hasher(2);
10482 hasher.AddCharacter(c1);
10483 hasher.AddCharacter(c2);
10484 // If this assert fails then we failed to reproduce the two-character
10485 // version of the string hashing algorithm above. One reason could be
10486 // that we were passed two digits as characters, since the hash
10487 // algorithm is different in that case.
10488 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10489#endif
10490 hash_ = hash;
10491 }
10492
10493 bool IsMatch(Object* o) {
10494 if (!o->IsString()) return false;
10495 String* other = String::cast(o);
10496 if (other->length() != 2) return false;
10497 if (other->Get(0) != c1_) return false;
10498 return other->Get(1) == c2_;
10499 }
10500
10501 uint32_t Hash() { return hash_; }
10502 uint32_t HashForObject(Object* key) {
10503 if (!key->IsString()) return 0;
10504 return String::cast(key)->Hash();
10505 }
10506
10507 Object* AsObject() {
10508 // The TwoCharHashTableKey is only used for looking in the symbol
10509 // table, not for adding to it.
10510 UNREACHABLE();
10511 return NULL;
10512 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +000010513
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010514 private:
10515 uint32_t c1_;
10516 uint32_t c2_;
10517 uint32_t hash_;
10518};
10519
10520
ager@chromium.org7c537e22008-10-16 08:43:32 +000010521bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10522 SymbolKey key(string);
10523 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010524 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000010525 return false;
10526 } else {
10527 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +000010528 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +000010529 *symbol = result;
10530 return true;
10531 }
10532}
10533
10534
ager@chromium.org6141cbe2009-11-20 12:14:52 +000010535bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10536 uint32_t c2,
10537 String** symbol) {
10538 TwoCharHashTableKey key(c1, c2);
10539 int entry = FindEntry(&key);
10540 if (entry == kNotFound) {
10541 return false;
10542 } else {
10543 String* result = String::cast(KeyAt(entry));
10544 ASSERT(StringShape(result).IsSymbol());
10545 *symbol = result;
10546 return true;
10547 }
10548}
10549
10550
lrn@chromium.org303ada72010-10-27 09:33:13 +000010551MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010552 Utf8SymbolKey key(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010553 return LookupKey(&key, s);
10554}
10555
10556
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010557MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10558 Object** s) {
10559 AsciiSymbolKey key(str);
10560 return LookupKey(&key, s);
10561}
10562
10563
danno@chromium.org40cb8782011-05-25 07:58:50 +000010564MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10565 int from,
10566 int length,
10567 Object** s) {
10568 SubStringAsciiSymbolKey key(str, from, length);
10569 return LookupKey(&key, s);
10570}
10571
10572
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +000010573MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10574 Object** s) {
10575 TwoByteSymbolKey key(str);
10576 return LookupKey(&key, s);
10577}
10578
lrn@chromium.org303ada72010-10-27 09:33:13 +000010579MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010580 int entry = FindEntry(key);
10581
10582 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010583 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010584 *s = KeyAt(entry);
10585 return this;
10586 }
10587
10588 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010589 Object* obj;
10590 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10591 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10592 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593
10594 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010595 Object* symbol;
10596 { MaybeObject* maybe_symbol = key->AsObject();
10597 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010599
10600 // If the symbol table grew as part of EnsureCapacity, obj is not
10601 // the current symbol table and therefore we cannot use
10602 // SymbolTable::cast here.
10603 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10604
10605 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010606 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607 table->set(EntryToIndex(entry), symbol);
10608 table->ElementAdded();
10609 *s = symbol;
10610 return table;
10611}
10612
10613
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010614Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010615 StringKey key(src);
10616 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010617 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010618 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010619}
10620
10621
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010622Object* CompilationCacheTable::LookupEval(String* src,
10623 Context* context,
10624 StrictModeFlag strict_mode) {
10625 StringSharedKey key(src, context->closure()->shared(), strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +000010626 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +000010628 return get(EntryToIndex(entry) + 1);
10629}
10630
10631
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010632Object* CompilationCacheTable::LookupRegExp(String* src,
10633 JSRegExp::Flags flags) {
10634 RegExpKey key(src, flags);
10635 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010636 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010637 return get(EntryToIndex(entry) + 1);
10638}
10639
10640
lrn@chromium.org303ada72010-10-27 09:33:13 +000010641MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010642 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010643 Object* obj;
10644 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10645 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10646 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010647
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000010648 CompilationCacheTable* cache =
10649 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010650 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +000010651 cache->set(EntryToIndex(entry), src);
10652 cache->set(EntryToIndex(entry) + 1, value);
10653 cache->ElementAdded();
10654 return cache;
10655}
10656
10657
lrn@chromium.org303ada72010-10-27 09:33:13 +000010658MaybeObject* CompilationCacheTable::PutEval(String* src,
10659 Context* context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000010660 SharedFunctionInfo* value) {
10661 StringSharedKey key(src,
10662 context->closure()->shared(),
10663 value->strict_mode() ? kStrictMode : kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010664 Object* obj;
10665 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10666 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10667 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010668
10669 CompilationCacheTable* cache =
10670 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010671 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +000010672
lrn@chromium.org303ada72010-10-27 09:33:13 +000010673 Object* k;
10674 { MaybeObject* maybe_k = key.AsObject();
10675 if (!maybe_k->ToObject(&k)) return maybe_k;
10676 }
ager@chromium.org381abbb2009-02-25 13:23:22 +000010677
10678 cache->set(EntryToIndex(entry), k);
10679 cache->set(EntryToIndex(entry) + 1, value);
10680 cache->ElementAdded();
10681 return cache;
10682}
10683
10684
lrn@chromium.org303ada72010-10-27 09:33:13 +000010685MaybeObject* CompilationCacheTable::PutRegExp(String* src,
10686 JSRegExp::Flags flags,
10687 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010688 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010689 Object* obj;
10690 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10691 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10692 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010693
10694 CompilationCacheTable* cache =
10695 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010696 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000010697 // We store the value in the key slot, and compare the search key
10698 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000010699 cache->set(EntryToIndex(entry), value);
10700 cache->set(EntryToIndex(entry) + 1, value);
10701 cache->ElementAdded();
10702 return cache;
10703}
10704
10705
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010706void CompilationCacheTable::Remove(Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010707 Object* null_value = GetHeap()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010708 for (int entry = 0, size = Capacity(); entry < size; entry++) {
10709 int entry_index = EntryToIndex(entry);
10710 int value_index = entry_index + 1;
10711 if (get(value_index) == value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712 fast_set(this, entry_index, null_value);
10713 fast_set(this, value_index, null_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010714 ElementRemoved();
10715 }
10716 }
10717 return;
10718}
10719
10720
ager@chromium.org236ad962008-09-25 09:45:57 +000010721// SymbolsKey used for HashTable where key is array of symbols.
10722class SymbolsKey : public HashTableKey {
10723 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010724 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +000010725
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010726 bool IsMatch(Object* symbols) {
10727 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +000010728 int len = symbols_->length();
10729 if (o->length() != len) return false;
10730 for (int i = 0; i < len; i++) {
10731 if (o->get(i) != symbols_->get(i)) return false;
10732 }
10733 return true;
10734 }
10735
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010736 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +000010737
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010738 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010739 FixedArray* symbols = FixedArray::cast(obj);
10740 int len = symbols->length();
10741 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +000010742 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010743 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +000010744 }
10745 return hash;
10746 }
10747
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010748 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +000010749
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010750 private:
ager@chromium.org236ad962008-09-25 09:45:57 +000010751 FixedArray* symbols_;
10752};
10753
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010754
ager@chromium.org236ad962008-09-25 09:45:57 +000010755Object* MapCache::Lookup(FixedArray* array) {
10756 SymbolsKey key(array);
10757 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010758 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010759 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +000010760}
10761
10762
lrn@chromium.org303ada72010-10-27 09:33:13 +000010763MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +000010764 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010765 Object* obj;
10766 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10767 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10768 }
ager@chromium.org236ad962008-09-25 09:45:57 +000010769
10770 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010771 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +000010772 cache->set(EntryToIndex(entry), array);
10773 cache->set(EntryToIndex(entry) + 1, value);
10774 cache->ElementAdded();
10775 return cache;
10776}
10777
10778
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010779template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010780MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
10781 Object* obj;
10782 { MaybeObject* maybe_obj =
10783 HashTable<Shape, Key>::Allocate(at_least_space_for);
10784 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010785 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010786 // Initialize the next enumeration index.
10787 Dictionary<Shape, Key>::cast(obj)->
10788 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789 return obj;
10790}
10791
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010792
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010793template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010794MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010795 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010796 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010797
10798 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010799 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010800 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010801 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10802 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010803 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010804 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010805 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010806 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807
10808 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010809 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010810 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812 FixedArray* enumeration_order = FixedArray::cast(obj);
10813
10814 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010815 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010816 int pos = 0;
10817 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010818 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010819 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010820 }
10821 }
10822
10823 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010824 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010825
10826 // Overwrite the enumeration_order with the enumeration indices.
10827 for (int i = 0; i < length; i++) {
10828 int index = Smi::cast(iteration_order->get(i))->value();
10829 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010830 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010831 }
10832
10833 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010834 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010835 pos = 0;
10836 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010837 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010838 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10839 PropertyDetails details = DetailsAt(i);
10840 PropertyDetails new_details =
10841 PropertyDetails(details.attributes(), details.type(), enum_index);
10842 DetailsAtPut(i, new_details);
10843 }
10844 }
10845
10846 // Set the next enumeration index.
10847 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10848 return this;
10849}
10850
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010851template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010852MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010853 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010854 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010855 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10856 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010857 Object* result;
10858 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10859 if (!maybe_result->ToObject(&result)) return maybe_result;
10860 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010862 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863}
10864
10865
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010866void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867 // Do nothing if the interval [from, to) is empty.
10868 if (from >= to) return;
10869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010870 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010871 int removed_entries = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010872 Object* sentinel = heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 int capacity = Capacity();
10874 for (int i = 0; i < capacity; i++) {
10875 Object* key = KeyAt(i);
10876 if (key->IsNumber()) {
10877 uint32_t number = static_cast<uint32_t>(key->Number());
10878 if (from <= number && number < to) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010879 SetEntry(i, sentinel, sentinel);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880 removed_entries++;
10881 }
10882 }
10883 }
10884
10885 // Update the number of elements.
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000010886 ElementsRemoved(removed_entries);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010887}
10888
10889
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010890template<typename Shape, typename Key>
10891Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010892 JSReceiver::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010893 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010894 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010895 // Ignore attributes if forcing a deletion.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010896 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010897 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000010898 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010899 SetEntry(entry, heap->null_value(), heap->null_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010900 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010901 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010902}
10903
10904
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010905template<typename Shape, typename Key>
ager@chromium.org04921a82011-06-27 13:21:41 +000010906MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
10907 return HashTable<Shape, Key>::Shrink(key);
10908}
10909
10910
10911template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010912MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010913 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010914
10915 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010916 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917 ValueAtPut(entry, value);
10918 return this;
10919 }
10920
10921 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010922 Object* obj;
10923 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10924 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10925 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010926
lrn@chromium.org303ada72010-10-27 09:33:13 +000010927 Object* k;
10928 { MaybeObject* maybe_k = Shape::AsObject(key);
10929 if (!maybe_k->ToObject(&k)) return maybe_k;
10930 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010931 PropertyDetails details = PropertyDetails(NONE, NORMAL);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010932 return Dictionary<Shape, Key>::cast(obj)->
10933 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934}
10935
10936
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010937template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010938MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10939 Object* value,
10940 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010941 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010942 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010943 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010944 Object* obj;
10945 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10946 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10947 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010948 return Dictionary<Shape, Key>::cast(obj)->
10949 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950}
10951
10952
10953// Add a key, value pair to the dictionary.
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>::AddEntry(Key key,
10956 Object* value,
10957 PropertyDetails details,
10958 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010959 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010960 Object* k;
10961 { MaybeObject* maybe_k = Shape::AsObject(key);
10962 if (!maybe_k->ToObject(&k)) return maybe_k;
10963 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010964
10965 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010966 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010967 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010968 // Assign an enumeration index to the property and update
10969 // SetNextEnumerationIndex.
10970 int index = NextEnumerationIndex();
10971 details = PropertyDetails(details.attributes(), details.type(), index);
10972 SetNextEnumerationIndex(index + 1);
10973 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010974 SetEntry(entry, k, value, details);
10975 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
10976 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
10977 HashTable<Shape, Key>::ElementAdded();
10978 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979}
10980
10981
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010982void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010983 // If the dictionary requires slow elements an element has already
10984 // been added at a high index.
10985 if (requires_slow_elements()) return;
10986 // Check if this index is high enough that we should require slow
10987 // elements.
10988 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010989 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010990 return;
10991 }
10992 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010993 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010995 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010996 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997 }
10998}
10999
11000
lrn@chromium.org303ada72010-10-27 09:33:13 +000011001MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
11002 Object* value,
11003 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011004 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011005 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011006 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007}
11008
11009
lrn@chromium.org303ada72010-10-27 09:33:13 +000011010MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011011 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011012 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011013}
11014
11015
lrn@chromium.org303ada72010-10-27 09:33:13 +000011016MaybeObject* NumberDictionary::Set(uint32_t key,
11017 Object* value,
11018 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011019 int entry = FindEntry(key);
11020 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011021 // Preserve enumeration index.
11022 details = PropertyDetails(details.attributes(),
11023 details.type(),
11024 DetailsAt(entry).index());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011025 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
11026 Object* object_key;
11027 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000011028 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029 return this;
11030}
11031
11032
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011033
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011034template<typename Shape, typename Key>
11035int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11036 PropertyAttributes filter) {
11037 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011038 int result = 0;
11039 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011040 Object* k = HashTable<Shape, Key>::KeyAt(i);
11041 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011042 PropertyDetails details = DetailsAt(i);
11043 if (details.IsDeleted()) continue;
11044 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045 if ((attr & filter) == 0) result++;
11046 }
11047 }
11048 return result;
11049}
11050
11051
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011052template<typename Shape, typename Key>
11053int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011054 return NumberOfElementsFilterAttributes(
11055 static_cast<PropertyAttributes>(DONT_ENUM));
11056}
11057
11058
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011059template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011060void Dictionary<Shape, Key>::CopyKeysTo(
11061 FixedArray* storage,
11062 PropertyAttributes filter,
11063 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011064 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011065 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011066 int index = 0;
11067 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011068 Object* k = HashTable<Shape, Key>::KeyAt(i);
11069 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011070 PropertyDetails details = DetailsAt(i);
11071 if (details.IsDeleted()) continue;
11072 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011073 if ((attr & filter) == 0) storage->set(index++, k);
11074 }
11075 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011076 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11077 storage->SortPairs(storage, index);
11078 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079 ASSERT(storage->length() >= index);
11080}
11081
11082
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011083void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11084 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011085 ASSERT(storage->length() >= NumberOfEnumElements());
11086 int capacity = Capacity();
11087 int index = 0;
11088 for (int i = 0; i < capacity; i++) {
11089 Object* k = KeyAt(i);
11090 if (IsKey(k)) {
11091 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011092 if (details.IsDeleted() || details.IsDontEnum()) continue;
11093 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011094 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011095 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011096 }
11097 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011098 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011099 ASSERT(storage->length() >= index);
11100}
11101
11102
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011103template<typename Shape, typename Key>
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011104void Dictionary<Shape, Key>::CopyKeysTo(
11105 FixedArray* storage,
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011106 int index,
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011107 typename Dictionary<Shape, Key>::SortMode sort_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011108 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11109 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011110 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011111 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011112 Object* k = HashTable<Shape, Key>::KeyAt(i);
11113 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011114 PropertyDetails details = DetailsAt(i);
11115 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011116 storage->set(index++, k);
11117 }
11118 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011119 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11120 storage->SortPairs(storage, index);
11121 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011122 ASSERT(storage->length() >= index);
11123}
11124
11125
11126// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011127template<typename Shape, typename Key>
11128Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11129 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011130 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011131 Object* k = HashTable<Shape, Key>::KeyAt(i);
11132 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000011133 Object* e = ValueAt(i);
11134 if (e->IsJSGlobalPropertyCell()) {
11135 e = JSGlobalPropertyCell::cast(e)->value();
11136 }
11137 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 }
11139 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011140 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011141 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011142}
11143
11144
lrn@chromium.org303ada72010-10-27 09:33:13 +000011145MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011146 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147 // Make sure we preserve dictionary representation if there are too many
11148 // descriptors.
11149 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
11150
11151 // Figure out if it is necessary to generate new enumeration indices.
11152 int max_enumeration_index =
11153 NextEnumerationIndex() +
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011154 (DescriptorArray::kMaxNumberOfDescriptors -
11155 NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011156 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000011157 Object* result;
11158 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11159 if (!maybe_result->ToObject(&result)) return maybe_result;
11160 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011161 }
11162
11163 int instance_descriptor_length = 0;
11164 int number_of_fields = 0;
11165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011166 Heap* heap = GetHeap();
11167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168 // Compute the length of the instance descriptor.
11169 int capacity = Capacity();
11170 for (int i = 0; i < capacity; i++) {
11171 Object* k = KeyAt(i);
11172 if (IsKey(k)) {
11173 Object* value = ValueAt(i);
11174 PropertyType type = DetailsAt(i).type();
11175 ASSERT(type != FIELD);
11176 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000011177 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011178 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000011179 number_of_fields += 1;
11180 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181 }
11182 }
11183
11184 // Allocate the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011185 Object* descriptors_unchecked;
11186 { MaybeObject* maybe_descriptors_unchecked =
11187 DescriptorArray::Allocate(instance_descriptor_length);
11188 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
11189 return maybe_descriptors_unchecked;
11190 }
11191 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011192 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193
ager@chromium.org32912102009-01-16 10:38:43 +000011194 int inobject_props = obj->map()->inobject_properties();
11195 int number_of_allocated_fields =
11196 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000011197 if (number_of_allocated_fields < 0) {
11198 // There is enough inobject space for all fields (including unused).
11199 number_of_allocated_fields = 0;
11200 unused_property_fields = inobject_props - number_of_fields;
11201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011202
11203 // Allocate the fixed array for the fields.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011204 Object* fields;
11205 { MaybeObject* maybe_fields =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011206 heap->AllocateFixedArray(number_of_allocated_fields);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011207 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
11208 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011209
11210 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011211 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011212 int current_offset = 0;
11213 for (int i = 0; i < capacity; i++) {
11214 Object* k = KeyAt(i);
11215 if (IsKey(k)) {
11216 Object* value = ValueAt(i);
11217 // Ensure the key is a symbol before writing into the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011218 Object* key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011220 if (!maybe_key->ToObject(&key)) return maybe_key;
11221 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011222 PropertyDetails details = DetailsAt(i);
11223 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000011224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011225 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011226 ConstantFunctionDescriptor d(String::cast(key),
11227 JSFunction::cast(value),
11228 details.attributes(),
11229 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011230 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011231 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000011232 if (current_offset < inobject_props) {
11233 obj->InObjectPropertyAtPut(current_offset,
11234 value,
11235 UPDATE_WRITE_BARRIER);
11236 } else {
11237 int offset = current_offset - inobject_props;
11238 FixedArray::cast(fields)->set(offset, value);
11239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011240 FieldDescriptor d(String::cast(key),
11241 current_offset++,
11242 details.attributes(),
11243 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011244 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011245 } else if (type == CALLBACKS) {
11246 CallbacksDescriptor d(String::cast(key),
11247 value,
11248 details.attributes(),
11249 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000011250 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 } else {
11252 UNREACHABLE();
11253 }
11254 }
11255 }
11256 ASSERT(current_offset == number_of_fields);
11257
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011258 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011259 // Allocate new map.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011260 Object* new_map;
11261 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
11262 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
11263 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011264
11265 // Transform the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011266 obj->set_map(Map::cast(new_map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011267 obj->map()->set_instance_descriptors(descriptors);
11268 obj->map()->set_unused_property_fields(unused_property_fields);
11269
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011270 obj->set_properties(FixedArray::cast(fields));
11271 ASSERT(obj->IsJSObject());
11272
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000011273 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
ager@chromium.org32912102009-01-16 10:38:43 +000011274 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011275 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000011276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277 return obj;
11278}
11279
11280
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011281Object* ObjectHashTable::Lookup(JSObject* key) {
11282 // If the object does not have an identity hash, it was never used as a key.
11283 MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
11284 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
11285 int entry = FindEntry(key);
11286 if (entry == kNotFound) return GetHeap()->undefined_value();
11287 return get(EntryToIndex(entry) + 1);
11288}
11289
11290
11291MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
11292 // Make sure the key object has an identity hash code.
11293 int hash;
11294 { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
11295 if (maybe_hash->IsFailure()) return maybe_hash;
11296 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
11297 }
11298 int entry = FindEntry(key);
11299
11300 // Check whether to perform removal operation.
11301 if (value->IsUndefined()) {
11302 if (entry == kNotFound) return this;
11303 RemoveEntry(entry);
11304 return Shrink(key);
11305 }
11306
11307 // Key is already in table, just overwrite value.
11308 if (entry != kNotFound) {
11309 set(EntryToIndex(entry) + 1, value);
11310 return this;
11311 }
11312
11313 // Check whether the hash table should be extended.
11314 Object* obj;
11315 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11316 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11317 }
11318 ObjectHashTable* table = ObjectHashTable::cast(obj);
11319 table->AddEntry(table->FindInsertionEntry(hash), key, value);
11320 return table;
11321}
11322
11323
11324void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
11325 set(EntryToIndex(entry), key);
11326 set(EntryToIndex(entry) + 1, value);
11327 ElementAdded();
11328}
11329
11330
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011331void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
11332 set_null(heap, EntryToIndex(entry));
11333 set_null(heap, EntryToIndex(entry) + 1);
vegorov@chromium.org7943d462011-08-01 11:41:52 +000011334 ElementRemoved();
11335}
11336
11337
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011338#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011339// Check if there is a break point at this code position.
11340bool DebugInfo::HasBreakPoint(int code_position) {
11341 // Get the break point info object for this code position.
11342 Object* break_point_info = GetBreakPointInfo(code_position);
11343
11344 // If there is no break point info object or no break points in the break
11345 // point info object there is no break point at this code position.
11346 if (break_point_info->IsUndefined()) return false;
11347 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
11348}
11349
11350
11351// Get the break point info object for this code position.
11352Object* DebugInfo::GetBreakPointInfo(int code_position) {
11353 // Find the index of the break point info object for this code position.
11354 int index = GetBreakPointInfoIndex(code_position);
11355
11356 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011357 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011358 return BreakPointInfo::cast(break_points()->get(index));
11359}
11360
11361
11362// Clear a break point at the specified code position.
11363void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
11364 int code_position,
11365 Handle<Object> break_point_object) {
11366 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11367 if (break_point_info->IsUndefined()) return;
11368 BreakPointInfo::ClearBreakPoint(
11369 Handle<BreakPointInfo>::cast(break_point_info),
11370 break_point_object);
11371}
11372
11373
11374void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
11375 int code_position,
11376 int source_position,
11377 int statement_position,
11378 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011379 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011380 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11381 if (!break_point_info->IsUndefined()) {
11382 BreakPointInfo::SetBreakPoint(
11383 Handle<BreakPointInfo>::cast(break_point_info),
11384 break_point_object);
11385 return;
11386 }
11387
11388 // Adding a new break point for a code position which did not have any
11389 // break points before. Try to find a free slot.
11390 int index = kNoBreakPointInfo;
11391 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11392 if (debug_info->break_points()->get(i)->IsUndefined()) {
11393 index = i;
11394 break;
11395 }
11396 }
11397 if (index == kNoBreakPointInfo) {
11398 // No free slot - extend break point info array.
11399 Handle<FixedArray> old_break_points =
11400 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011401 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011402 isolate->factory()->NewFixedArray(
11403 old_break_points->length() +
11404 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011405
11406 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011407 for (int i = 0; i < old_break_points->length(); i++) {
11408 new_break_points->set(i, old_break_points->get(i));
11409 }
11410 index = old_break_points->length();
11411 }
11412 ASSERT(index != kNoBreakPointInfo);
11413
11414 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11416 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011417 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11418 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11419 new_break_point_info->
11420 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 new_break_point_info->set_break_point_objects(
11422 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011423 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11424 debug_info->break_points()->set(index, *new_break_point_info);
11425}
11426
11427
11428// Get the break point objects for a code position.
11429Object* DebugInfo::GetBreakPointObjects(int code_position) {
11430 Object* break_point_info = GetBreakPointInfo(code_position);
11431 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011432 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011433 }
11434 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11435}
11436
11437
11438// Get the total number of break points.
11439int DebugInfo::GetBreakPointCount() {
11440 if (break_points()->IsUndefined()) return 0;
11441 int count = 0;
11442 for (int i = 0; i < break_points()->length(); i++) {
11443 if (!break_points()->get(i)->IsUndefined()) {
11444 BreakPointInfo* break_point_info =
11445 BreakPointInfo::cast(break_points()->get(i));
11446 count += break_point_info->GetBreakPointCount();
11447 }
11448 }
11449 return count;
11450}
11451
11452
11453Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11454 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011455 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011457 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11458 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11459 Handle<BreakPointInfo> break_point_info =
11460 Handle<BreakPointInfo>(BreakPointInfo::cast(
11461 debug_info->break_points()->get(i)));
11462 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11463 break_point_object)) {
11464 return *break_point_info;
11465 }
11466 }
11467 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011468 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011469}
11470
11471
11472// Find the index of the break point info object for the specified code
11473// position.
11474int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11475 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11476 for (int i = 0; i < break_points()->length(); i++) {
11477 if (!break_points()->get(i)->IsUndefined()) {
11478 BreakPointInfo* break_point_info =
11479 BreakPointInfo::cast(break_points()->get(i));
11480 if (break_point_info->code_position()->value() == code_position) {
11481 return i;
11482 }
11483 }
11484 }
11485 return kNoBreakPointInfo;
11486}
11487
11488
11489// Remove the specified break point object.
11490void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11491 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011492 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011493 // If there are no break points just ignore.
11494 if (break_point_info->break_point_objects()->IsUndefined()) return;
11495 // If there is a single break point clear it if it is the same.
11496 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11497 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 break_point_info->set_break_point_objects(
11499 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011500 }
11501 return;
11502 }
11503 // If there are multiple break points shrink the array
11504 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11505 Handle<FixedArray> old_array =
11506 Handle<FixedArray>(
11507 FixedArray::cast(break_point_info->break_point_objects()));
11508 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011509 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011510 int found_count = 0;
11511 for (int i = 0; i < old_array->length(); i++) {
11512 if (old_array->get(i) == *break_point_object) {
11513 ASSERT(found_count == 0);
11514 found_count++;
11515 } else {
11516 new_array->set(i - found_count, old_array->get(i));
11517 }
11518 }
11519 // If the break point was found in the list change it.
11520 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11521}
11522
11523
11524// Add the specified break point object.
11525void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11526 Handle<Object> break_point_object) {
11527 // If there was no break point objects before just set it.
11528 if (break_point_info->break_point_objects()->IsUndefined()) {
11529 break_point_info->set_break_point_objects(*break_point_object);
11530 return;
11531 }
11532 // If the break point object is the same as before just ignore.
11533 if (break_point_info->break_point_objects() == *break_point_object) return;
11534 // If there was one break point object before replace with array.
11535 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011537 array->set(0, break_point_info->break_point_objects());
11538 array->set(1, *break_point_object);
11539 break_point_info->set_break_point_objects(*array);
11540 return;
11541 }
11542 // If there was more than one break point before extend array.
11543 Handle<FixedArray> old_array =
11544 Handle<FixedArray>(
11545 FixedArray::cast(break_point_info->break_point_objects()));
11546 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011547 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011548 for (int i = 0; i < old_array->length(); i++) {
11549 // If the break point was there before just ignore.
11550 if (old_array->get(i) == *break_point_object) return;
11551 new_array->set(i, old_array->get(i));
11552 }
11553 // Add the new break point.
11554 new_array->set(old_array->length(), *break_point_object);
11555 break_point_info->set_break_point_objects(*new_array);
11556}
11557
11558
11559bool BreakPointInfo::HasBreakPointObject(
11560 Handle<BreakPointInfo> break_point_info,
11561 Handle<Object> break_point_object) {
11562 // No break point.
11563 if (break_point_info->break_point_objects()->IsUndefined()) return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011564 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011565 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11566 return break_point_info->break_point_objects() == *break_point_object;
11567 }
11568 // Multiple break points.
11569 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11570 for (int i = 0; i < array->length(); i++) {
11571 if (array->get(i) == *break_point_object) {
11572 return true;
11573 }
11574 }
11575 return false;
11576}
11577
11578
11579// Get the number of break points.
11580int BreakPointInfo::GetBreakPointCount() {
11581 // No break point.
11582 if (break_point_objects()->IsUndefined()) return 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011583 // Single break point.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011584 if (!break_point_objects()->IsFixedArray()) return 1;
11585 // Multiple break points.
11586 return FixedArray::cast(break_point_objects())->length();
11587}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011588#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011589
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000011590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011591} } // namespace v8::internal