blob: bf881e99db955d6e88bc4d666e7f0df3f9d194e0 [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"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "execution.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "full-codegen.h"
38#include "hydrogen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "objects-inl.h"
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000040#include "objects-visiting.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "macro-assembler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "safepoint-table.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000043#include "scanner-base.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "string-stream.h"
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000045#include "utils.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000046#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047
mads.s.ager31e71382008-08-13 09:32:07 +000048#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +000049#include "disasm.h"
mads.s.ager31e71382008-08-13 09:32:07 +000050#include "disassembler.h"
51#endif
52
kasperl@chromium.org71affb52009-05-26 05:44:31 +000053namespace v8 {
54namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056// Getters and setters are stored in a fixed array property. These are
57// constants for their indices.
58const int kGetterIndex = 0;
59const int kSetterIndex = 1;
60
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
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);
193 HandleScope scope;
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();
233 HandleScope scope;
234 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 {
492 return dictionary->DeleteProperty(entry, mode);
493 }
494 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000495 return GetHeap()->true_value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000496}
497
498
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000499bool JSObject::IsDirty() {
500 Object* cons_obj = map()->constructor();
501 if (!cons_obj->IsJSFunction())
502 return true;
503 JSFunction* fun = JSFunction::cast(cons_obj);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000504 if (!fun->shared()->IsApiFunction())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000505 return true;
506 // If the object is fully fast case and has the same map it was
507 // created with then no changes can have been made to it.
508 return map() != fun->initial_map()
509 || !HasFastElements()
510 || !HasFastProperties();
511}
512
513
lrn@chromium.org303ada72010-10-27 09:33:13 +0000514MaybeObject* Object::GetProperty(Object* receiver,
515 LookupResult* result,
516 String* name,
517 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518 // Make sure that the top context does not change when doing
519 // callbacks or interceptor calls.
520 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 Heap* heap = name->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522
523 // Traverse the prototype chain from the current object (this) to
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000524 // the holder and check for access rights. This avoids traversing the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525 // objects more than once in case of interceptors, because the
526 // holder will always be the interceptor holder and the search may
527 // only continue with a current object just after the interceptor
528 // holder in the prototype chain.
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000529 // Proxy handlers do not use the proxy's prototype, so we can skip this.
530 if (!result->IsHandler()) {
531 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
532 ASSERT(this != this->GetPrototype());
533 for (Object* current = this; true; current = current->GetPrototype()) {
534 if (current->IsAccessCheckNeeded()) {
535 // Check if we're allowed to read from the current object. Note
536 // that even though we may not actually end up loading the named
537 // property from the current object, we still check that we have
538 // access to it.
539 JSObject* checked = JSObject::cast(current);
540 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
541 return checked->GetPropertyWithFailedAccessCheck(receiver,
542 result,
543 name,
544 attributes);
545 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000547 // Stop traversing the chain once we reach the last object in the
548 // chain; either the holder of the result or null in case of an
549 // absent property.
550 if (current == last) break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000552 }
553
kasper.lund44510672008-07-25 07:37:58 +0000554 if (!result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000555 *attributes = ABSENT;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000557 }
558 *attributes = result->GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000559 Object* value;
560 JSObject* holder = result->holder();
561 switch (result->type()) {
562 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +0000563 value = holder->GetNormalizedProperty(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000564 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000566 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +0000567 value = holder->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000568 ASSERT(!value->IsTheHole() || result->IsReadOnly());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 return value->IsTheHole() ? heap->undefined_value() : value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 case CONSTANT_FUNCTION:
571 return result->GetConstantFunction();
572 case CALLBACKS:
573 return GetPropertyWithCallback(receiver,
574 result->GetCallbackObject(),
575 name,
576 holder);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000577 case HANDLER: {
578 JSProxy* proxy = JSProxy::cast(this);
579 return GetPropertyWithHandler(receiver, name, proxy->handler());
580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000581 case INTERCEPTOR: {
582 JSObject* recvr = JSObject::cast(receiver);
583 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
584 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000585 case MAP_TRANSITION:
586 case EXTERNAL_ARRAY_TRANSITION:
587 case CONSTANT_TRANSITION:
588 case NULL_DESCRIPTOR:
589 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000590 }
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +0000591 UNREACHABLE();
592 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593}
594
595
lrn@chromium.org303ada72010-10-27 09:33:13 +0000596MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000597 Object* holder = NULL;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000598 if (IsSmi()) {
599 Context* global_context = Isolate::Current()->context()->global_context();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000600 holder = global_context->number_function()->instance_prototype();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000601 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000602 HeapObject* heap_object = HeapObject::cast(this);
603
604 if (heap_object->IsJSObject()) {
605 return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
606 }
607 Heap* heap = heap_object->GetHeap();
608 Isolate* isolate = heap->isolate();
609
610 Context* global_context = isolate->context()->global_context();
611 if (heap_object->IsString()) {
612 holder = global_context->string_function()->instance_prototype();
613 } else if (heap_object->IsHeapNumber()) {
614 holder = global_context->number_function()->instance_prototype();
615 } else if (heap_object->IsBoolean()) {
616 holder = global_context->boolean_function()->instance_prototype();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000617 } else if (heap_object->IsJSProxy()) {
618 return heap->undefined_value(); // For now...
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000619 } else {
620 // Undefined and null have no indexed properties.
621 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
622 return heap->undefined_value();
623 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000624 }
625
626 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000627}
628
629
630Object* Object::GetPrototype() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000631 if (IsSmi()) {
632 Heap* heap = Isolate::Current()->heap();
633 Context* context = heap->isolate()->context()->global_context();
634 return context->number_function()->instance_prototype();
635 }
636
637 HeapObject* heap_object = HeapObject::cast(this);
638
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000639 // The object is either a number, a string, a boolean,
640 // a real JS object, or a Harmony proxy.
641 if (heap_object->IsJSObject() || heap_object->IsJSProxy()) {
642 return heap_object->map()->prototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000643 }
644 Heap* heap = heap_object->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 Context* context = heap->isolate()->context()->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000647 if (heap_object->IsHeapNumber()) {
648 return context->number_function()->instance_prototype();
649 }
650 if (heap_object->IsString()) {
651 return context->string_function()->instance_prototype();
652 }
653 if (heap_object->IsBoolean()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000654 return context->boolean_function()->instance_prototype();
655 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 return heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000657 }
658}
659
660
whesse@chromium.org023421e2010-12-21 12:19:12 +0000661void Object::ShortPrint(FILE* out) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000662 HeapStringAllocator allocator;
663 StringStream accumulator(&allocator);
664 ShortPrint(&accumulator);
whesse@chromium.org023421e2010-12-21 12:19:12 +0000665 accumulator.OutputToFile(out);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000666}
667
668
669void Object::ShortPrint(StringStream* accumulator) {
670 if (IsSmi()) {
671 Smi::cast(this)->SmiPrint(accumulator);
672 } else if (IsFailure()) {
673 Failure::cast(this)->FailurePrint(accumulator);
674 } else {
675 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
676 }
677}
678
679
whesse@chromium.org023421e2010-12-21 12:19:12 +0000680void Smi::SmiPrint(FILE* out) {
681 PrintF(out, "%d", value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000682}
683
684
685void Smi::SmiPrint(StringStream* accumulator) {
686 accumulator->Add("%d", value());
687}
688
689
690void Failure::FailurePrint(StringStream* accumulator) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000691 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000692}
693
694
whesse@chromium.org023421e2010-12-21 12:19:12 +0000695void Failure::FailurePrint(FILE* out) {
696 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697}
698
699
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000700// Should a word be prefixed by 'a' or 'an' in order to read naturally in
701// English? Returns false for non-ASCII or words that don't start with
702// a capital letter. The a/an rule follows pronunciation in English.
703// We don't use the BBC's overcorrect "an historic occasion" though if
704// you speak a dialect you may well say "an 'istoric occasion".
705static bool AnWord(String* str) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000706 if (str->length() == 0) return false; // A nothing.
707 int c0 = str->Get(0);
708 int c1 = str->length() > 1 ? str->Get(1) : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 if (c0 == 'U') {
710 if (c1 > 'Z') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000711 return true; // An Umpire, but a UTF8String, a U.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000712 }
713 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000714 return true; // An Ape, an ABCBook.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
716 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
717 c0 == 'S' || c0 == 'X')) {
ager@chromium.org870a0b62008-11-04 11:43:05 +0000718 return true; // An MP3File, an M.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719 }
720 return false;
721}
722
723
lrn@chromium.org303ada72010-10-27 09:33:13 +0000724MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000725#ifdef DEBUG
726 // Do not attempt to flatten in debug mode when allocation is not
727 // allowed. This is to avoid an assertion failure when allocating.
728 // Flattening strings is the only case where we always allow
729 // allocation because no GC is performed if the allocation fails.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000730 if (!HEAP->IsAllocationAllowed()) return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000731#endif
732
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000733 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000734 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 case kConsStringTag: {
736 ConsString* cs = ConsString::cast(this);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000737 if (cs->second()->length() == 0) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000738 return cs->first();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739 }
740 // There's little point in putting the flat string in new space if the
741 // cons string is in old space. It can never get GCed until there is
742 // an old space GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000743 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000744 int len = length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000745 Object* object;
746 String* result;
ager@chromium.org5ec48922009-05-05 07:25:34 +0000747 if (IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000749 if (!maybe_object->ToObject(&object)) return maybe_object;
750 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000751 result = String::cast(object);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000752 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000753 int first_length = first->length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000754 char* dest = SeqAsciiString::cast(result)->GetChars();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000755 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000756 String* second = cs->second();
757 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000758 dest + first_length,
759 0,
760 len - first_length);
761 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000762 { MaybeObject* maybe_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000763 heap->AllocateRawTwoByteString(len, tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000764 if (!maybe_object->ToObject(&object)) return maybe_object;
765 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000766 result = String::cast(object);
767 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
ager@chromium.org870a0b62008-11-04 11:43:05 +0000768 String* first = cs->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000769 int first_length = first->length();
770 WriteToFlat(first, dest, 0, first_length);
ager@chromium.org870a0b62008-11-04 11:43:05 +0000771 String* second = cs->second();
772 WriteToFlat(second,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000773 dest + first_length,
774 0,
775 len - first_length);
776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 cs->set_first(result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000778 cs->set_second(heap->empty_string());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000779 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 }
781 default:
782 return this;
783 }
784}
785
786
ager@chromium.org6f10e412009-02-13 10:11:16 +0000787bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
lrn@chromium.org32d961d2010-06-30 09:09:34 +0000788 // Externalizing twice leaks the external resource, so it's
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000789 // prohibited by the API.
790 ASSERT(!this->IsExternalString());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000791#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000792 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000793 // Assert that the resource and the string are equivalent.
794 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000795 ScopedVector<uc16> smart_chars(this->length());
796 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
797 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000798 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000799 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000800 }
801#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000802 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000803 int size = this->Size(); // Byte size of the original string.
804 if (size < ExternalString::kSize) {
805 // The string is too small to fit an external String in its place. This can
806 // only happen for zero length strings.
807 return false;
808 }
809 ASSERT(size >= ExternalString::kSize);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000810 bool is_ascii = this->IsAsciiRepresentation();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000811 bool is_symbol = this->IsSymbol();
812 int length = this->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000813 int hash_field = this->hash_field();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000814
815 // Morph the object to an external string by adjusting the map and
816 // reinitializing the fields.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000817 this->set_map(is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 heap->external_string_with_ascii_data_map() :
819 heap->external_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000820 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
821 self->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000822 self->set_hash_field(hash_field);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000823 self->set_resource(resource);
824 // Additionally make the object into an external symbol if the original string
825 // was a symbol to start with.
826 if (is_symbol) {
827 self->Hash(); // Force regeneration of the hash value.
828 // Now morph this external string into a external symbol.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000829 this->set_map(is_ascii ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 heap->external_symbol_with_ascii_data_map() :
831 heap->external_symbol_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000832 }
833
834 // Fill the remainder of the string with dead wood.
835 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000836 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000837 return true;
838}
839
840
841bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
842#ifdef DEBUG
ager@chromium.org3811b432009-10-28 14:53:37 +0000843 if (FLAG_enable_slow_asserts) {
ager@chromium.org6f10e412009-02-13 10:11:16 +0000844 // Assert that the resource and the string are equivalent.
845 ASSERT(static_cast<size_t>(this->length()) == resource->length());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000846 ScopedVector<char> smart_chars(this->length());
847 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
848 ASSERT(memcmp(smart_chars.start(),
ager@chromium.org6f10e412009-02-13 10:11:16 +0000849 resource->data(),
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000850 resource->length() * sizeof(smart_chars[0])) == 0);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000851 }
852#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 Heap* heap = GetHeap();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000854 int size = this->Size(); // Byte size of the original string.
855 if (size < ExternalString::kSize) {
856 // The string is too small to fit an external String in its place. This can
857 // only happen for zero length strings.
858 return false;
859 }
860 ASSERT(size >= ExternalString::kSize);
861 bool is_symbol = this->IsSymbol();
862 int length = this->length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000863 int hash_field = this->hash_field();
ager@chromium.org6f10e412009-02-13 10:11:16 +0000864
865 // Morph the object to an external string by adjusting the map and
866 // reinitializing the fields.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000867 this->set_map(heap->external_ascii_string_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000868 ExternalAsciiString* self = ExternalAsciiString::cast(this);
869 self->set_length(length);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000870 self->set_hash_field(hash_field);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000871 self->set_resource(resource);
872 // Additionally make the object into an external symbol if the original string
873 // was a symbol to start with.
874 if (is_symbol) {
875 self->Hash(); // Force regeneration of the hash value.
876 // Now morph this external string into a external symbol.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000877 this->set_map(heap->external_ascii_symbol_map());
ager@chromium.org6f10e412009-02-13 10:11:16 +0000878 }
879
880 // Fill the remainder of the string with dead wood.
881 int new_size = this->Size(); // Byte size of the external String object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000882 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
ager@chromium.org6f10e412009-02-13 10:11:16 +0000883 return true;
884}
885
886
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000887void String::StringShortPrint(StringStream* accumulator) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000888 int len = length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000889 if (len > kMaxShortPrintLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 accumulator->Add("<Very long string[%u]>", len);
891 return;
892 }
893
894 if (!LooksValid()) {
895 accumulator->Add("<Invalid String>");
896 return;
897 }
898
899 StringInputBuffer buf(this);
900
901 bool truncated = false;
kasper.lund7276f142008-07-30 08:49:36 +0000902 if (len > kMaxShortPrintLength) {
903 len = kMaxShortPrintLength;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000904 truncated = true;
905 }
906 bool ascii = true;
907 for (int i = 0; i < len; i++) {
908 int c = buf.GetNext();
909
910 if (c < 32 || c >= 127) {
911 ascii = false;
912 }
913 }
914 buf.Reset(this);
915 if (ascii) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000916 accumulator->Add("<String[%u]: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 for (int i = 0; i < len; i++) {
918 accumulator->Put(buf.GetNext());
919 }
920 accumulator->Put('>');
921 } else {
922 // Backslash indicates that the string contains control
923 // characters and that backslashes are therefore escaped.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000924 accumulator->Add("<String[%u]\\: ", length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 for (int i = 0; i < len; i++) {
926 int c = buf.GetNext();
927 if (c == '\n') {
928 accumulator->Add("\\n");
929 } else if (c == '\r') {
930 accumulator->Add("\\r");
931 } else if (c == '\\') {
932 accumulator->Add("\\\\");
933 } else if (c < 32 || c > 126) {
934 accumulator->Add("\\x%02x", c);
935 } else {
936 accumulator->Put(c);
937 }
938 }
939 if (truncated) {
940 accumulator->Put('.');
941 accumulator->Put('.');
942 accumulator->Put('.');
943 }
944 accumulator->Put('>');
945 }
946 return;
947}
948
949
950void JSObject::JSObjectShortPrint(StringStream* accumulator) {
951 switch (map()->instance_type()) {
952 case JS_ARRAY_TYPE: {
953 double length = JSArray::cast(this)->length()->Number();
954 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
955 break;
956 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000957 case JS_REGEXP_TYPE: {
958 accumulator->Add("<JS RegExp>");
959 break;
960 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961 case JS_FUNCTION_TYPE: {
962 Object* fun_name = JSFunction::cast(this)->shared()->name();
963 bool printed = false;
964 if (fun_name->IsString()) {
965 String* str = String::cast(fun_name);
966 if (str->length() > 0) {
967 accumulator->Add("<JS Function ");
968 accumulator->Put(str);
969 accumulator->Put('>');
970 printed = true;
971 }
972 }
973 if (!printed) {
974 accumulator->Add("<JS Function>");
975 }
976 break;
977 }
978 // All other JSObjects are rather similar to each other (JSObject,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000979 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000980 default: {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000981 Map* map_of_this = map();
982 Heap* heap = map_of_this->heap();
983 Object* constructor = map_of_this->constructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984 bool printed = false;
985 if (constructor->IsHeapObject() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 !heap->Contains(HeapObject::cast(constructor))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
988 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000989 bool global_object = IsJSGlobalProxy();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000990 if (constructor->IsJSFunction()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
993 } else {
994 Object* constructor_name =
995 JSFunction::cast(constructor)->shared()->name();
996 if (constructor_name->IsString()) {
997 String* str = String::cast(constructor_name);
998 if (str->length() > 0) {
999 bool vowel = AnWord(str);
1000 accumulator->Add("<%sa%s ",
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001001 global_object ? "Global Object: " : "",
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002 vowel ? "n" : "");
1003 accumulator->Put(str);
1004 accumulator->Put('>');
1005 printed = true;
1006 }
1007 }
1008 }
1009 }
1010 if (!printed) {
1011 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1012 }
1013 }
1014 if (IsJSValue()) {
1015 accumulator->Add(" value = ");
1016 JSValue::cast(this)->value()->ShortPrint(accumulator);
1017 }
1018 accumulator->Put('>');
1019 break;
1020 }
1021 }
1022}
1023
1024
1025void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001026 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1027 Heap* heap = GetHeap();
1028 if (!heap->Contains(this)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 accumulator->Add("!!!INVALID POINTER!!!");
1030 return;
1031 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 if (!heap->Contains(map())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033 accumulator->Add("!!!INVALID MAP!!!");
1034 return;
1035 }
1036
1037 accumulator->Add("%p ", this);
1038
1039 if (IsString()) {
1040 String::cast(this)->StringShortPrint(accumulator);
1041 return;
1042 }
1043 if (IsJSObject()) {
1044 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1045 return;
1046 }
1047 switch (map()->instance_type()) {
1048 case MAP_TYPE:
1049 accumulator->Add("<Map>");
1050 break;
1051 case FIXED_ARRAY_TYPE:
1052 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1053 break;
1054 case BYTE_ARRAY_TYPE:
1055 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1056 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001057 case EXTERNAL_PIXEL_ARRAY_TYPE:
1058 accumulator->Add("<ExternalPixelArray[%u]>",
1059 ExternalPixelArray::cast(this)->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001060 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00001061 case EXTERNAL_BYTE_ARRAY_TYPE:
1062 accumulator->Add("<ExternalByteArray[%u]>",
1063 ExternalByteArray::cast(this)->length());
1064 break;
1065 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1066 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1067 ExternalUnsignedByteArray::cast(this)->length());
1068 break;
1069 case EXTERNAL_SHORT_ARRAY_TYPE:
1070 accumulator->Add("<ExternalShortArray[%u]>",
1071 ExternalShortArray::cast(this)->length());
1072 break;
1073 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1074 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1075 ExternalUnsignedShortArray::cast(this)->length());
1076 break;
1077 case EXTERNAL_INT_ARRAY_TYPE:
1078 accumulator->Add("<ExternalIntArray[%u]>",
1079 ExternalIntArray::cast(this)->length());
1080 break;
1081 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1082 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1083 ExternalUnsignedIntArray::cast(this)->length());
1084 break;
1085 case EXTERNAL_FLOAT_ARRAY_TYPE:
1086 accumulator->Add("<ExternalFloatArray[%u]>",
1087 ExternalFloatArray::cast(this)->length());
1088 break;
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001089 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1090 accumulator->Add("<ExternalDoubleArray[%u]>",
1091 ExternalDoubleArray::cast(this)->length());
1092 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 case SHARED_FUNCTION_INFO_TYPE:
1094 accumulator->Add("<SharedFunctionInfo>");
1095 break;
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001096 case JS_MESSAGE_OBJECT_TYPE:
1097 accumulator->Add("<JSMessageObject>");
1098 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099#define MAKE_STRUCT_CASE(NAME, Name, name) \
1100 case NAME##_TYPE: \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001101 accumulator->Put('<'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001102 accumulator->Add(#Name); \
ager@chromium.org381abbb2009-02-25 13:23:22 +00001103 accumulator->Put('>'); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001104 break;
1105 STRUCT_LIST(MAKE_STRUCT_CASE)
1106#undef MAKE_STRUCT_CASE
1107 case CODE_TYPE:
1108 accumulator->Add("<Code>");
1109 break;
1110 case ODDBALL_TYPE: {
1111 if (IsUndefined())
1112 accumulator->Add("<undefined>");
1113 else if (IsTheHole())
1114 accumulator->Add("<the hole>");
1115 else if (IsNull())
1116 accumulator->Add("<null>");
1117 else if (IsTrue())
1118 accumulator->Add("<true>");
1119 else if (IsFalse())
1120 accumulator->Add("<false>");
1121 else
1122 accumulator->Add("<Odd Oddball>");
1123 break;
1124 }
1125 case HEAP_NUMBER_TYPE:
1126 accumulator->Add("<Number: ");
1127 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1128 accumulator->Put('>');
1129 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001130 case FOREIGN_TYPE:
1131 accumulator->Add("<Foreign>");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001132 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001133 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1134 accumulator->Add("Cell for ");
1135 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1136 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 default:
1138 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1139 break;
1140 }
1141}
1142
1143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144void HeapObject::Iterate(ObjectVisitor* v) {
1145 // Handle header
1146 IteratePointer(v, kMapOffset);
1147 // Handle object body
1148 Map* m = map();
1149 IterateBody(m->instance_type(), SizeFromMap(m), v);
1150}
1151
1152
1153void HeapObject::IterateBody(InstanceType type, int object_size,
1154 ObjectVisitor* v) {
1155 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1156 // During GC, the map pointer field is encoded.
1157 if (type < FIRST_NONSTRING_TYPE) {
1158 switch (type & kStringRepresentationMask) {
1159 case kSeqStringTag:
1160 break;
1161 case kConsStringTag:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001162 ConsString::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163 break;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001164 case kExternalStringTag:
1165 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1166 reinterpret_cast<ExternalAsciiString*>(this)->
1167 ExternalAsciiStringIterateBody(v);
1168 } else {
1169 reinterpret_cast<ExternalTwoByteString*>(this)->
1170 ExternalTwoByteStringIterateBody(v);
1171 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 break;
1173 }
1174 return;
1175 }
1176
1177 switch (type) {
1178 case FIXED_ARRAY_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001179 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180 break;
1181 case JS_OBJECT_TYPE:
ager@chromium.org32912102009-01-16 10:38:43 +00001182 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 case JS_VALUE_TYPE:
1184 case JS_ARRAY_TYPE:
ager@chromium.org236ad962008-09-25 09:45:57 +00001185 case JS_REGEXP_TYPE:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001186 case JS_GLOBAL_PROXY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001187 case JS_GLOBAL_OBJECT_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 case JS_BUILTINS_OBJECT_TYPE:
kmillikin@chromium.org31b12772011-02-02 16:08:26 +00001189 case JS_MESSAGE_OBJECT_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001190 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001191 break;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00001192 case JS_FUNCTION_TYPE:
1193 reinterpret_cast<JSFunction*>(this)
1194 ->JSFunctionIterateBody(object_size, v);
1195 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196 case ODDBALL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001197 Oddball::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001198 break;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00001199 case JS_PROXY_TYPE:
1200 JSProxy::BodyDescriptor::IterateBody(this, v);
1201 break;
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001202 case FOREIGN_TYPE:
1203 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 break;
1205 case MAP_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001206 Map::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001207 break;
1208 case CODE_TYPE:
1209 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1210 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001211 case JS_GLOBAL_PROPERTY_CELL_TYPE:
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001212 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001213 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 case HEAP_NUMBER_TYPE:
1215 case FILLER_TYPE:
1216 case BYTE_ARRAY_TYPE:
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001217 case EXTERNAL_PIXEL_ARRAY_TYPE:
ager@chromium.org3811b432009-10-28 14:53:37 +00001218 case EXTERNAL_BYTE_ARRAY_TYPE:
1219 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1220 case EXTERNAL_SHORT_ARRAY_TYPE:
1221 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1222 case EXTERNAL_INT_ARRAY_TYPE:
1223 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1224 case EXTERNAL_FLOAT_ARRAY_TYPE:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00001225 case EXTERNAL_DOUBLE_ARRAY_TYPE:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001227 case SHARED_FUNCTION_INFO_TYPE:
1228 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001229 break;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001230
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001231#define MAKE_STRUCT_CASE(NAME, Name, name) \
1232 case NAME##_TYPE:
1233 STRUCT_LIST(MAKE_STRUCT_CASE)
1234#undef MAKE_STRUCT_CASE
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001235 StructBodyDescriptor::IterateBody(this, object_size, v);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 break;
1237 default:
1238 PrintF("Unknown type: %d\n", type);
1239 UNREACHABLE();
1240 }
1241}
1242
1243
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244Object* HeapNumber::HeapNumberToBoolean() {
1245 // NaN, +0, and -0 should return the false object
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001246#if __BYTE_ORDER == __LITTLE_ENDIAN
1247 union IeeeDoubleLittleEndianArchType u;
1248#elif __BYTE_ORDER == __BIG_ENDIAN
1249 union IeeeDoubleBigEndianArchType u;
1250#endif
1251 u.d = value();
1252 if (u.bits.exp == 2047) {
1253 // Detect NaN for IEEE double precision floating point.
1254 if ((u.bits.man_low | u.bits.man_high) != 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001255 return GetHeap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001256 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001257 if (u.bits.exp == 0) {
1258 // Detect +0, and -0 for IEEE double precision floating point.
1259 if ((u.bits.man_low | u.bits.man_high) == 0)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001260 return GetHeap()->false_value();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001261 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001262 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263}
1264
1265
whesse@chromium.org023421e2010-12-21 12:19:12 +00001266void HeapNumber::HeapNumberPrint(FILE* out) {
1267 PrintF(out, "%.16g", Number());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268}
1269
1270
1271void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1272 // The Windows version of vsnprintf can allocate when printing a %g string
1273 // into a buffer that may not be big enough. We don't want random memory
1274 // allocation when producing post-crash stack traces, so we print into a
1275 // buffer that is plenty big enough for any floating point number, then
1276 // print that using vsnprintf (which may truncate but never allocate if
1277 // there is no more space in the buffer).
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001278 EmbeddedVector<char, 100> buffer;
1279 OS::SNPrintF(buffer, "%.16g", Number());
1280 accumulator->Add("%s", buffer.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281}
1282
1283
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001284String* JSReceiver::class_name() {
1285 if (IsJSFunction() && IsJSFunctionProxy()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 return GetHeap()->function_class_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001287 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 if (map()->constructor()->IsJSFunction()) {
1289 JSFunction* constructor = JSFunction::cast(map()->constructor());
1290 return String::cast(constructor->shared()->instance_class_name());
1291 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001292 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001293 return GetHeap()->Object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294}
1295
1296
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001297String* JSReceiver::constructor_name() {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001298 if (map()->constructor()->IsJSFunction()) {
1299 JSFunction* constructor = JSFunction::cast(map()->constructor());
1300 String* name = String::cast(constructor->shared()->name());
vegorov@chromium.org42841962010-10-18 11:18:59 +00001301 if (name->length() > 0) return name;
1302 String* inferred_name = constructor->shared()->inferred_name();
1303 if (inferred_name->length() > 0) return inferred_name;
1304 Object* proto = GetPrototype();
1305 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001306 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001307 // TODO(rossberg): what about proxies?
ager@chromium.orga1645e22009-09-09 19:27:10 +00001308 // If the constructor is not present, return "Object".
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 return GetHeap()->Object_symbol();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001310}
1311
1312
lrn@chromium.org303ada72010-10-27 09:33:13 +00001313MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1314 String* name,
1315 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001316 int index = new_map->PropertyIndexFor(name);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001317 if (map()->unused_property_fields() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 ASSERT(map()->unused_property_fields() == 0);
1319 int new_unused = new_map->unused_property_fields();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001320 Object* values;
1321 { MaybeObject* maybe_values =
1322 properties()->CopySize(properties()->length() + new_unused + 1);
1323 if (!maybe_values->ToObject(&values)) return maybe_values;
1324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 set_properties(FixedArray::cast(values));
1326 }
1327 set_map(new_map);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001328 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001329}
1330
1331
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001332static bool IsIdentifier(UnicodeCache* cache,
1333 unibrow::CharacterStream* buffer) {
1334 // Checks whether the buffer contains an identifier (no escape).
1335 if (!buffer->has_more()) return false;
1336 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1337 return false;
1338 }
1339 while (buffer->has_more()) {
1340 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1341 return false;
1342 }
1343 }
1344 return true;
1345}
1346
1347
lrn@chromium.org303ada72010-10-27 09:33:13 +00001348MaybeObject* JSObject::AddFastProperty(String* name,
1349 Object* value,
1350 PropertyAttributes attributes) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001351 ASSERT(!IsJSGlobalProxy());
1352
ager@chromium.org8c51fc92009-04-22 11:54:55 +00001353 // Normalize the object if the name is an actual string (not the
1354 // hidden symbols) and is not a real identifier.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001355 Isolate* isolate = GetHeap()->isolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001356 StringInputBuffer buffer(name);
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001357 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001358 && name != isolate->heap()->hidden_symbol()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001359 Object* obj;
1360 { MaybeObject* maybe_obj =
1361 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1362 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1363 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 return AddSlowProperty(name, value, attributes);
1365 }
1366
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001367 DescriptorArray* old_descriptors = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001368 // Compute the new index for new field.
1369 int index = map()->NextFreePropertyIndex();
1370
1371 // Allocate new instance descriptors with (name, index) added
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001372 FieldDescriptor new_field(name, index, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001373 Object* new_descriptors;
1374 { MaybeObject* maybe_new_descriptors =
1375 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1376 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1377 return maybe_new_descriptors;
1378 }
1379 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001380
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001381 // Only allow map transition if the object isn't the global object and there
1382 // is not a transition for the name, or there's a transition for the name but
1383 // it's unrelated to properties.
1384 int descriptor_index = old_descriptors->Search(name);
1385
1386 // External array transitions are stored in the descriptor for property "",
1387 // which is not a identifier and should have forced a switch to slow
1388 // properties above.
1389 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1390 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1391 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1392 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 bool allow_map_transition =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001394 can_insert_transition &&
1395 (isolate->context()->global_context()->object_function()->map() != map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396
ager@chromium.org7c537e22008-10-16 08:43:32 +00001397 ASSERT(index < map()->inobject_properties() ||
1398 (index - map()->inobject_properties()) < properties()->length() ||
1399 map()->unused_property_fields() == 0);
1400 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001401 Object* r;
1402 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1403 if (!maybe_r->ToObject(&r)) return maybe_r;
1404 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001405 Map* new_map = Map::cast(r);
1406 if (allow_map_transition) {
1407 // Allocate new instance descriptors for the old map with map transition.
1408 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001409 Object* r;
1410 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1411 if (!maybe_r->ToObject(&r)) return maybe_r;
1412 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001413 old_descriptors = DescriptorArray::cast(r);
1414 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415
ager@chromium.org7c537e22008-10-16 08:43:32 +00001416 if (map()->unused_property_fields() == 0) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001417 if (properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001418 Object* obj;
1419 { MaybeObject* maybe_obj =
1420 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1421 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1422 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 return AddSlowProperty(name, value, attributes);
1424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425 // Make room for the new value
lrn@chromium.org303ada72010-10-27 09:33:13 +00001426 Object* values;
1427 { MaybeObject* maybe_values =
1428 properties()->CopySize(properties()->length() + kFieldsAdded);
1429 if (!maybe_values->ToObject(&values)) return maybe_values;
1430 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001431 set_properties(FixedArray::cast(values));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001432 new_map->set_unused_property_fields(kFieldsAdded - 1);
1433 } else {
1434 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001436 // We have now allocated all the necessary objects.
1437 // All the changes can be applied at once, so they are atomic.
1438 map()->set_instance_descriptors(old_descriptors);
1439 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1440 set_map(new_map);
1441 return FastPropertyAtPut(index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001442}
1443
1444
lrn@chromium.org303ada72010-10-27 09:33:13 +00001445MaybeObject* JSObject::AddConstantFunctionProperty(
1446 String* name,
1447 JSFunction* function,
1448 PropertyAttributes attributes) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001449 ASSERT(!GetHeap()->InNewSpace(function));
sgjesse@chromium.org846fb742009-12-18 08:56:33 +00001450
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 // Allocate new instance descriptors with (name, function) added
1452 ConstantFunctionDescriptor d(name, function, attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001453 Object* new_descriptors;
1454 { MaybeObject* maybe_new_descriptors =
1455 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1456 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1457 return maybe_new_descriptors;
1458 }
1459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // Allocate a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001462 Object* new_map;
1463 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1464 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001466
1467 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1468 Map::cast(new_map)->set_instance_descriptors(descriptors);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001469 Map* old_map = map();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001470 set_map(Map::cast(new_map));
1471
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001472 // If the old map is the global object map (from new Object()),
1473 // then transitions are not added to it, so we are done.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001474 Heap* heap = old_map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 if (old_map == heap->isolate()->context()->global_context()->
1476 object_function()->map()) {
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001477 return function;
1478 }
1479
1480 // Do not add CONSTANT_TRANSITIONS to global objects
1481 if (IsGlobalObject()) {
1482 return function;
1483 }
1484
1485 // Add a CONSTANT_TRANSITION descriptor to the old map,
1486 // so future assignments to this property on other objects
1487 // of the same type will create a normal field, not a constant function.
1488 // Don't do this for special properties, with non-trival attributes.
1489 if (attributes != NONE) {
1490 return function;
1491 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001492 ConstTransitionDescriptor mark(name, Map::cast(new_map));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001493 { MaybeObject* maybe_new_descriptors =
1494 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1495 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1496 // We have accomplished the main goal, so return success.
1497 return function;
1498 }
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001499 }
1500 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 return function;
1503}
1504
1505
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506// Add property in slow mode
lrn@chromium.org303ada72010-10-27 09:33:13 +00001507MaybeObject* JSObject::AddSlowProperty(String* name,
1508 Object* value,
1509 PropertyAttributes attributes) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001510 ASSERT(!HasFastProperties());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001511 StringDictionary* dict = property_dictionary();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001512 Object* store_value = value;
1513 if (IsGlobalObject()) {
1514 // In case name is an orphaned property reuse the cell.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001515 int entry = dict->FindEntry(name);
1516 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001517 store_value = dict->ValueAt(entry);
1518 JSGlobalPropertyCell::cast(store_value)->set_value(value);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001519 // Assign an enumeration index to the property and update
1520 // SetNextEnumerationIndex.
1521 int index = dict->NextEnumerationIndex();
1522 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1523 dict->SetNextEnumerationIndex(index + 1);
1524 dict->SetEntry(entry, name, store_value, details);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001525 return value;
1526 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001527 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001528 { MaybeObject* maybe_store_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001529 heap->AllocateJSGlobalPropertyCell(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001530 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1531 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001532 JSGlobalPropertyCell::cast(store_value)->set_value(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001533 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001534 PropertyDetails details = PropertyDetails(attributes, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001535 Object* result;
1536 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1537 if (!maybe_result->ToObject(&result)) return maybe_result;
1538 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001539 if (dict != result) set_properties(StringDictionary::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 return value;
1541}
1542
1543
lrn@chromium.org303ada72010-10-27 09:33:13 +00001544MaybeObject* JSObject::AddProperty(String* name,
1545 Object* value,
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001546 PropertyAttributes attributes,
1547 StrictModeFlag strict_mode) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001548 ASSERT(!IsJSGlobalProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001549 Map* map_of_this = map();
1550 Heap* heap = map_of_this->heap();
1551 if (!map_of_this->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001552 if (strict_mode == kNonStrictMode) {
1553 return heap->undefined_value();
1554 } else {
1555 Handle<Object> args[1] = {Handle<String>(name)};
1556 return heap->isolate()->Throw(
1557 *FACTORY->NewTypeError("object_not_extensible",
1558 HandleVector(args, 1)));
1559 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001560 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 if (HasFastProperties()) {
1562 // Ensure the descriptor array does not get too big.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001563 if (map_of_this->instance_descriptors()->number_of_descriptors() <
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 DescriptorArray::kMaxNumberOfDescriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001565 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566 return AddConstantFunctionProperty(name,
1567 JSFunction::cast(value),
1568 attributes);
1569 } else {
1570 return AddFastProperty(name, value, attributes);
1571 }
1572 } else {
1573 // Normalize the object to prevent very large instance descriptors.
1574 // This eliminates unwanted N^2 allocation and lookup behavior.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001575 Object* obj;
1576 { MaybeObject* maybe_obj =
1577 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1578 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1579 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001580 }
1581 }
1582 return AddSlowProperty(name, value, attributes);
1583}
1584
1585
lrn@chromium.org303ada72010-10-27 09:33:13 +00001586MaybeObject* JSObject::SetPropertyPostInterceptor(
1587 String* name,
1588 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001589 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001590 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 // Check local property, ignore interceptor.
1592 LookupResult result;
1593 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001594 if (result.IsFound()) {
1595 // An existing property, a map transition or a null descriptor was
1596 // found. Use set property to handle all these cases.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001597 return SetProperty(&result, name, value, attributes, strict_mode);
ager@chromium.org5c838252010-02-19 08:53:10 +00001598 }
1599 // Add a new real property.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001600 return AddProperty(name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601}
1602
1603
lrn@chromium.org303ada72010-10-27 09:33:13 +00001604MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1605 Object* value,
1606 PropertyAttributes attributes) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001607 StringDictionary* dictionary = property_dictionary();
1608 int old_index = dictionary->FindEntry(name);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001609 int new_enumeration_index = 0; // 0 means "Use the next available index."
1610 if (old_index != -1) {
1611 // All calls to ReplaceSlowProperty have had all transitions removed.
1612 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1613 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1614 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001615
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001616 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001617 return SetNormalizedProperty(name, value, new_details);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001618}
1619
ager@chromium.org6141cbe2009-11-20 12:14:52 +00001620
lrn@chromium.org303ada72010-10-27 09:33:13 +00001621MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
ager@chromium.org7c537e22008-10-16 08:43:32 +00001622 String* name,
1623 Object* new_value,
1624 PropertyAttributes attributes) {
1625 Map* old_map = map();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001626 Object* result;
1627 { MaybeObject* maybe_result =
1628 ConvertDescriptorToField(name, new_value, attributes);
1629 if (!maybe_result->ToObject(&result)) return maybe_result;
1630 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001631 // If we get to this point we have succeeded - do not return failure
1632 // after this point. Later stuff is optional.
1633 if (!HasFastProperties()) {
1634 return result;
1635 }
1636 // Do not add transitions to the map of "new Object()".
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001637 if (map() == old_map->heap()->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 object_function()->map()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001639 return result;
1640 }
1641
1642 MapTransitionDescriptor transition(name,
1643 map(),
1644 attributes);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001645 Object* new_descriptors;
1646 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1647 CopyInsert(&transition, KEEP_TRANSITIONS);
1648 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1649 return result; // Yes, return _result_.
1650 }
1651 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001652 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1653 return result;
1654}
1655
1656
lrn@chromium.org303ada72010-10-27 09:33:13 +00001657MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1658 Object* new_value,
1659 PropertyAttributes attributes) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001660 if (map()->unused_property_fields() == 0 &&
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001661 properties()->length() > MaxFastProperties()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001662 Object* obj;
1663 { MaybeObject* maybe_obj =
1664 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1665 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1666 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001667 return ReplaceSlowProperty(name, new_value, attributes);
1668 }
1669
1670 int index = map()->NextFreePropertyIndex();
1671 FieldDescriptor new_field(name, index, attributes);
1672 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001673 Object* descriptors_unchecked;
1674 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1675 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1676 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1677 return maybe_descriptors_unchecked;
1678 }
1679 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001680 DescriptorArray* new_descriptors =
1681 DescriptorArray::cast(descriptors_unchecked);
1682
1683 // Make a new map for the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001684 Object* new_map_unchecked;
1685 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1686 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1687 return maybe_new_map_unchecked;
1688 }
1689 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001690 Map* new_map = Map::cast(new_map_unchecked);
1691 new_map->set_instance_descriptors(new_descriptors);
1692
1693 // Make new properties array if necessary.
1694 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1695 int new_unused_property_fields = map()->unused_property_fields() - 1;
1696 if (map()->unused_property_fields() == 0) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001697 new_unused_property_fields = kFieldsAdded - 1;
lrn@chromium.org303ada72010-10-27 09:33:13 +00001698 Object* new_properties_object;
1699 { MaybeObject* maybe_new_properties_object =
1700 properties()->CopySize(properties()->length() + kFieldsAdded);
1701 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1702 return maybe_new_properties_object;
1703 }
1704 }
1705 new_properties = FixedArray::cast(new_properties_object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001706 }
1707
1708 // Update pointers to commit changes.
1709 // Object points to the new map.
1710 new_map->set_unused_property_fields(new_unused_property_fields);
1711 set_map(new_map);
1712 if (new_properties) {
1713 set_properties(FixedArray::cast(new_properties));
1714 }
1715 return FastPropertyAtPut(index, new_value);
1716}
1717
1718
1719
lrn@chromium.org303ada72010-10-27 09:33:13 +00001720MaybeObject* JSObject::SetPropertyWithInterceptor(
1721 String* name,
1722 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001723 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001724 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001725 Isolate* isolate = GetIsolate();
1726 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 Handle<JSObject> this_handle(this);
1728 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1731 if (!interceptor->setter()->IsUndefined()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001732 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1733 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001734 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735 v8::NamedPropertySetter setter =
1736 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1737 v8::Handle<v8::Value> result;
1738 {
1739 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 Handle<Object> value_unhole(value->IsTheHole() ?
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001742 isolate->heap()->undefined_value() :
1743 value,
1744 isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001745 result = setter(v8::Utils::ToLocal(name_handle),
1746 v8::Utils::ToLocal(value_unhole),
1747 info);
1748 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750 if (!result.IsEmpty()) return *value_handle;
1751 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 MaybeObject* raw_result =
1753 this_handle->SetPropertyPostInterceptor(*name_handle,
1754 *value_handle,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001755 attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001756 strict_mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001757 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 return raw_result;
1759}
1760
1761
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001762MaybeObject* JSReceiver::SetProperty(String* name,
1763 Object* value,
1764 PropertyAttributes attributes,
1765 StrictModeFlag strict_mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 LookupResult result;
1767 LocalLookup(name, &result);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001768 return SetProperty(&result, name, value, attributes, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769}
1770
1771
lrn@chromium.org303ada72010-10-27 09:33:13 +00001772MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1773 String* name,
1774 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001775 JSObject* holder,
1776 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001777 Isolate* isolate = GetIsolate();
1778 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001779
1780 // We should never get here to initialize a const with the hole
1781 // value since a const declaration would conflict with the setter.
1782 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001783 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784
1785 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001786 // data structure used to store the callbacks. Eventually foreign
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001788 if (structure->IsForeign()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001789 AccessorDescriptor* callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00001790 reinterpret_cast<AccessorDescriptor*>(
1791 Foreign::cast(structure)->address());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001792 MaybeObject* obj = (callback->setter)(this, value, callback->data);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001794 if (obj->IsFailure()) return obj;
1795 return *value_handle;
1796 }
1797
1798 if (structure->IsAccessorInfo()) {
1799 // api style callbacks
1800 AccessorInfo* data = AccessorInfo::cast(structure);
1801 Object* call_obj = data->setter();
1802 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1803 if (call_fun == NULL) return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1806 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00001807 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001808 {
1809 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001810 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001811 call_fun(v8::Utils::ToLocal(key),
1812 v8::Utils::ToLocal(value_handle),
1813 info);
1814 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001815 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 return *value_handle;
1817 }
1818
1819 if (structure->IsFixedArray()) {
1820 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1821 if (setter->IsJSFunction()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001822 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001824 if (strict_mode == kNonStrictMode) {
1825 return value;
1826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 Handle<String> key(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001828 Handle<Object> holder_handle(holder, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001830 return isolate->Throw(
1831 *isolate->factory()->NewTypeError("no_setter_in_callback",
1832 HandleVector(args, 2)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001834 }
1835
1836 UNREACHABLE();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001837 return NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001838}
1839
1840
lrn@chromium.org303ada72010-10-27 09:33:13 +00001841MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1842 Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001843 Isolate* isolate = GetIsolate();
1844 Handle<Object> value_handle(value, isolate);
1845 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1846 Handle<JSObject> self(this, isolate);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001847#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001848 Debug* debug = isolate->debug();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001849 // Handle stepping into a setter if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001850 if (debug->StepInActive()) {
1851 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001852 }
1853#endif
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001854 bool has_pending_exception;
1855 Object** argv[] = { value_handle.location() };
1856 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1857 // Check for pending exception and return the result.
1858 if (has_pending_exception) return Failure::Exception();
1859 return *value_handle;
1860}
1861
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001863void JSObject::LookupCallbackSetterInPrototypes(String* name,
1864 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001865 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001866 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001867 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001868 pt = pt->GetPrototype()) {
1869 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00001870 if (result->IsProperty()) {
1871 if (result->IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 result->NotFound();
1873 return;
1874 }
1875 if (result->type() == CALLBACKS) {
1876 return;
1877 }
1878 }
1879 }
1880 result->NotFound();
1881}
1882
1883
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001884MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1885 uint32_t index,
1886 Object* value,
1887 bool* found,
1888 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001890 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001891 pt != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001892 pt = pt->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001893 if (!JSObject::cast(pt)->HasDictionaryElements()) {
1894 continue;
1895 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00001896 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1897 int entry = dictionary->FindEntry(index);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001898 if (entry != NumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001899 PropertyDetails details = dictionary->DetailsAt(entry);
1900 if (details.type() == CALLBACKS) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001901 *found = true;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00001902 return SetElementWithCallback(dictionary->ValueAt(entry),
1903 index,
1904 value,
1905 JSObject::cast(pt),
1906 strict_mode);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001907 }
1908 }
1909 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001910 *found = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 return heap->the_hole_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001912}
1913
1914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001915void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1916 DescriptorArray* descriptors = map()->instance_descriptors();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001917 int number = descriptors->SearchWithCache(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001918 if (number != DescriptorArray::kNotFound) {
1919 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1920 } else {
1921 result->NotFound();
1922 }
1923}
1924
1925
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001926void Map::LookupInDescriptors(JSObject* holder,
1927 String* name,
1928 LookupResult* result) {
1929 DescriptorArray* descriptors = instance_descriptors();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001930 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1931 int number = cache->Lookup(descriptors, name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001932 if (number == DescriptorLookupCache::kAbsent) {
1933 number = descriptors->Search(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 cache->Update(descriptors, name, number);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001935 }
1936 if (number != DescriptorArray::kNotFound) {
1937 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1938 } else {
1939 result->NotFound();
1940 }
1941}
1942
1943
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001944MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
1945 bool safe_to_add_transition) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001946 Heap* current_heap = heap();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001947 DescriptorArray* descriptors = instance_descriptors();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948 String* external_array_sentinel_name = current_heap->empty_symbol();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001949
1950 if (safe_to_add_transition) {
1951 // It's only safe to manipulate the descriptor array if it would be
1952 // safe to add a transition.
1953
1954 ASSERT(!is_shared()); // no transitions can be added to shared maps.
1955 // Check if the external array transition already exists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956 DescriptorLookupCache* cache =
1957 current_heap->isolate()->descriptor_lookup_cache();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001958 int index = cache->Lookup(descriptors, external_array_sentinel_name);
1959 if (index == DescriptorLookupCache::kAbsent) {
1960 index = descriptors->Search(external_array_sentinel_name);
1961 cache->Update(descriptors,
1962 external_array_sentinel_name,
1963 index);
1964 }
1965
1966 // If the transition already exists, check the type. If there is a match,
1967 // return it.
1968 if (index != DescriptorArray::kNotFound) {
1969 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
1970 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
1971 details.array_type() == array_type) {
1972 return descriptors->GetValue(index);
1973 } else {
1974 safe_to_add_transition = false;
1975 }
1976 }
1977 }
1978
1979 // No transition to an existing external array map. Make a new one.
1980 Object* obj;
1981 { MaybeObject* maybe_map = CopyDropTransitions();
1982 if (!maybe_map->ToObject(&obj)) return maybe_map;
1983 }
1984 Map* new_map = Map::cast(obj);
1985
1986 new_map->set_has_fast_elements(false);
1987 new_map->set_has_external_array_elements(true);
1988 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
1989
1990 // Only remember the map transition if the object's map is NOT equal to the
1991 // global object_function's map and there is not an already existing
1992 // non-matching external array transition.
1993 bool allow_map_transition =
1994 safe_to_add_transition &&
1995 (GetIsolate()->context()->global_context()->object_function()->map() !=
1996 map());
1997 if (allow_map_transition) {
1998 // Allocate new instance descriptors for the old map with map transition.
1999 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
2000 Map::cast(new_map),
2001 array_type);
2002 Object* new_descriptors;
2003 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2004 &desc,
2005 KEEP_TRANSITIONS);
2006 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2007 return maybe_new_descriptors;
2008 }
2009 descriptors = DescriptorArray::cast(new_descriptors);
2010 set_instance_descriptors(descriptors);
2011 }
2012
2013 return new_map;
2014}
2015
2016
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017void JSObject::LocalLookupRealNamedProperty(String* name,
2018 LookupResult* result) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002019 if (IsJSGlobalProxy()) {
2020 Object* proto = GetPrototype();
2021 if (proto->IsNull()) return result->NotFound();
2022 ASSERT(proto->IsJSGlobalObject());
2023 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2024 }
2025
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026 if (HasFastProperties()) {
2027 LookupInDescriptor(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002028 if (result->IsFound()) {
2029 // A property, a map transition or a null descriptor was found.
2030 // We return all of these result types because
2031 // LocalLookupRealNamedProperty is used when setting properties
2032 // where map transitions and null descriptors are handled.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033 ASSERT(result->holder() == this && result->type() != NORMAL);
2034 // Disallow caching for uninitialized constants. These can only
2035 // occur as fields.
2036 if (result->IsReadOnly() && result->type() == FIELD &&
ager@chromium.org7c537e22008-10-16 08:43:32 +00002037 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002038 result->DisallowCaching();
2039 }
2040 return;
2041 }
2042 } else {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002043 int entry = property_dictionary()->FindEntry(name);
2044 if (entry != StringDictionary::kNotFound) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002045 Object* value = property_dictionary()->ValueAt(entry);
2046 if (IsGlobalObject()) {
2047 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2048 if (d.IsDeleted()) {
2049 result->NotFound();
2050 return;
2051 }
2052 value = JSGlobalPropertyCell::cast(value)->value();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002053 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002054 // Make sure to disallow caching for uninitialized constants
2055 // found in the dictionary-mode objects.
2056 if (value->IsTheHole()) result->DisallowCaching();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002057 result->DictionaryResult(this, entry);
2058 return;
2059 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 }
2061 result->NotFound();
2062}
2063
2064
2065void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2066 LocalLookupRealNamedProperty(name, result);
2067 if (result->IsProperty()) return;
2068
2069 LookupRealNamedPropertyInPrototypes(name, result);
2070}
2071
2072
2073void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2074 LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002075 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076 for (Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002077 pt != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002078 pt = JSObject::cast(pt)->GetPrototype()) {
2079 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002080 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002081 }
2082 result->NotFound();
2083}
2084
2085
2086// We only need to deal with CALLBACKS and INTERCEPTORS
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002087MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2088 LookupResult* result,
2089 String* name,
2090 Object* value,
2091 bool check_prototype,
2092 StrictModeFlag strict_mode) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002093 if (check_prototype && !result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002094 LookupCallbackSetterInPrototypes(name, result);
2095 }
2096
2097 if (result->IsProperty()) {
2098 if (!result->IsReadOnly()) {
2099 switch (result->type()) {
2100 case CALLBACKS: {
2101 Object* obj = result->GetCallbackObject();
2102 if (obj->IsAccessorInfo()) {
2103 AccessorInfo* info = AccessorInfo::cast(obj);
2104 if (info->all_can_write()) {
2105 return SetPropertyWithCallback(result->GetCallbackObject(),
2106 name,
2107 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002108 result->holder(),
2109 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110 }
2111 }
2112 break;
2113 }
2114 case INTERCEPTOR: {
2115 // Try lookup real named properties. Note that only property can be
2116 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2117 LookupResult r;
2118 LookupRealNamedProperty(name, &r);
2119 if (r.IsProperty()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002120 return SetPropertyWithFailedAccessCheck(&r,
2121 name,
2122 value,
2123 check_prototype,
2124 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002125 }
2126 break;
2127 }
2128 default: {
2129 break;
2130 }
2131 }
2132 }
2133 }
2134
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002135 HandleScope scope;
2136 Handle<Object> value_handle(value);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002137 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002138 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002139 return *value_handle;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002140}
2141
2142
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002143MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2144 String* key,
2145 Object* value,
2146 PropertyAttributes attributes,
2147 StrictModeFlag strict_mode) {
2148 if (result->IsFound() && result->type() == HANDLER) {
2149 return JSProxy::cast(this)->SetPropertyWithHandler(
2150 key, value, attributes, strict_mode);
2151 } else {
2152 return JSObject::cast(this)->SetPropertyForResult(
2153 result, key, value, attributes, strict_mode);
2154 }
2155}
2156
2157
2158MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2159 String* name_raw,
2160 Object* value_raw,
2161 PropertyAttributes attributes,
2162 StrictModeFlag strict_mode) {
2163 Isolate* isolate = GetIsolate();
2164 HandleScope scope;
2165 Handle<Object> receiver(this);
2166 Handle<Object> name(name_raw);
2167 Handle<Object> value(value_raw);
2168 Handle<Object> handler(this->handler());
2169
2170 // Extract trap function.
2171 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2172 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2173 if (trap->IsUndefined()) {
2174 trap = isolate->derived_set_trap();
2175 }
2176
2177 // Call trap function.
2178 Object** args[] = {
2179 receiver.location(), name.location(), value.location()
2180 };
2181 bool has_exception;
2182 Handle<Object> result =
2183 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2184 if (has_exception) return Failure::Exception();
2185
2186 return value_raw;
2187}
2188
2189
2190MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2191 JSReceiver* receiver_raw,
2192 String* name_raw,
2193 bool* has_exception) {
2194 Isolate* isolate = GetIsolate();
2195 HandleScope scope;
2196 Handle<JSReceiver> receiver(receiver_raw);
2197 Handle<Object> name(name_raw);
2198 Handle<Object> handler(this->handler());
2199
2200 // Extract trap function.
2201 Handle<String> trap_name =
2202 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2203 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2204 if (trap->IsUndefined()) {
2205 Handle<Object> args[] = { handler, trap_name };
2206 Handle<Object> error = isolate->factory()->NewTypeError(
2207 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2208 isolate->Throw(*error);
2209 *has_exception = true;
2210 return NONE;
2211 }
2212
2213 // Call trap function.
2214 Object** args[] = { name.location() };
2215 Handle<Object> result =
2216 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2217 if (has_exception) return NONE;
2218
2219 // TODO(rossberg): convert result to PropertyAttributes
2220 USE(result);
2221 return NONE;
2222}
2223
2224
2225MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002226 String* name,
2227 Object* value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002228 PropertyAttributes attributes,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002229 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002230 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002231 // Make sure that the top context does not change when doing callbacks or
2232 // interceptor calls.
2233 AssertNoContextChange ncc;
2234
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002235 // Optimization for 2-byte strings often used as keys in a decompression
2236 // dictionary. We make these short keys into symbols to avoid constantly
2237 // reallocating them.
2238 if (!name->IsSymbol() && name->length() <= 2) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002239 Object* symbol_version;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002240 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002241 if (maybe_symbol_version->ToObject(&symbol_version)) {
2242 name = String::cast(symbol_version);
2243 }
2244 }
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002245 }
2246
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 // Check access rights if needed.
2248 if (IsAccessCheckNeeded()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002250 return SetPropertyWithFailedAccessCheck(result,
2251 name,
2252 value,
2253 true,
2254 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002256
2257 if (IsJSGlobalProxy()) {
2258 Object* proto = GetPrototype();
2259 if (proto->IsNull()) return value;
2260 ASSERT(proto->IsJSGlobalObject());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002261 return JSObject::cast(proto)->SetProperty(
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002262 result, name, value, attributes, strict_mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002263 }
2264
ager@chromium.org32912102009-01-16 10:38:43 +00002265 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002266 // We could not find a local property so let's check whether there is an
2267 // accessor that wants to handle the property.
2268 LookupResult accessor_result;
2269 LookupCallbackSetterInPrototypes(name, &accessor_result);
ager@chromium.org5c838252010-02-19 08:53:10 +00002270 if (accessor_result.IsProperty()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002271 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2272 name,
2273 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002274 accessor_result.holder(),
2275 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002276 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002277 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002278 if (!result->IsFound()) {
2279 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002280 return AddProperty(name, value, attributes, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002281 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002282 if (result->IsReadOnly() && result->IsProperty()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002283 if (strict_mode == kStrictMode) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002284 HandleScope scope;
2285 Handle<String> key(name);
2286 Handle<Object> holder(this);
2287 Handle<Object> args[2] = { key, holder };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2289 "strict_read_only_property", HandleVector(args, 2)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002290 } else {
2291 return value;
2292 }
2293 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002294 // This is a real property that is not read-only, or it is a
2295 // transition or null descriptor and there are no setters in the prototypes.
2296 switch (result->type()) {
2297 case NORMAL:
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002298 return SetNormalizedProperty(result, value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002299 case FIELD:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002300 return FastPropertyAtPut(result->GetFieldIndex(), value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002301 case MAP_TRANSITION:
2302 if (attributes == result->GetAttributes()) {
2303 // Only use map transition if the attributes match.
2304 return AddFastPropertyUsingMap(result->GetTransitionMap(),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002305 name,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002306 value);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002307 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002308 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002309 case CONSTANT_FUNCTION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002310 // Only replace the function if necessary.
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002311 if (value == result->GetConstantFunction()) return value;
2312 // Preserve the attributes of this existing property.
2313 attributes = result->GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002314 return ConvertDescriptorToField(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002315 case CALLBACKS:
2316 return SetPropertyWithCallback(result->GetCallbackObject(),
2317 name,
2318 value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002319 result->holder(),
2320 strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002321 case INTERCEPTOR:
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00002322 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002323 case CONSTANT_TRANSITION: {
2324 // If the same constant function is being added we can simply
2325 // transition to the target map.
2326 Map* target_map = result->GetTransitionMap();
2327 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2328 int number = target_descriptors->SearchWithCache(name);
2329 ASSERT(number != DescriptorArray::kNotFound);
2330 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2331 JSFunction* function =
2332 JSFunction::cast(target_descriptors->GetValue(number));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002333 ASSERT(!HEAP->InNewSpace(function));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002334 if (value == function) {
2335 set_map(target_map);
2336 return value;
2337 }
2338 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2339 // FIELD, even if the value is a constant function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002340 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002341 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002342 case NULL_DESCRIPTOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002343 case EXTERNAL_ARRAY_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002344 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002345 default:
2346 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002347 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002348 UNREACHABLE();
2349 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002350}
2351
2352
2353// Set a real local property, even if it is READ_ONLY. If the property is not
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002354// present, add it with attributes NONE. This code is an exact clone of
2355// SetProperty, with the check for IsReadOnly and the check for a
2356// callback setter removed. The two lines looking up the LookupResult
2357// result are also added. If one of the functions is changed, the other
2358// should be.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002359MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002360 String* name,
2361 Object* value,
2362 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002363
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002364 // Make sure that the top context does not change when doing callbacks or
2365 // interceptor calls.
2366 AssertNoContextChange ncc;
ager@chromium.org5c838252010-02-19 08:53:10 +00002367 LookupResult result;
2368 LocalLookup(name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002369 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002370 if (IsAccessCheckNeeded()) {
2371 Heap* heap = GetHeap();
2372 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00002373 return SetPropertyWithFailedAccessCheck(&result,
2374 name,
2375 value,
2376 false,
2377 kNonStrictMode);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002378 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002379 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002380
2381 if (IsJSGlobalProxy()) {
2382 Object* proto = GetPrototype();
2383 if (proto->IsNull()) return value;
2384 ASSERT(proto->IsJSGlobalObject());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002385 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002386 name,
2387 value,
2388 attributes);
2389 }
2390
ager@chromium.org7c537e22008-10-16 08:43:32 +00002391 // Check for accessor in prototype chain removed here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002392 if (!result.IsFound()) {
2393 // Neither properties nor transitions found.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002394 return AddProperty(name, value, attributes, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002395 }
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002396
ager@chromium.org5c838252010-02-19 08:53:10 +00002397 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2398
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002399 // Check of IsReadOnly removed from here in clone.
ager@chromium.org5c838252010-02-19 08:53:10 +00002400 switch (result.type()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002401 case NORMAL:
ager@chromium.org5c838252010-02-19 08:53:10 +00002402 return SetNormalizedProperty(name, value, details);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002403 case FIELD:
ager@chromium.org5c838252010-02-19 08:53:10 +00002404 return FastPropertyAtPut(result.GetFieldIndex(), value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002405 case MAP_TRANSITION:
ager@chromium.org5c838252010-02-19 08:53:10 +00002406 if (attributes == result.GetAttributes()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002407 // Only use map transition if the attributes match.
ager@chromium.org5c838252010-02-19 08:53:10 +00002408 return AddFastPropertyUsingMap(result.GetTransitionMap(),
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002409 name,
2410 value);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002411 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002412 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002413 case CONSTANT_FUNCTION:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002414 // Only replace the function if necessary.
ager@chromium.org5c838252010-02-19 08:53:10 +00002415 if (value == result.GetConstantFunction()) return value;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00002416 // Preserve the attributes of this existing property.
ager@chromium.org5c838252010-02-19 08:53:10 +00002417 attributes = result.GetAttributes();
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00002418 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002419 case CALLBACKS:
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002420 case INTERCEPTOR:
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002421 // Override callback in clone
2422 return ConvertDescriptorToField(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002423 case CONSTANT_TRANSITION:
2424 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2425 // if the value is a function.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002426 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002427 case NULL_DESCRIPTOR:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002428 case EXTERNAL_ARRAY_TRANSITION:
ager@chromium.org7c537e22008-10-16 08:43:32 +00002429 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002430 default:
2431 UNREACHABLE();
2432 }
2433 UNREACHABLE();
2434 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002435}
2436
2437
2438PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2439 JSObject* receiver,
2440 String* name,
2441 bool continue_search) {
2442 // Check local property, ignore interceptor.
2443 LookupResult result;
2444 LocalLookupRealNamedProperty(name, &result);
kasper.lund44510672008-07-25 07:37:58 +00002445 if (result.IsProperty()) return result.GetAttributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002446
2447 if (continue_search) {
2448 // Continue searching via the prototype chain.
2449 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002450 if (!pt->IsNull()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002451 return JSObject::cast(pt)->
2452 GetPropertyAttributeWithReceiver(receiver, name);
2453 }
2454 }
2455 return ABSENT;
2456}
2457
2458
2459PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2460 JSObject* receiver,
2461 String* name,
2462 bool continue_search) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002463 Isolate* isolate = GetIsolate();
2464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002465 // Make sure that the top context does not change when doing
2466 // callbacks or interceptor calls.
2467 AssertNoContextChange ncc;
2468
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002469 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002470 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2471 Handle<JSObject> receiver_handle(receiver);
2472 Handle<JSObject> holder_handle(this);
2473 Handle<String> name_handle(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002474 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002475 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002476 if (!interceptor->query()->IsUndefined()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002477 v8::NamedPropertyQuery query =
2478 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002479 LOG(isolate,
2480 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002481 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002482 {
2483 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002484 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002485 result = query(v8::Utils::ToLocal(name_handle), info);
2486 }
2487 if (!result.IsEmpty()) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002488 ASSERT(result->IsInt32());
2489 return static_cast<PropertyAttributes>(result->Int32Value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002490 }
2491 } else if (!interceptor->getter()->IsUndefined()) {
2492 v8::NamedPropertyGetter getter =
2493 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002494 LOG(isolate,
2495 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496 v8::Handle<v8::Value> result;
2497 {
2498 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002499 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002500 result = getter(v8::Utils::ToLocal(name_handle), info);
2501 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002502 if (!result.IsEmpty()) return DONT_ENUM;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002503 }
2504 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2505 *name_handle,
2506 continue_search);
2507}
2508
2509
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002510PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2511 JSReceiver* receiver,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002512 String* key) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002513 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002514 if (IsJSObject() && key->AsArrayIndex(&index)) {
2515 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2516 return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002517 return ABSENT;
2518 }
2519 // Named property.
2520 LookupResult result;
2521 Lookup(key, &result);
2522 return GetPropertyAttribute(receiver, &result, key, true);
2523}
2524
2525
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002526PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2527 LookupResult* result,
2528 String* name,
2529 bool continue_search) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002530 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002531 if (IsAccessCheckNeeded()) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002532 JSObject* this_obj = JSObject::cast(this);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002533 Heap* heap = GetHeap();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002534 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2535 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2536 receiver, result, name, continue_search);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002537 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002538 }
ager@chromium.org5c838252010-02-19 08:53:10 +00002539 if (result->IsProperty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002540 switch (result->type()) {
2541 case NORMAL: // fall through
2542 case FIELD:
2543 case CONSTANT_FUNCTION:
2544 case CALLBACKS:
2545 return result->GetAttributes();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002546 case HANDLER: {
2547 // TODO(rossberg): propagate exceptions properly.
2548 bool has_exception = false;
2549 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2550 receiver, name, &has_exception);
2551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002552 case INTERCEPTOR:
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002553 return result->holder()->GetPropertyAttributeWithInterceptor(
2554 JSObject::cast(receiver), name, continue_search);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002555 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002556 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002557 }
2558 }
2559 return ABSENT;
2560}
2561
2562
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002563PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002564 // Check whether the name is an array index.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002565 uint32_t index = 0;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002566 if (IsJSObject() && name->AsArrayIndex(&index)) {
2567 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002568 return ABSENT;
2569 }
2570 // Named property.
2571 LookupResult result;
2572 LocalLookup(name, &result);
2573 return GetPropertyAttribute(this, &result, name, false);
2574}
2575
2576
lrn@chromium.org303ada72010-10-27 09:33:13 +00002577MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2578 PropertyNormalizationMode mode) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002579 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002580 Map* fast = obj->map();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002581 int index = Hash(fast) % kEntries;
2582 Object* result = get(index);
2583 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002584#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002585 if (FLAG_enable_slow_asserts) {
2586 // The cached map should match newly created normalized map bit-by-bit.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002587 Object* fresh;
2588 { MaybeObject* maybe_fresh =
2589 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2590 if (maybe_fresh->ToObject(&fresh)) {
2591 ASSERT(memcmp(Map::cast(fresh)->address(),
2592 Map::cast(result)->address(),
2593 Map::kSize) == 0);
2594 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002595 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00002596 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002597#endif
2598 return result;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002599 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002600
lrn@chromium.org303ada72010-10-27 09:33:13 +00002601 { MaybeObject* maybe_result =
2602 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2603 if (!maybe_result->ToObject(&result)) return maybe_result;
2604 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002605 set(index, result);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002606 isolate->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002607
2608 return result;
2609}
2610
2611
ricow@chromium.org65fae842010-08-25 15:26:24 +00002612void NormalizedMapCache::Clear() {
2613 int entries = length();
2614 for (int i = 0; i != entries; i++) {
2615 set_undefined(i);
2616 }
2617}
2618
2619
2620int NormalizedMapCache::Hash(Map* fast) {
2621 // For performance reasons we only hash the 3 most variable fields of a map:
2622 // constructor, prototype and bit_field2.
2623
2624 // Shift away the tag.
2625 int hash = (static_cast<uint32_t>(
2626 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2);
2627
2628 // XOR-ing the prototype and constructor directly yields too many zero bits
2629 // when the two pointers are close (which is fairly common).
2630 // To avoid this we shift the prototype 4 bits relatively to the constructor.
2631 hash ^= (static_cast<uint32_t>(
2632 reinterpret_cast<uintptr_t>(fast->prototype())) << 2);
2633
2634 return hash ^ (hash >> 16) ^ fast->bit_field2();
2635}
2636
2637
2638bool NormalizedMapCache::CheckHit(Map* slow,
2639 Map* fast,
2640 PropertyNormalizationMode mode) {
2641#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002642 slow->SharedMapVerify();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002643#endif
2644 return
2645 slow->constructor() == fast->constructor() &&
2646 slow->prototype() == fast->prototype() &&
2647 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
2648 0 :
2649 fast->inobject_properties()) &&
2650 slow->instance_type() == fast->instance_type() &&
2651 slow->bit_field() == fast->bit_field() &&
danno@chromium.org40cb8782011-05-25 07:58:50 +00002652 slow->bit_field2() == fast->bit_field2() &&
2653 (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002654}
2655
2656
lrn@chromium.org303ada72010-10-27 09:33:13 +00002657MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002658 if (map()->is_shared()) {
2659 // Fast case maps are never marked as shared.
2660 ASSERT(!HasFastProperties());
2661 // Replace the map with an identical copy that can be safely modified.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002662 Object* obj;
2663 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2664 UNIQUE_NORMALIZED_MAP);
2665 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2666 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002667 GetIsolate()->counters()->normalized_maps()->Increment();
ricow@chromium.org65fae842010-08-25 15:26:24 +00002668
2669 set_map(Map::cast(obj));
2670 }
2671 return map()->UpdateCodeCache(name, code);
2672}
2673
2674
lrn@chromium.org303ada72010-10-27 09:33:13 +00002675MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2676 int expected_additional_properties) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677 if (!HasFastProperties()) return this;
2678
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002679 // The global object is always normalized.
2680 ASSERT(!IsGlobalObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00002681 // JSGlobalProxy must never be normalized
2682 ASSERT(!IsJSGlobalProxy());
2683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002684 Map* map_of_this = map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002685
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002686 // Allocate new content.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002687 int property_count = map_of_this->NumberOfDescribedProperties();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002688 if (expected_additional_properties > 0) {
2689 property_count += expected_additional_properties;
2690 } else {
2691 property_count += 2; // Make space for two more properties.
2692 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002693 Object* obj;
2694 { MaybeObject* maybe_obj =
2695 StringDictionary::Allocate(property_count);
2696 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2697 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002698 StringDictionary* dictionary = StringDictionary::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002700 DescriptorArray* descs = map_of_this->instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002701 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002702 PropertyDetails details(descs->GetDetails(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 switch (details.type()) {
2704 case CONSTANT_FUNCTION: {
2705 PropertyDetails d =
2706 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002707 Object* value = descs->GetConstantFunction(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002708 Object* result;
2709 { MaybeObject* maybe_result =
2710 dictionary->Add(descs->GetKey(i), value, d);
2711 if (!maybe_result->ToObject(&result)) return maybe_result;
2712 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002713 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002714 break;
2715 }
2716 case FIELD: {
2717 PropertyDetails d =
2718 PropertyDetails(details.attributes(), NORMAL, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002719 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
lrn@chromium.org303ada72010-10-27 09:33:13 +00002720 Object* result;
2721 { MaybeObject* maybe_result =
2722 dictionary->Add(descs->GetKey(i), value, d);
2723 if (!maybe_result->ToObject(&result)) return maybe_result;
2724 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002725 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002726 break;
2727 }
2728 case CALLBACKS: {
2729 PropertyDetails d =
2730 PropertyDetails(details.attributes(), CALLBACKS, details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00002731 Object* value = descs->GetCallbacksObject(i);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002732 Object* result;
2733 { MaybeObject* maybe_result =
2734 dictionary->Add(descs->GetKey(i), value, d);
2735 if (!maybe_result->ToObject(&result)) return maybe_result;
2736 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002737 dictionary = StringDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738 break;
2739 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002740 case MAP_TRANSITION:
2741 case CONSTANT_TRANSITION:
2742 case NULL_DESCRIPTOR:
2743 case INTERCEPTOR:
karlklose@chromium.org83a47282011-05-11 11:54:09 +00002744 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002745 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002746 default:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002747 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002748 }
2749 }
2750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002751 Heap* current_heap = map_of_this->heap();
2752
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002753 // Copy the next enumeration index from instance descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002754 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755 dictionary->SetNextEnumerationIndex(index);
2756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002757 { MaybeObject* maybe_obj =
2758 current_heap->isolate()->context()->global_context()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002759 normalized_map_cache()->Get(this, mode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002760 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2761 }
ager@chromium.org32912102009-01-16 10:38:43 +00002762 Map* new_map = Map::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002763
ager@chromium.org32912102009-01-16 10:38:43 +00002764 // We have now successfully allocated all the necessary objects.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002765 // Changes can now be made with the guarantee that all of them take effect.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002766
2767 // Resize the object in the heap if necessary.
2768 int new_instance_size = new_map->instance_size();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002769 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002770 ASSERT(instance_size_delta >= 0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002771 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2772 instance_size_delta);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002773
ager@chromium.org32912102009-01-16 10:38:43 +00002774 set_map(new_map);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002775 new_map->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002777 set_properties(dictionary);
2778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002779 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002780
2781#ifdef DEBUG
2782 if (FLAG_trace_normalization) {
2783 PrintF("Object properties have been normalized:\n");
2784 Print();
2785 }
2786#endif
2787 return this;
2788}
2789
2790
lrn@chromium.org303ada72010-10-27 09:33:13 +00002791MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002792 if (HasFastProperties()) return this;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002793 ASSERT(!IsGlobalObject());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794 return property_dictionary()->
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002795 TransformPropertiesToFastFor(this, unused_property_fields);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796}
2797
2798
lrn@chromium.org303ada72010-10-27 09:33:13 +00002799MaybeObject* JSObject::NormalizeElements() {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002800 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002801 if (HasDictionaryElements()) return this;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002802 Map* old_map = map();
2803 ASSERT(old_map->has_fast_elements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002804
lrn@chromium.org303ada72010-10-27 09:33:13 +00002805 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002806 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00002807 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2808 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002809 Map* new_map = Map::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002810
2811 // Get number of entries.
2812 FixedArray* array = FixedArray::cast(elements());
2813
2814 // Compute the effective length.
2815 int length = IsJSArray() ?
2816 Smi::cast(JSArray::cast(this)->length())->value() :
2817 array->length();
lrn@chromium.org303ada72010-10-27 09:33:13 +00002818 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length);
2819 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2820 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002821 NumberDictionary* dictionary = NumberDictionary::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002822 // Copy entries.
2823 for (int i = 0; i < length; i++) {
2824 Object* value = array->get(i);
2825 if (!value->IsTheHole()) {
2826 PropertyDetails details = PropertyDetails(NONE, NORMAL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00002827 Object* result;
2828 { MaybeObject* maybe_result =
2829 dictionary->AddNumberEntry(i, array->get(i), details);
2830 if (!maybe_result->ToObject(&result)) return maybe_result;
2831 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00002832 dictionary = NumberDictionary::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002833 }
2834 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002835 // Switch to using the dictionary as the backing storage for
2836 // elements. Set the new map first to satify the elements type
2837 // assert in set_elements().
2838 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002839 set_elements(dictionary);
2840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002841 new_map->heap()->isolate()->counters()->elements_to_dictionary()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002842 Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002843
2844#ifdef DEBUG
2845 if (FLAG_trace_normalization) {
2846 PrintF("Object elements have been normalized:\n");
2847 Print();
2848 }
2849#endif
2850
2851 return this;
2852}
2853
2854
lrn@chromium.org303ada72010-10-27 09:33:13 +00002855MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
2856 DeleteMode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002857 // Check local property, ignore interceptor.
2858 LookupResult result;
2859 LocalLookupRealNamedProperty(name, &result);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002860 if (!result.IsProperty()) return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002861
2862 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002863 Object* obj;
2864 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2865 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2866 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002867
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002868 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869}
2870
2871
lrn@chromium.org303ada72010-10-27 09:33:13 +00002872MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002873 Isolate* isolate = GetIsolate();
2874 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002875 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2876 Handle<String> name_handle(name);
2877 Handle<JSObject> this_handle(this);
2878 if (!interceptor->deleter()->IsUndefined()) {
2879 v8::NamedPropertyDeleter deleter =
2880 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002881 LOG(isolate,
2882 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2883 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002884 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002885 v8::Handle<v8::Boolean> result;
2886 {
2887 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002888 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002889 result = deleter(v8::Utils::ToLocal(name_handle), info);
2890 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002891 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002892 if (!result.IsEmpty()) {
2893 ASSERT(result->IsBoolean());
2894 return *v8::Utils::OpenHandle(*result);
2895 }
2896 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002897 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00002898 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002899 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900 return raw_result;
2901}
2902
2903
lrn@chromium.org303ada72010-10-27 09:33:13 +00002904MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
2905 DeleteMode mode) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002906 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002907 switch (GetElementsKind()) {
2908 case FAST_ELEMENTS: {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002909 Object* obj;
2910 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2911 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2912 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002913 uint32_t length = IsJSArray() ?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002914 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2915 static_cast<uint32_t>(FixedArray::cast(elements())->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002916 if (index < length) {
2917 FixedArray::cast(elements())->set_the_hole(index);
2918 }
2919 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002920 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002921 case DICTIONARY_ELEMENTS: {
2922 NumberDictionary* dictionary = element_dictionary();
2923 int entry = dictionary->FindEntry(index);
2924 if (entry != NumberDictionary::kNotFound) {
2925 return dictionary->DeleteProperty(entry, mode);
2926 }
2927 break;
2928 }
2929 default:
2930 UNREACHABLE();
2931 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002932 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002933 return GetHeap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002934}
2935
2936
lrn@chromium.org303ada72010-10-27 09:33:13 +00002937MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002938 Isolate* isolate = GetIsolate();
2939 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002940 // Make sure that the top context does not change when doing
2941 // callbacks or interceptor calls.
2942 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002943 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002944 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002945 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002946 v8::IndexedPropertyDeleter deleter =
2947 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
2948 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002949 LOG(isolate,
2950 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
2951 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002952 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002953 v8::Handle<v8::Boolean> result;
2954 {
2955 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002956 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002957 result = deleter(index, info);
2958 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002959 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002960 if (!result.IsEmpty()) {
2961 ASSERT(result->IsBoolean());
2962 return *v8::Utils::OpenHandle(*result);
2963 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00002964 MaybeObject* raw_result =
ager@chromium.orge2902be2009-06-08 12:21:35 +00002965 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002966 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002967 return raw_result;
2968}
2969
2970
lrn@chromium.org303ada72010-10-27 09:33:13 +00002971MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002972 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002973 // Check access rights if needed.
2974 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002975 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
2976 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2977 return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002978 }
2979
2980 if (IsJSGlobalProxy()) {
2981 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002982 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002983 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00002984 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002985 }
2986
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002987 if (HasIndexedInterceptor()) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00002988 // Skip interceptor if forcing deletion.
2989 if (mode == FORCE_DELETION) {
2990 return DeleteElementPostInterceptor(index, mode);
2991 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002992 return DeleteElementWithInterceptor(index);
2993 }
2994
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002995 switch (GetElementsKind()) {
2996 case FAST_ELEMENTS: {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002997 Object* obj;
2998 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2999 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3000 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003001 uint32_t length = IsJSArray() ?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
3003 static_cast<uint32_t>(FixedArray::cast(elements())->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003004 if (index < length) {
3005 FixedArray::cast(elements())->set_the_hole(index);
3006 }
3007 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003008 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003009 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003010 case EXTERNAL_BYTE_ELEMENTS:
3011 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3012 case EXTERNAL_SHORT_ELEMENTS:
3013 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3014 case EXTERNAL_INT_ELEMENTS:
3015 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3016 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003017 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003018 // Pixel and external array elements cannot be deleted. Just
3019 // silently ignore here.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003020 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003021 case DICTIONARY_ELEMENTS: {
3022 NumberDictionary* dictionary = element_dictionary();
3023 int entry = dictionary->FindEntry(index);
3024 if (entry != NumberDictionary::kNotFound) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003025 Object* result = dictionary->DeleteProperty(entry, mode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003026 if (mode == STRICT_DELETION && result ==
3027 isolate->heap()->false_value()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003028 // In strict mode, deleting a non-configurable property throws
3029 // exception. dictionary->DeleteProperty will return false_value()
3030 // if a non-configurable property is being deleted.
3031 HandleScope scope;
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003032 Handle<Object> self(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003033 Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00003034 Handle<Object> args[2] = { i, self };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003035 return isolate->Throw(*isolate->factory()->NewTypeError(
3036 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003037 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003038 }
3039 break;
3040 }
3041 default:
3042 UNREACHABLE();
3043 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003044 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003045 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046}
3047
3048
lrn@chromium.org303ada72010-10-27 09:33:13 +00003049MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003051 // ECMA-262, 3rd, 8.6.2.5
3052 ASSERT(name->IsString());
3053
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003054 // Check access rights if needed.
3055 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003056 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3057 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3058 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059 }
3060
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003061 if (IsJSGlobalProxy()) {
3062 Object* proto = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003063 if (proto->IsNull()) return isolate->heap()->false_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003064 ASSERT(proto->IsJSGlobalObject());
ager@chromium.orge2902be2009-06-08 12:21:35 +00003065 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003066 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003067
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003068 uint32_t index = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003069 if (name->AsArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003070 return DeleteElement(index, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071 } else {
3072 LookupResult result;
3073 LocalLookup(name, &result);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003074 if (!result.IsProperty()) return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003075 // Ignore attributes if forcing a deletion.
3076 if (result.IsDontDelete() && mode != FORCE_DELETION) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003077 if (mode == STRICT_DELETION) {
3078 // Deleting a non-configurable property in strict mode.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003079 HandleScope scope(isolate);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003080 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 return isolate->Throw(*isolate->factory()->NewTypeError(
3082 "strict_delete_property", HandleVector(args, 2)));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003083 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003084 return isolate->heap()->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00003085 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086 // Check for interceptor.
3087 if (result.type() == INTERCEPTOR) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00003088 // Skip interceptor if forcing a deletion.
3089 if (mode == FORCE_DELETION) {
3090 return DeletePropertyPostInterceptor(name, mode);
3091 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003092 return DeletePropertyWithInterceptor(name);
3093 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003094 // Normalize object if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003095 Object* obj;
3096 { MaybeObject* maybe_obj =
3097 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3098 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3099 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003100 // Make sure the properties are normalized before removing the entry.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003101 return DeleteNormalizedProperty(name, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003102 }
3103}
3104
3105
3106// Check whether this object references another object.
3107bool JSObject::ReferencesObject(Object* obj) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003108 Map* map_of_this = map();
3109 Heap* heap = map_of_this->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003110 AssertNoAllocation no_alloc;
3111
3112 // Is the object the constructor for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003113 if (map_of_this->constructor() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003114 return true;
3115 }
3116
3117 // Is the object the prototype for this object?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003118 if (map_of_this->prototype() == obj) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003119 return true;
3120 }
3121
3122 // Check if the object is among the named properties.
3123 Object* key = SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003124 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003125 return true;
3126 }
3127
3128 // Check if the object is among the indexed properties.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003129 switch (GetElementsKind()) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003130 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003131 case EXTERNAL_BYTE_ELEMENTS:
3132 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3133 case EXTERNAL_SHORT_ELEMENTS:
3134 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3135 case EXTERNAL_INT_ELEMENTS:
3136 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3137 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003138 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003139 // Raw pixels and external arrays do not reference other
3140 // objects.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003141 break;
3142 case FAST_ELEMENTS: {
3143 int length = IsJSArray() ?
3144 Smi::cast(JSArray::cast(this)->length())->value() :
3145 FixedArray::cast(elements())->length();
3146 for (int i = 0; i < length; i++) {
3147 Object* element = FixedArray::cast(elements())->get(i);
3148 if (!element->IsTheHole() && element == obj) {
3149 return true;
3150 }
3151 }
3152 break;
3153 }
3154 case DICTIONARY_ELEMENTS: {
3155 key = element_dictionary()->SlowReverseLookup(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003156 if (!key->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003157 return true;
3158 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003159 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003160 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003161 default:
3162 UNREACHABLE();
3163 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003164 }
3165
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00003166 // For functions check the context.
3167 if (IsJSFunction()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003168 // Get the constructor function for arguments array.
3169 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003170 heap->isolate()->context()->global_context()->
3171 arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003172 JSFunction* arguments_function =
3173 JSFunction::cast(arguments_boilerplate->map()->constructor());
3174
3175 // Get the context and don't check if it is the global context.
3176 JSFunction* f = JSFunction::cast(this);
3177 Context* context = f->context();
3178 if (context->IsGlobalContext()) {
3179 return false;
3180 }
3181
3182 // Check the non-special context slots.
3183 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3184 // Only check JS objects.
3185 if (context->get(i)->IsJSObject()) {
3186 JSObject* ctxobj = JSObject::cast(context->get(i));
3187 // If it is an arguments array check the content.
3188 if (ctxobj->map()->constructor() == arguments_function) {
3189 if (ctxobj->ReferencesObject(obj)) {
3190 return true;
3191 }
3192 } else if (ctxobj == obj) {
3193 return true;
3194 }
3195 }
3196 }
3197
3198 // Check the context extension if any.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003199 if (context->has_extension()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003200 return context->extension()->ReferencesObject(obj);
3201 }
3202 }
3203
3204 // No references to object.
3205 return false;
3206}
3207
3208
lrn@chromium.org303ada72010-10-27 09:33:13 +00003209MaybeObject* JSObject::PreventExtensions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 Isolate* isolate = GetIsolate();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003211 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003212 !isolate->MayNamedAccess(this,
3213 isolate->heap()->undefined_value(),
3214 v8::ACCESS_KEYS)) {
3215 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3216 return isolate->heap()->false_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003217 }
3218
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003219 if (IsJSGlobalProxy()) {
3220 Object* proto = GetPrototype();
3221 if (proto->IsNull()) return this;
3222 ASSERT(proto->IsJSGlobalObject());
3223 return JSObject::cast(proto)->PreventExtensions();
3224 }
3225
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003226 // If there are fast elements we normalize.
3227 if (HasFastElements()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003228 Object* ok;
3229 { MaybeObject* maybe_ok = NormalizeElements();
3230 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3231 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003232 }
3233 // Make sure that we never go back to fast case.
3234 element_dictionary()->set_requires_slow_elements();
3235
3236 // Do a map transition, other objects with this map may still
3237 // be extensible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003238 Object* new_map;
3239 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
3240 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3241 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003242 Map::cast(new_map)->set_is_extensible(false);
3243 set_map(Map::cast(new_map));
3244 ASSERT(!map()->is_extensible());
3245 return new_map;
3246}
3247
3248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003249// Tests for the fast common case for property enumeration:
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003250// - This object and all prototypes has an enum cache (which means that it has
3251// no interceptors and needs no access checks).
3252// - This object has no elements.
3253// - No prototype has enumerable properties/elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003254bool JSObject::IsSimpleEnum() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003255 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003256 for (Object* o = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003257 o != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003258 o = JSObject::cast(o)->GetPrototype()) {
3259 JSObject* curr = JSObject::cast(o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003260 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003261 ASSERT(!curr->HasNamedInterceptor());
3262 ASSERT(!curr->HasIndexedInterceptor());
3263 ASSERT(!curr->IsAccessCheckNeeded());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003264 if (curr->NumberOfEnumElements() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003265 if (curr != this) {
3266 FixedArray* curr_fixed_array =
3267 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00003268 if (curr_fixed_array->length() > 0) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003269 }
3270 }
3271 return true;
3272}
3273
3274
3275int Map::NumberOfDescribedProperties() {
3276 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003277 DescriptorArray* descs = instance_descriptors();
3278 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3279 if (descs->IsProperty(i)) result++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280 }
3281 return result;
3282}
3283
3284
3285int Map::PropertyIndexFor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003286 DescriptorArray* descs = instance_descriptors();
3287 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3288 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3289 return descs->GetFieldIndex(i);
3290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003291 }
3292 return -1;
3293}
3294
3295
3296int Map::NextFreePropertyIndex() {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003297 int max_index = -1;
3298 DescriptorArray* descs = instance_descriptors();
3299 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3300 if (descs->GetType(i) == FIELD) {
3301 int current_index = descs->GetFieldIndex(i);
3302 if (current_index > max_index) max_index = current_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003303 }
3304 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003305 return max_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003306}
3307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308
3309AccessorDescriptor* Map::FindAccessor(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003310 DescriptorArray* descs = instance_descriptors();
3311 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3312 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3313 return descs->GetCallbacks(i);
3314 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003315 }
3316 return NULL;
3317}
3318
3319
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003320void JSReceiver::LocalLookup(String* name, LookupResult* result) {
3321 if (IsJSProxy()) {
3322 result->HandlerResult();
3323 } else {
3324 JSObject::cast(this)->LocalLookup(name, result);
3325 }
3326}
3327
3328
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003329void JSObject::LocalLookup(String* name, LookupResult* result) {
3330 ASSERT(name->IsString());
3331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003332 Heap* heap = GetHeap();
3333
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003334 if (IsJSGlobalProxy()) {
3335 Object* proto = GetPrototype();
3336 if (proto->IsNull()) return result->NotFound();
3337 ASSERT(proto->IsJSGlobalObject());
3338 return JSObject::cast(proto)->LocalLookup(name, result);
3339 }
3340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003341 // Do not use inline caching if the object is a non-global object
3342 // that requires access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003343 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344 result->DisallowCaching();
3345 }
3346
3347 // Check __proto__ before interceptor.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003348 if (name->Equals(heap->Proto_symbol()) &&
3349 !IsJSContextExtensionObject()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350 result->ConstantResult(this);
3351 return;
3352 }
3353
3354 // Check for lookup interceptor except when bootstrapping.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003355 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003356 result->InterceptorResult(this);
3357 return;
3358 }
3359
3360 LocalLookupRealNamedProperty(name, result);
3361}
3362
3363
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003364void JSReceiver::Lookup(String* name, LookupResult* result) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003365 // Ecma-262 3rd 8.6.2.4
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003366 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003367 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 current != heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003369 current = JSObject::cast(current)->GetPrototype()) {
3370 JSObject::cast(current)->LocalLookup(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003371 if (result->IsProperty()) return;
ager@chromium.org870a0b62008-11-04 11:43:05 +00003372 }
3373 result->NotFound();
3374}
3375
3376
3377// Search object and it's prototype chain for callback properties.
3378void JSObject::LookupCallback(String* name, LookupResult* result) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003379 Heap* heap = GetHeap();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003380 for (Object* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003381 current != heap->null_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003382 current = JSObject::cast(current)->GetPrototype()) {
3383 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003384 if (result->IsProperty() && result->type() == CALLBACKS) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385 }
3386 result->NotFound();
3387}
3388
3389
lrn@chromium.org303ada72010-10-27 09:33:13 +00003390MaybeObject* JSObject::DefineGetterSetter(String* name,
3391 PropertyAttributes attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003392 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003393 // Make sure that the top context does not change when doing callbacks or
3394 // interceptor calls.
3395 AssertNoContextChange ncc;
3396
ager@chromium.orgddb913d2009-01-27 10:01:48 +00003397 // Try to flatten before operating on the string.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003398 name->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003399
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003400 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003401 return heap->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003402 }
3403
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003404 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003405 bool is_element = name->AsArrayIndex(&index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003406
3407 if (is_element) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003408 switch (GetElementsKind()) {
3409 case FAST_ELEMENTS:
3410 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003411 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003412 case EXTERNAL_BYTE_ELEMENTS:
3413 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3414 case EXTERNAL_SHORT_ELEMENTS:
3415 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3416 case EXTERNAL_INT_ELEMENTS:
3417 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3418 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003419 case EXTERNAL_DOUBLE_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00003420 // Ignore getters and setters on pixel and external array
3421 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003422 return heap->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003423 case DICTIONARY_ELEMENTS: {
3424 // Lookup the index.
3425 NumberDictionary* dictionary = element_dictionary();
3426 int entry = dictionary->FindEntry(index);
3427 if (entry != NumberDictionary::kNotFound) {
3428 Object* result = dictionary->ValueAt(entry);
3429 PropertyDetails details = dictionary->DetailsAt(entry);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003430 if (details.IsReadOnly()) return heap->undefined_value();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003431 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003432 if (result->IsFixedArray()) {
3433 return result;
3434 }
3435 // Otherwise allow to override it.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003436 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003437 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003438 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003439 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003440 default:
3441 UNREACHABLE();
3442 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003443 }
3444 } else {
3445 // Lookup the name.
3446 LookupResult result;
3447 LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003448 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003449 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003450 if (result.type() == CALLBACKS) {
3451 Object* obj = result.GetCallbackObject();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003452 // Need to preserve old getters/setters.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003453 if (obj->IsFixedArray()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003454 // Use set to update attributes.
3455 return SetPropertyCallback(name, obj, attributes);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003456 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003457 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003458 }
3459 }
3460
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 // Allocate the fixed array to hold getter and setter.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003462 Object* structure;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003463 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003464 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003467 if (is_element) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003468 return SetElementCallback(index, structure, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003469 } else {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003470 return SetPropertyCallback(name, structure, attributes);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003471 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003472}
3473
3474
3475bool JSObject::CanSetCallback(String* name) {
3476 ASSERT(!IsAccessCheckNeeded()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003477 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003478
3479 // Check if there is an API defined callback object which prohibits
3480 // callback overwriting in this object or it's prototype chain.
3481 // This mechanism is needed for instance in a browser setting, where
3482 // certain accessors such as window.location should not be allowed
3483 // to be overwritten because allowing overwriting could potentially
3484 // cause security problems.
3485 LookupResult callback_result;
3486 LookupCallback(name, &callback_result);
3487 if (callback_result.IsProperty()) {
3488 Object* obj = callback_result.GetCallbackObject();
3489 if (obj->IsAccessorInfo() &&
3490 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3491 return false;
3492 }
3493 }
3494
3495 return true;
3496}
3497
3498
lrn@chromium.org303ada72010-10-27 09:33:13 +00003499MaybeObject* JSObject::SetElementCallback(uint32_t index,
3500 Object* structure,
3501 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003502 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3503
3504 // Normalize elements to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003505 Object* ok;
3506 { MaybeObject* maybe_ok = NormalizeElements();
3507 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3508 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003509
3510 // Update the dictionary with the new CALLBACKS property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003511 Object* dict;
3512 { MaybeObject* maybe_dict =
3513 element_dictionary()->Set(index, structure, details);
3514 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
3515 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003516
3517 NumberDictionary* elements = NumberDictionary::cast(dict);
3518 elements->set_requires_slow_elements();
3519 // Set the potential new dictionary on the object.
3520 set_elements(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003521
3522 return structure;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003523}
3524
3525
lrn@chromium.org303ada72010-10-27 09:33:13 +00003526MaybeObject* JSObject::SetPropertyCallback(String* name,
3527 Object* structure,
3528 PropertyAttributes attributes) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003529 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3530
3531 bool convert_back_to_fast = HasFastProperties() &&
3532 (map()->instance_descriptors()->number_of_descriptors()
3533 < DescriptorArray::kMaxNumberOfDescriptors);
3534
3535 // Normalize object to make this operation simple.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003536 Object* ok;
3537 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3538 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3539 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003540
3541 // For the global object allocate a new map to invalidate the global inline
3542 // caches which have a global property cell reference directly in the code.
3543 if (IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003544 Object* new_map;
3545 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3546 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3547 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003548 set_map(Map::cast(new_map));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003549 // When running crankshaft, changing the map is not enough. We
3550 // need to deoptimize all functions that rely on this global
3551 // object.
3552 Deoptimizer::DeoptimizeGlobalObject(this);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003553 }
3554
3555 // Update the dictionary with the new CALLBACKS property.
lrn@chromium.org303ada72010-10-27 09:33:13 +00003556 Object* result;
3557 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3558 if (!maybe_result->ToObject(&result)) return maybe_result;
3559 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003560
3561 if (convert_back_to_fast) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003562 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3563 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3564 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003565 }
3566 return result;
3567}
3568
lrn@chromium.org303ada72010-10-27 09:33:13 +00003569MaybeObject* JSObject::DefineAccessor(String* name,
3570 bool is_getter,
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003571 Object* fun,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003572 PropertyAttributes attributes) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003573 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003574 Isolate* isolate = GetIsolate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003575 // Check access rights if needed.
3576 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003577 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3578 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3579 return isolate->heap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003580 }
3581
3582 if (IsJSGlobalProxy()) {
3583 Object* proto = GetPrototype();
3584 if (proto->IsNull()) return this;
3585 ASSERT(proto->IsJSGlobalObject());
3586 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3587 fun, attributes);
3588 }
3589
lrn@chromium.org303ada72010-10-27 09:33:13 +00003590 Object* array;
3591 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3592 if (!maybe_array->ToObject(&array)) return maybe_array;
3593 }
3594 if (array->IsUndefined()) return array;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3596 return this;
3597}
3598
3599
lrn@chromium.org303ada72010-10-27 09:33:13 +00003600MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003601 Isolate* isolate = GetIsolate();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003602 String* name = String::cast(info->name());
3603 // Check access rights if needed.
3604 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003605 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3606 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3607 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003608 }
3609
3610 if (IsJSGlobalProxy()) {
3611 Object* proto = GetPrototype();
3612 if (proto->IsNull()) return this;
3613 ASSERT(proto->IsJSGlobalObject());
3614 return JSObject::cast(proto)->DefineAccessor(info);
3615 }
3616
3617 // Make sure that the top context does not change when doing callbacks or
3618 // interceptor calls.
3619 AssertNoContextChange ncc;
3620
3621 // Try to flatten before operating on the string.
3622 name->TryFlatten();
3623
3624 if (!CanSetCallback(name)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003626 }
3627
3628 uint32_t index = 0;
3629 bool is_element = name->AsArrayIndex(&index);
3630
3631 if (is_element) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003632 if (IsJSArray()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003633
3634 // Accessors overwrite previous callbacks (cf. with getters/setters).
3635 switch (GetElementsKind()) {
3636 case FAST_ELEMENTS:
3637 break;
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00003638 case EXTERNAL_PIXEL_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003639 case EXTERNAL_BYTE_ELEMENTS:
3640 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3641 case EXTERNAL_SHORT_ELEMENTS:
3642 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3643 case EXTERNAL_INT_ELEMENTS:
3644 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3645 case EXTERNAL_FLOAT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003646 case EXTERNAL_DOUBLE_ELEMENTS:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003647 // Ignore getters and setters on pixel and external array
3648 // elements.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003649 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003650 case DICTIONARY_ELEMENTS:
3651 break;
3652 default:
3653 UNREACHABLE();
3654 break;
3655 }
3656
lrn@chromium.org303ada72010-10-27 09:33:13 +00003657 Object* ok;
3658 { MaybeObject* maybe_ok =
3659 SetElementCallback(index, info, info->property_attributes());
3660 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3661 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003662 } else {
3663 // Lookup the name.
3664 LookupResult result;
3665 LocalLookup(name, &result);
3666 // ES5 forbids turning a property into an accessor if it's not
3667 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3668 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003670 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00003671 Object* ok;
3672 { MaybeObject* maybe_ok =
3673 SetPropertyCallback(name, info, info->property_attributes());
3674 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3675 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003676 }
3677
3678 return this;
3679}
3680
3681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003682Object* JSObject::LookupAccessor(String* name, bool is_getter) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003683 Heap* heap = GetHeap();
3684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003685 // Make sure that the top context does not change when doing callbacks or
3686 // interceptor calls.
3687 AssertNoContextChange ncc;
3688
3689 // Check access rights if needed.
3690 if (IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003691 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3692 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3693 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003694 }
3695
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 // Make the lookup and include prototypes.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003697 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00003698 uint32_t index = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003699 if (name->AsArrayIndex(&index)) {
3700 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003702 obj = JSObject::cast(obj)->GetPrototype()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003703 JSObject* js_object = JSObject::cast(obj);
3704 if (js_object->HasDictionaryElements()) {
3705 NumberDictionary* dictionary = js_object->element_dictionary();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003706 int entry = dictionary->FindEntry(index);
3707 if (entry != NumberDictionary::kNotFound) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003708 Object* element = dictionary->ValueAt(entry);
3709 PropertyDetails details = dictionary->DetailsAt(entry);
3710 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003711 if (element->IsFixedArray()) {
3712 return FixedArray::cast(element)->get(accessor_index);
3713 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003714 }
3715 }
3716 }
3717 }
3718 } else {
3719 for (Object* obj = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 obj != heap->null_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003721 obj = JSObject::cast(obj)->GetPrototype()) {
3722 LookupResult result;
3723 JSObject::cast(obj)->LocalLookup(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003724 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725 if (result.IsReadOnly()) return heap->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003726 if (result.type() == CALLBACKS) {
3727 Object* obj = result.GetCallbackObject();
3728 if (obj->IsFixedArray()) {
3729 return FixedArray::cast(obj)->get(accessor_index);
3730 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 }
3732 }
3733 }
3734 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003735 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736}
3737
3738
3739Object* JSObject::SlowReverseLookup(Object* value) {
3740 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003741 DescriptorArray* descs = map()->instance_descriptors();
3742 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3743 if (descs->GetType(i) == FIELD) {
3744 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3745 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00003747 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3748 if (descs->GetConstantFunction(i) == value) {
3749 return descs->GetKey(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003750 }
3751 }
3752 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003753 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003754 } else {
3755 return property_dictionary()->SlowReverseLookup(value);
3756 }
3757}
3758
3759
lrn@chromium.org303ada72010-10-27 09:33:13 +00003760MaybeObject* Map::CopyDropDescriptors() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003761 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003762 Object* result;
3763 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003764 heap->AllocateMap(instance_type(), instance_size());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003765 if (!maybe_result->ToObject(&result)) return maybe_result;
3766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 Map::cast(result)->set_prototype(prototype());
3768 Map::cast(result)->set_constructor(constructor());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003769 // Don't copy descriptors, so map transitions always remain a forest.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003770 // If we retained the same descriptors we would have two maps
3771 // pointing to the same transition which is bad because the garbage
3772 // collector relies on being able to reverse pointers from transitions
3773 // to maps. If properties need to be retained use CopyDropTransitions.
danno@chromium.org40cb8782011-05-25 07:58:50 +00003774 Map::cast(result)->clear_instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003775 // Please note instance_type and instance_size are set when allocated.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003776 Map::cast(result)->set_inobject_properties(inobject_properties());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 Map::cast(result)->set_unused_property_fields(unused_property_fields());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003778
3779 // If the map has pre-allocated properties always start out with a descriptor
3780 // array describing these properties.
3781 if (pre_allocated_property_fields() > 0) {
3782 ASSERT(constructor()->IsJSFunction());
3783 JSFunction* ctor = JSFunction::cast(constructor());
lrn@chromium.org303ada72010-10-27 09:33:13 +00003784 Object* descriptors;
3785 { MaybeObject* maybe_descriptors =
3786 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
3787 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3788 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00003789 Map::cast(result)->set_instance_descriptors(
3790 DescriptorArray::cast(descriptors));
3791 Map::cast(result)->set_pre_allocated_property_fields(
3792 pre_allocated_property_fields());
3793 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003794 Map::cast(result)->set_bit_field(bit_field());
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003795 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003796 Map::cast(result)->set_bit_field3(bit_field3());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003797 Map::cast(result)->set_is_shared(false);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003798 Map::cast(result)->ClearCodeCache(heap);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003799 return result;
3800}
3801
3802
lrn@chromium.org303ada72010-10-27 09:33:13 +00003803MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
3804 NormalizedMapSharingMode sharing) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003805 int new_instance_size = instance_size();
3806 if (mode == CLEAR_INOBJECT_PROPERTIES) {
3807 new_instance_size -= inobject_properties() * kPointerSize;
3808 }
3809
lrn@chromium.org303ada72010-10-27 09:33:13 +00003810 Object* result;
3811 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003812 GetHeap()->AllocateMap(instance_type(), new_instance_size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003813 if (!maybe_result->ToObject(&result)) return maybe_result;
3814 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003815
3816 if (mode != CLEAR_INOBJECT_PROPERTIES) {
3817 Map::cast(result)->set_inobject_properties(inobject_properties());
3818 }
3819
3820 Map::cast(result)->set_prototype(prototype());
3821 Map::cast(result)->set_constructor(constructor());
3822
3823 Map::cast(result)->set_bit_field(bit_field());
3824 Map::cast(result)->set_bit_field2(bit_field2());
danno@chromium.org40cb8782011-05-25 07:58:50 +00003825 Map::cast(result)->set_bit_field3(bit_field3());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003826
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003827 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
3828
ricow@chromium.org65fae842010-08-25 15:26:24 +00003829#ifdef DEBUG
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003830 if (Map::cast(result)->is_shared()) {
3831 Map::cast(result)->SharedMapVerify();
3832 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003833#endif
3834
3835 return result;
3836}
3837
3838
lrn@chromium.org303ada72010-10-27 09:33:13 +00003839MaybeObject* Map::CopyDropTransitions() {
3840 Object* new_map;
3841 { MaybeObject* maybe_new_map = CopyDropDescriptors();
3842 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3843 }
3844 Object* descriptors;
3845 { MaybeObject* maybe_descriptors =
3846 instance_descriptors()->RemoveTransitions();
3847 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3848 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003849 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00003850 return new_map;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003851}
3852
3853
lrn@chromium.org303ada72010-10-27 09:33:13 +00003854MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003855 // Allocate the code cache if not present.
3856 if (code_cache()->IsFixedArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003857 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003858 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
lrn@chromium.org303ada72010-10-27 09:33:13 +00003859 if (!maybe_result->ToObject(&result)) return maybe_result;
3860 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003861 set_code_cache(result);
3862 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003863
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003864 // Update the code cache.
3865 return CodeCache::cast(code_cache())->Update(name, code);
3866}
3867
3868
3869Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3870 // Do a lookup if a code cache exists.
3871 if (!code_cache()->IsFixedArray()) {
3872 return CodeCache::cast(code_cache())->Lookup(name, flags);
3873 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003875 }
3876}
3877
3878
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00003879int Map::IndexInCodeCache(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003880 // Get the internal index if a code cache exists.
3881 if (!code_cache()->IsFixedArray()) {
3882 return CodeCache::cast(code_cache())->GetIndex(name, code);
3883 }
3884 return -1;
3885}
3886
3887
3888void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3889 // No GC is supposed to happen between a call to IndexInCodeCache and
3890 // RemoveFromCodeCache so the code cache must be there.
3891 ASSERT(!code_cache()->IsFixedArray());
3892 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3893}
3894
3895
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003896void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
3897 Map* current = this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003898 Map* meta_map = heap()->meta_map();
3899 while (current != meta_map) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003900 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00003901 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
3902 if (d->IsEmpty()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003903 Map* prev = current->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003904 current->set_map(meta_map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003905 callback(current, data);
3906 current = prev;
3907 continue;
3908 }
3909
3910 FixedArray* contents = reinterpret_cast<FixedArray*>(
3911 d->get(DescriptorArray::kContentArrayIndex));
3912 Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3913 Object* map_or_index = *map_or_index_field;
3914 bool map_done = true;
3915 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3916 i < contents->length();
3917 i += 2) {
3918 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3919 if (details.IsTransition()) {
3920 Map* next = reinterpret_cast<Map*>(contents->get(i));
3921 next->set_map(current);
3922 *map_or_index_field = Smi::FromInt(i + 2);
3923 current = next;
3924 map_done = false;
3925 break;
3926 }
3927 }
3928 if (!map_done) continue;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003929 *map_or_index_field = heap()->fixed_array_map();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003930 Map* prev = current->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003931 current->set_map(meta_map);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003932 callback(current, data);
3933 current = prev;
3934 }
3935}
3936
3937
lrn@chromium.org303ada72010-10-27 09:33:13 +00003938MaybeObject* CodeCache::Update(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003939 // The number of monomorphic stubs for normal load/store/call IC's can grow to
3940 // a large number and therefore they need to go into a hash table. They are
3941 // used to load global properties from cells.
3942 if (code->type() == NORMAL) {
3943 // Make sure that a hash table is allocated for the normal load code cache.
3944 if (normal_type_cache()->IsUndefined()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003945 Object* result;
3946 { MaybeObject* maybe_result =
3947 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
3948 if (!maybe_result->ToObject(&result)) return maybe_result;
3949 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003950 set_normal_type_cache(result);
3951 }
3952 return UpdateNormalTypeCache(name, code);
3953 } else {
3954 ASSERT(default_cache()->IsFixedArray());
3955 return UpdateDefaultCache(name, code);
3956 }
3957}
3958
3959
lrn@chromium.org303ada72010-10-27 09:33:13 +00003960MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003961 // When updating the default code cache we disregard the type encoded in the
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003962 // flags. This allows call constant stubs to overwrite call field
3963 // stubs, etc.
3964 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
3965
3966 // First check whether we can update existing code cache without
3967 // extending it.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003968 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 int length = cache->length();
ager@chromium.org236ad962008-09-25 09:45:57 +00003970 int deleted_index = -1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003971 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 Object* key = cache->get(i);
ager@chromium.org236ad962008-09-25 09:45:57 +00003973 if (key->IsNull()) {
3974 if (deleted_index < 0) deleted_index = i;
3975 continue;
3976 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003977 if (key->IsUndefined()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00003978 if (deleted_index >= 0) i = deleted_index;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003979 cache->set(i + kCodeCacheEntryNameOffset, name);
3980 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003981 return this;
3982 }
3983 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003984 Code::Flags found =
3985 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003986 if (Code::RemoveTypeFromFlags(found) == flags) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003987 cache->set(i + kCodeCacheEntryCodeOffset, code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 return this;
3989 }
3990 }
3991 }
3992
ager@chromium.org236ad962008-09-25 09:45:57 +00003993 // Reached the end of the code cache. If there were deleted
3994 // elements, reuse the space for the first of them.
3995 if (deleted_index >= 0) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003996 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
3997 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
ager@chromium.org236ad962008-09-25 09:45:57 +00003998 return this;
3999 }
4000
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004001 // Extend the code cache with some new entries (at least one). Must be a
4002 // multiple of the entry size.
4003 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4004 new_length = new_length - new_length % kCodeCacheEntrySize;
4005 ASSERT((new_length % kCodeCacheEntrySize) == 0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004006 Object* result;
4007 { MaybeObject* maybe_result = cache->CopySize(new_length);
4008 if (!maybe_result->ToObject(&result)) return maybe_result;
4009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010
4011 // Add the (name, code) pair to the new cache.
4012 cache = FixedArray::cast(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004013 cache->set(length + kCodeCacheEntryNameOffset, name);
4014 cache->set(length + kCodeCacheEntryCodeOffset, code);
4015 set_default_cache(cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004016 return this;
4017}
4018
4019
lrn@chromium.org303ada72010-10-27 09:33:13 +00004020MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004021 // Adding a new entry can cause a new cache to be allocated.
4022 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004023 Object* new_cache;
4024 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4025 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4026 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004027 set_normal_type_cache(new_cache);
4028 return this;
4029}
4030
4031
4032Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4033 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4034 return LookupNormalTypeCache(name, flags);
4035 } else {
4036 return LookupDefaultCache(name, flags);
4037 }
4038}
4039
4040
4041Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4042 FixedArray* cache = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004043 int length = cache->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004044 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4045 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
ager@chromium.org236ad962008-09-25 09:45:57 +00004046 // Skip deleted elements.
4047 if (key->IsNull()) continue;
4048 if (key->IsUndefined()) return key;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004049 if (name->Equals(String::cast(key))) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004050 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4051 if (code->flags() == flags) {
4052 return code;
4053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004054 }
4055 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004056 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057}
4058
4059
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004060Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4061 if (!normal_type_cache()->IsUndefined()) {
4062 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4063 return cache->Lookup(name, flags);
4064 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004065 return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004066 }
4067}
4068
4069
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004070int CodeCache::GetIndex(Object* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004071 if (code->type() == NORMAL) {
4072 if (normal_type_cache()->IsUndefined()) return -1;
4073 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004074 return cache->GetIndex(String::cast(name), code->flags());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004075 }
4076
4077 FixedArray* array = default_cache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004078 int len = array->length();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004079 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4080 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004082 return -1;
4083}
4084
4085
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004086void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004087 if (code->type() == NORMAL) {
4088 ASSERT(!normal_type_cache()->IsUndefined());
4089 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
sgjesse@chromium.org99a37fa2010-03-11 09:23:46 +00004090 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004091 cache->RemoveByIndex(index);
4092 } else {
4093 FixedArray* array = default_cache();
4094 ASSERT(array->length() >= index && array->get(index)->IsCode());
4095 // Use null instead of undefined for deleted elements to distinguish
4096 // deleted elements from unused elements. This distinction is used
4097 // when looking up in the cache and when updating the cache.
4098 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4099 array->set_null(index - 1); // Name.
4100 array->set_null(index); // Code.
4101 }
4102}
4103
4104
4105// The key in the code cache hash table consists of the property name and the
4106// code object. The actual match is on the name and the code flags. If a key
4107// is created using the flags and not a code object it can only be used for
4108// lookup not to create a new entry.
4109class CodeCacheHashTableKey : public HashTableKey {
4110 public:
4111 CodeCacheHashTableKey(String* name, Code::Flags flags)
4112 : name_(name), flags_(flags), code_(NULL) { }
4113
4114 CodeCacheHashTableKey(String* name, Code* code)
4115 : name_(name),
4116 flags_(code->flags()),
4117 code_(code) { }
4118
4119
4120 bool IsMatch(Object* other) {
4121 if (!other->IsFixedArray()) return false;
4122 FixedArray* pair = FixedArray::cast(other);
4123 String* name = String::cast(pair->get(0));
4124 Code::Flags flags = Code::cast(pair->get(1))->flags();
4125 if (flags != flags_) {
4126 return false;
4127 }
4128 return name_->Equals(name);
4129 }
4130
4131 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4132 return name->Hash() ^ flags;
4133 }
4134
4135 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4136
4137 uint32_t HashForObject(Object* obj) {
4138 FixedArray* pair = FixedArray::cast(obj);
4139 String* name = String::cast(pair->get(0));
4140 Code* code = Code::cast(pair->get(1));
4141 return NameFlagsHashHelper(name, code->flags());
4142 }
4143
lrn@chromium.org303ada72010-10-27 09:33:13 +00004144 MUST_USE_RESULT MaybeObject* AsObject() {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004145 ASSERT(code_ != NULL);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004146 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004147 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004148 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4149 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004150 FixedArray* pair = FixedArray::cast(obj);
4151 pair->set(0, name_);
4152 pair->set(1, code_);
4153 return pair;
4154 }
4155
4156 private:
4157 String* name_;
4158 Code::Flags flags_;
4159 Code* code_;
4160};
4161
4162
4163Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4164 CodeCacheHashTableKey key(name, flags);
4165 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004166 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004167 return get(EntryToIndex(entry) + 1);
4168}
4169
4170
lrn@chromium.org303ada72010-10-27 09:33:13 +00004171MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004172 CodeCacheHashTableKey key(name, code);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004173 Object* obj;
4174 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4175 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4176 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004177
4178 // Don't use this, as the table might have grown.
4179 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4180
4181 int entry = cache->FindInsertionEntry(key.Hash());
lrn@chromium.org303ada72010-10-27 09:33:13 +00004182 Object* k;
4183 { MaybeObject* maybe_k = key.AsObject();
4184 if (!maybe_k->ToObject(&k)) return maybe_k;
4185 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004186
4187 cache->set(EntryToIndex(entry), k);
4188 cache->set(EntryToIndex(entry) + 1, code);
4189 cache->ElementAdded();
4190 return cache;
4191}
4192
4193
4194int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4195 CodeCacheHashTableKey key(name, flags);
4196 int entry = FindEntry(&key);
4197 return (entry == kNotFound) ? -1 : entry;
4198}
4199
4200
4201void CodeCacheHashTable::RemoveByIndex(int index) {
4202 ASSERT(index >= 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004203 Heap* heap = GetHeap();
4204 set(EntryToIndex(index), heap->null_value());
4205 set(EntryToIndex(index) + 1, heap->null_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004206 ElementRemoved();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004207}
4208
4209
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210static bool HasKey(FixedArray* array, Object* key) {
4211 int len0 = array->length();
4212 for (int i = 0; i < len0; i++) {
4213 Object* element = array->get(i);
4214 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4215 if (element->IsString() &&
4216 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4217 return true;
4218 }
4219 }
4220 return false;
4221}
4222
4223
lrn@chromium.org303ada72010-10-27 09:33:13 +00004224MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004225 ASSERT(!array->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004226 switch (array->GetElementsKind()) {
4227 case JSObject::FAST_ELEMENTS:
4228 return UnionOfKeys(FixedArray::cast(array->elements()));
4229 case JSObject::DICTIONARY_ELEMENTS: {
4230 NumberDictionary* dict = array->element_dictionary();
4231 int size = dict->NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004232
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004233 // Allocate a temporary fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004234 Object* object;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004235 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004236 if (!maybe_object->ToObject(&object)) return maybe_object;
4237 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004238 FixedArray* key_array = FixedArray::cast(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004240 int capacity = dict->Capacity();
4241 int pos = 0;
4242 // Copy the elements from the JSArray to the temporary fixed array.
4243 for (int i = 0; i < capacity; i++) {
4244 if (dict->IsKey(dict->KeyAt(i))) {
4245 key_array->set(pos++, dict->ValueAt(i));
4246 }
4247 }
4248 // Compute the union of this and the temporary fixed array.
4249 return UnionOfKeys(key_array);
ager@chromium.org5ec48922009-05-05 07:25:34 +00004250 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004251 default:
4252 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004253 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00004254 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004255 return GetHeap()->null_value(); // Failure case needs to "return" a value.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004256}
4257
4258
lrn@chromium.org303ada72010-10-27 09:33:13 +00004259MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004260 int len0 = length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004261#ifdef DEBUG
4262 if (FLAG_enable_slow_asserts) {
4263 for (int i = 0; i < len0; i++) {
4264 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4265 }
4266 }
4267#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 int len1 = other->length();
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004269 // Optimize if 'other' is empty.
4270 // We cannot optimize if 'this' is empty, as other may have holes
4271 // or non keys.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004272 if (len1 == 0) return this;
4273
4274 // Compute how many elements are not in this.
4275 int extra = 0;
4276 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004277 Object* value = other->get(y);
4278 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004279 }
4280
ager@chromium.org5ec48922009-05-05 07:25:34 +00004281 if (extra == 0) return this;
4282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004283 // Allocate the result
lrn@chromium.org303ada72010-10-27 09:33:13 +00004284 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004285 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004286 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4287 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004288 // Fill in the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004289 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004290 FixedArray* result = FixedArray::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004291 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004292 for (int i = 0; i < len0; i++) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004293 Object* e = get(i);
4294 ASSERT(e->IsString() || e->IsNumber());
4295 result->set(i, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004296 }
4297 // Fill in the extra keys.
4298 int index = 0;
4299 for (int y = 0; y < len1; y++) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004300 Object* value = other->get(y);
4301 if (!value->IsTheHole() && !HasKey(this, value)) {
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00004302 Object* e = other->get(y);
4303 ASSERT(e->IsString() || e->IsNumber());
4304 result->set(len0 + index, e, mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004305 index++;
4306 }
4307 }
4308 ASSERT(extra == index);
4309 return result;
4310}
4311
4312
lrn@chromium.org303ada72010-10-27 09:33:13 +00004313MaybeObject* FixedArray::CopySize(int new_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004314 Heap* heap = GetHeap();
4315 if (new_length == 0) return heap->empty_fixed_array();
lrn@chromium.org303ada72010-10-27 09:33:13 +00004316 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004317 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004318 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4319 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 FixedArray* result = FixedArray::cast(obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004321 // Copy the content
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004322 AssertNoAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004323 int len = length();
4324 if (new_length < len) len = new_length;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004325 result->set_map(map());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004326 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327 for (int i = 0; i < len; i++) {
4328 result->set(i, get(i), mode);
4329 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004330 return result;
4331}
4332
4333
4334void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004335 AssertNoAllocation no_gc;
4336 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004337 for (int index = 0; index < len; index++) {
4338 dest->set(dest_pos+index, get(pos+index), mode);
4339 }
4340}
4341
4342
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004343#ifdef DEBUG
4344bool FixedArray::IsEqualTo(FixedArray* other) {
4345 if (length() != other->length()) return false;
4346 for (int i = 0 ; i < length(); ++i) {
4347 if (get(i) != other->get(i)) return false;
4348 }
4349 return true;
4350}
4351#endif
4352
4353
lrn@chromium.org303ada72010-10-27 09:33:13 +00004354MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004355 Heap* heap = Isolate::Current()->heap();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004356 if (number_of_descriptors == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004357 return heap->empty_descriptor_array();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004358 }
4359 // Allocate the array of keys.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004360 Object* array;
4361 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004362 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
lrn@chromium.org303ada72010-10-27 09:33:13 +00004363 if (!maybe_array->ToObject(&array)) return maybe_array;
4364 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004365 // Do not use DescriptorArray::cast on incomplete object.
4366 FixedArray* result = FixedArray::cast(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004367
4368 // Allocate the content array and set it in the descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004369 { MaybeObject* maybe_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004370 heap->AllocateFixedArray(number_of_descriptors << 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004371 if (!maybe_array->ToObject(&array)) return maybe_array;
4372 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00004373 result->set(kBitField3StorageIndex, Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004374 result->set(kContentArrayIndex, array);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004375 result->set(kEnumerationIndexIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004376 Smi::FromInt(PropertyDetails::kInitialIndex));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 return result;
4378}
4379
4380
4381void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4382 FixedArray* new_cache) {
4383 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4384 if (HasEnumCache()) {
4385 FixedArray::cast(get(kEnumerationIndexIndex))->
4386 set(kEnumCacheBridgeCacheIndex, new_cache);
4387 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004388 if (IsEmpty()) return; // Do nothing for empty descriptor array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004389 FixedArray::cast(bridge_storage)->
4390 set(kEnumCacheBridgeCacheIndex, new_cache);
4391 fast_set(FixedArray::cast(bridge_storage),
4392 kEnumCacheBridgeEnumIndex,
4393 get(kEnumerationIndexIndex));
4394 set(kEnumerationIndexIndex, bridge_storage);
4395 }
4396}
4397
4398
lrn@chromium.org303ada72010-10-27 09:33:13 +00004399MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4400 TransitionFlag transition_flag) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004401 // Transitions are only kept when inserting another transition.
4402 // This precondition is not required by this function's implementation, but
4403 // is currently required by the semantics of maps, so we check it.
4404 // Conversely, we filter after replacing, so replacing a transition and
4405 // removing all other transitions is not supported.
4406 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4407 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4408 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409
4410 // Ensure the key is a symbol.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004411 Object* result;
4412 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4413 if (!maybe_result->ToObject(&result)) return maybe_result;
4414 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004415
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004416 int transitions = 0;
4417 int null_descriptors = 0;
4418 if (remove_transitions) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004419 for (int i = 0; i < number_of_descriptors(); i++) {
4420 if (IsTransition(i)) transitions++;
4421 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004422 }
4423 } else {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004424 for (int i = 0; i < number_of_descriptors(); i++) {
4425 if (IsNullDescriptor(i)) null_descriptors++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004426 }
4427 }
4428 int new_size = number_of_descriptors() - transitions - null_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004429
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004430 // If key is in descriptor, we replace it in-place when filtering.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004431 // Count a null descriptor for key as inserted, not replaced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004432 int index = Search(descriptor->GetKey());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004433 const bool inserting = (index == kNotFound);
4434 const bool replacing = !inserting;
4435 bool keep_enumeration_index = false;
4436 if (inserting) {
4437 ++new_size;
4438 }
4439 if (replacing) {
4440 // We are replacing an existing descriptor. We keep the enumeration
4441 // index of a visible property.
4442 PropertyType t = PropertyDetails(GetDetails(index)).type();
4443 if (t == CONSTANT_FUNCTION ||
4444 t == FIELD ||
4445 t == CALLBACKS ||
4446 t == INTERCEPTOR) {
4447 keep_enumeration_index = true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004448 } else if (remove_transitions) {
4449 // Replaced descriptor has been counted as removed if it is
4450 // a transition that will be replaced. Adjust count in this case.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004451 ++new_size;
4452 }
4453 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004454 { MaybeObject* maybe_result = Allocate(new_size);
4455 if (!maybe_result->ToObject(&result)) return maybe_result;
4456 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004457 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004458 // Set the enumeration index in the descriptors and set the enumeration index
4459 // in the result.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004460 int enumeration_index = NextEnumerationIndex();
4461 if (!descriptor->GetDetails().IsTransition()) {
4462 if (keep_enumeration_index) {
4463 descriptor->SetEnumerationIndex(
4464 PropertyDetails(GetDetails(index)).index());
4465 } else {
4466 descriptor->SetEnumerationIndex(enumeration_index);
4467 ++enumeration_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004469 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004470 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4471
4472 // Copy the descriptors, filtering out transitions and null descriptors,
4473 // and inserting or replacing a descriptor.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004474 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004475 int from_index = 0;
4476 int to_index = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004477
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004478 for (; from_index < number_of_descriptors(); from_index++) {
4479 String* key = GetKey(from_index);
4480 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4481 break;
4482 }
4483 if (IsNullDescriptor(from_index)) continue;
4484 if (remove_transitions && IsTransition(from_index)) continue;
4485 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004486 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004487
4488 new_descriptors->Set(to_index++, descriptor);
4489 if (replacing) from_index++;
4490
4491 for (; from_index < number_of_descriptors(); from_index++) {
4492 if (IsNullDescriptor(from_index)) continue;
4493 if (remove_transitions && IsTransition(from_index)) continue;
4494 new_descriptors->CopyFrom(to_index++, this, from_index);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004495 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004496
4497 ASSERT(to_index == new_descriptors->number_of_descriptors());
4498 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004500 return new_descriptors;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501}
4502
4503
lrn@chromium.org303ada72010-10-27 09:33:13 +00004504MaybeObject* DescriptorArray::RemoveTransitions() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004505 // Remove all transitions and null descriptors. Return a copy of the array
4506 // with all transitions removed, or a Failure object if the new array could
4507 // not be allocated.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004508
4509 // Compute the size of the map transition entries to be removed.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004510 int num_removed = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004511 for (int i = 0; i < number_of_descriptors(); i++) {
4512 if (!IsProperty(i)) num_removed++;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004513 }
4514
4515 // Allocate the new descriptor array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00004516 Object* result;
4517 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4518 if (!maybe_result->ToObject(&result)) return maybe_result;
4519 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004520 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4521
4522 // Copy the content.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004523 int next_descriptor = 0;
4524 for (int i = 0; i < number_of_descriptors(); i++) {
4525 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004526 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00004527 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004528
4529 return new_descriptors;
4530}
4531
4532
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004533void DescriptorArray::SortUnchecked() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004534 // In-place heap sort.
4535 int len = number_of_descriptors();
4536
4537 // Bottom-up max-heap construction.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004538 // Index of the last node with children
4539 const int max_parent_index = (len / 2) - 1;
4540 for (int i = max_parent_index; i >= 0; --i) {
4541 int parent_index = i;
4542 const uint32_t parent_hash = GetKey(i)->Hash();
4543 while (parent_index <= max_parent_index) {
4544 int child_index = 2 * parent_index + 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545 uint32_t child_hash = GetKey(child_index)->Hash();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004546 if (child_index + 1 < len) {
4547 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4548 if (right_child_hash > child_hash) {
4549 child_index++;
4550 child_hash = right_child_hash;
4551 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004552 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004553 if (child_hash <= parent_hash) break;
4554 Swap(parent_index, child_index);
4555 // Now element at child_index could be < its children.
4556 parent_index = child_index; // parent_hash remains correct.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004557 }
4558 }
4559
4560 // Extract elements and create sorted array.
4561 for (int i = len - 1; i > 0; --i) {
4562 // Put max element at the back of the array.
4563 Swap(0, i);
4564 // Sift down the new top element.
4565 int parent_index = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004566 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4567 const int max_parent_index = (i / 2) - 1;
4568 while (parent_index <= max_parent_index) {
4569 int child_index = parent_index * 2 + 1;
4570 uint32_t child_hash = GetKey(child_index)->Hash();
4571 if (child_index + 1 < i) {
4572 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4573 if (right_child_hash > child_hash) {
4574 child_index++;
4575 child_hash = right_child_hash;
4576 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004578 if (child_hash <= parent_hash) break;
4579 Swap(parent_index, child_index);
4580 parent_index = child_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004581 }
4582 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004583}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004585
4586void DescriptorArray::Sort() {
4587 SortUnchecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588 SLOW_ASSERT(IsSortedNoDuplicates());
4589}
4590
4591
4592int DescriptorArray::BinarySearch(String* name, int low, int high) {
4593 uint32_t hash = name->Hash();
4594
4595 while (low <= high) {
4596 int mid = (low + high) / 2;
4597 String* mid_name = GetKey(mid);
4598 uint32_t mid_hash = mid_name->Hash();
4599
4600 if (mid_hash > hash) {
4601 high = mid - 1;
4602 continue;
4603 }
4604 if (mid_hash < hash) {
4605 low = mid + 1;
4606 continue;
4607 }
4608 // Found an element with the same hash-code.
4609 ASSERT(hash == mid_hash);
4610 // There might be more, so we find the first one and
4611 // check them all to see if we have a match.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004612 if (name == mid_name && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4614 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004615 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 }
4617 break;
4618 }
4619 return kNotFound;
4620}
4621
4622
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004623int DescriptorArray::LinearSearch(String* name, int len) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00004624 uint32_t hash = name->Hash();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004625 for (int number = 0; number < len; number++) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00004626 String* entry = GetKey(number);
4627 if ((entry->Hash() == hash) &&
4628 name->Equals(entry) &&
4629 !is_null_descriptor(number)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004630 return number;
4631 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004632 }
4633 return kNotFound;
4634}
4635
4636
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004637MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4638 PretenureFlag pretenure) {
4639 ASSERT(deopt_entry_count > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004640 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004641 pretenure);
4642}
4643
4644
4645MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
4646 PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004647 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
4648 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004649 pretenure);
4650}
4651
4652
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004653#ifdef DEBUG
4654bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
4655 if (IsEmpty()) return other->IsEmpty();
4656 if (other->IsEmpty()) return false;
4657 if (length() != other->length()) return false;
4658 for (int i = 0; i < length(); ++i) {
4659 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
4660 }
4661 return GetContentArray()->IsEqualTo(other->GetContentArray());
4662}
4663#endif
4664
4665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004666bool String::LooksValid() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004667 if (!Isolate::Current()->heap()->Contains(this)) return false;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004668 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004669}
4670
4671
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004672int String::Utf8Length() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004673 if (IsAsciiRepresentation()) return length();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004674 // Attempt to flatten before accessing the string. It probably
4675 // doesn't make Utf8Length faster, but it is very likely that
4676 // the string will be accessed later (for example by WriteUtf8)
4677 // so it's still a good idea.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004678 Heap* heap = GetHeap();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004679 TryFlatten();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004680 Access<StringInputBuffer> buffer(
4681 heap->isolate()->objects_string_input_buffer());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004682 buffer->Reset(0, this);
4683 int result = 0;
4684 while (buffer->has_more())
4685 result += unibrow::Utf8::Length(buffer->GetNext());
4686 return result;
4687}
4688
4689
ager@chromium.org7c537e22008-10-16 08:43:32 +00004690Vector<const char> String::ToAsciiVector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004691 ASSERT(IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004692 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004693
4694 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004695 int length = this->length();
4696 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004697 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004698 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004699 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004700 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004701 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004702 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004703 }
4704 if (string_tag == kSeqStringTag) {
4705 SeqAsciiString* seq = SeqAsciiString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004706 char* start = seq->GetChars();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004707 return Vector<const char>(start + offset, length);
4708 }
4709 ASSERT(string_tag == kExternalStringTag);
4710 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
4711 const char* start = ext->resource()->data();
4712 return Vector<const char>(start + offset, length);
4713}
4714
4715
4716Vector<const uc16> String::ToUC16Vector() {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004717 ASSERT(IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004718 ASSERT(IsFlat());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004719
4720 int offset = 0;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004721 int length = this->length();
4722 StringRepresentationTag string_tag = StringShape(this).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004723 String* string = this;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004724 if (string_tag == kConsStringTag) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004725 ConsString* cons = ConsString::cast(string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004726 ASSERT(cons->second()->length() == 0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004727 string = cons->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004728 string_tag = StringShape(string).representation_tag();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004729 }
4730 if (string_tag == kSeqStringTag) {
4731 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004732 return Vector<const uc16>(seq->GetChars() + offset, length);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004733 }
4734 ASSERT(string_tag == kExternalStringTag);
4735 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
4736 const uc16* start =
4737 reinterpret_cast<const uc16*>(ext->resource()->data());
4738 return Vector<const uc16>(start + offset, length);
4739}
4740
4741
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004742SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4743 RobustnessFlag robust_flag,
4744 int offset,
4745 int length,
4746 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004747 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4748 return SmartPointer<char>(NULL);
4749 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004750 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004751
4752 // Negative length means the to the end of the string.
4753 if (length < 0) length = kMaxInt - offset;
4754
4755 // Compute the size of the UTF-8 string. Start at the specified offset.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004756 Access<StringInputBuffer> buffer(
4757 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758 buffer->Reset(offset, this);
4759 int character_position = offset;
4760 int utf8_bytes = 0;
4761 while (buffer->has_more()) {
4762 uint16_t character = buffer->GetNext();
4763 if (character_position < offset + length) {
4764 utf8_bytes += unibrow::Utf8::Length(character);
4765 }
4766 character_position++;
4767 }
4768
4769 if (length_return) {
4770 *length_return = utf8_bytes;
4771 }
4772
4773 char* result = NewArray<char>(utf8_bytes + 1);
4774
4775 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
4776 buffer->Rewind();
4777 buffer->Seek(offset);
4778 character_position = offset;
4779 int utf8_byte_position = 0;
4780 while (buffer->has_more()) {
4781 uint16_t character = buffer->GetNext();
4782 if (character_position < offset + length) {
4783 if (allow_nulls == DISALLOW_NULLS && character == 0) {
4784 character = ' ';
4785 }
4786 utf8_byte_position +=
4787 unibrow::Utf8::Encode(result + utf8_byte_position, character);
4788 }
4789 character_position++;
4790 }
4791 result[utf8_byte_position] = 0;
4792 return SmartPointer<char>(result);
4793}
4794
4795
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00004796SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4797 RobustnessFlag robust_flag,
4798 int* length_return) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
4800}
4801
4802
4803const uc16* String::GetTwoByteData() {
4804 return GetTwoByteData(0);
4805}
4806
4807
4808const uc16* String::GetTwoByteData(unsigned start) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00004809 ASSERT(!IsAsciiRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004810 switch (StringShape(this).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 case kSeqStringTag:
ager@chromium.org7c537e22008-10-16 08:43:32 +00004812 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004813 case kExternalStringTag:
4814 return ExternalTwoByteString::cast(this)->
4815 ExternalTwoByteStringGetData(start);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 case kConsStringTag:
4817 UNREACHABLE();
4818 return NULL;
4819 }
4820 UNREACHABLE();
4821 return NULL;
4822}
4823
4824
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004825SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004827 return SmartPointer<uc16>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004828 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004829 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004831 Access<StringInputBuffer> buffer(
4832 heap->isolate()->objects_string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004833 buffer->Reset(this);
4834
4835 uc16* result = NewArray<uc16>(length() + 1);
4836
4837 int i = 0;
4838 while (buffer->has_more()) {
4839 uint16_t character = buffer->GetNext();
4840 result[i++] = character;
4841 }
4842 result[i] = 0;
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00004843 return SmartPointer<uc16>(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004844}
4845
4846
ager@chromium.org7c537e22008-10-16 08:43:32 +00004847const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 return reinterpret_cast<uc16*>(
4849 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
4850}
4851
4852
ager@chromium.org7c537e22008-10-16 08:43:32 +00004853void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00004854 unsigned* offset_ptr,
4855 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 unsigned chars_read = 0;
4857 unsigned offset = *offset_ptr;
4858 while (chars_read < max_chars) {
4859 uint16_t c = *reinterpret_cast<uint16_t*>(
4860 reinterpret_cast<char*>(this) -
4861 kHeapObjectTag + kHeaderSize + offset * kShortSize);
4862 if (c <= kMaxAsciiCharCode) {
4863 // Fast case for ASCII characters. Cursor is an input output argument.
4864 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4865 rbb->util_buffer,
4866 rbb->capacity,
4867 rbb->cursor)) {
4868 break;
4869 }
4870 } else {
4871 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4872 rbb->util_buffer,
4873 rbb->capacity,
4874 rbb->cursor)) {
4875 break;
4876 }
4877 }
4878 offset++;
4879 chars_read++;
4880 }
4881 *offset_ptr = offset;
4882 rbb->remaining += chars_read;
4883}
4884
4885
ager@chromium.org7c537e22008-10-16 08:43:32 +00004886const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
4887 unsigned* remaining,
4888 unsigned* offset_ptr,
4889 unsigned max_chars) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004890 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
4891 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
4892 *remaining = max_chars;
4893 *offset_ptr += max_chars;
4894 return b;
4895}
4896
4897
4898// This will iterate unless the block of string data spans two 'halves' of
4899// a ConsString, in which case it will recurse. Since the block of string
4900// data to be read has a maximum size this limits the maximum recursion
4901// depth to something sane. Since C++ does not have tail call recursion
4902// elimination, the iteration must be explicit. Since this is not an
4903// -IntoBuffer method it can delegate to one of the efficient
4904// *AsciiStringReadBlock routines.
4905const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
4906 unsigned* offset_ptr,
4907 unsigned max_chars) {
4908 ConsString* current = this;
4909 unsigned offset = *offset_ptr;
4910 int offset_correction = 0;
4911
4912 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004913 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004914 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004915 if (left_length > offset &&
4916 (max_chars <= left_length - offset ||
4917 (rbb->capacity <= left_length - offset &&
4918 (max_chars = left_length - offset, true)))) { // comma operator!
4919 // Left hand side only - iterate unless we have reached the bottom of
4920 // the cons tree. The assignment on the left of the comma operator is
4921 // in order to make use of the fact that the -IntoBuffer routines can
4922 // produce at most 'capacity' characters. This enables us to postpone
4923 // the point where we switch to the -IntoBuffer routines (below) in order
4924 // to maximize the chances of delegating a big chunk of work to the
4925 // efficient *AsciiStringReadBlock routines.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004926 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927 current = ConsString::cast(left);
4928 continue;
4929 } else {
4930 const unibrow::byte* answer =
4931 String::ReadBlock(left, rbb, &offset, max_chars);
4932 *offset_ptr = offset + offset_correction;
4933 return answer;
4934 }
4935 } else if (left_length <= offset) {
4936 // Right hand side only - iterate unless we have reached the bottom of
4937 // the cons tree.
ager@chromium.org870a0b62008-11-04 11:43:05 +00004938 String* right = current->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939 offset -= left_length;
4940 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004941 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004942 current = ConsString::cast(right);
4943 continue;
4944 } else {
4945 const unibrow::byte* answer =
4946 String::ReadBlock(right, rbb, &offset, max_chars);
4947 *offset_ptr = offset + offset_correction;
4948 return answer;
4949 }
4950 } else {
4951 // The block to be read spans two sides of the ConsString, so we call the
4952 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
4953 // are able to assemble data from several part strings because they use
4954 // the util_buffer to store their data and never return direct pointers
4955 // to their storage. We don't try to read more than the buffer capacity
4956 // here or we can get too much recursion.
4957 ASSERT(rbb->remaining == 0);
4958 ASSERT(rbb->cursor == 0);
4959 current->ConsStringReadBlockIntoBuffer(
4960 rbb,
4961 &offset,
4962 max_chars > rbb->capacity ? rbb->capacity : max_chars);
4963 *offset_ptr = offset + offset_correction;
4964 return rbb->util_buffer;
4965 }
4966 }
4967}
4968
4969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004970uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
4971 ASSERT(index >= 0 && index < length());
4972 return resource()->data()[index];
4973}
4974
4975
4976const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
4977 unsigned* remaining,
4978 unsigned* offset_ptr,
4979 unsigned max_chars) {
4980 // Cast const char* to unibrow::byte* (signedness difference).
4981 const unibrow::byte* b =
4982 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
4983 *remaining = max_chars;
4984 *offset_ptr += max_chars;
4985 return b;
4986}
4987
4988
4989const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
4990 unsigned start) {
4991 return resource()->data() + start;
4992}
4993
4994
4995uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
4996 ASSERT(index >= 0 && index < length());
4997 return resource()->data()[index];
4998}
4999
5000
5001void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5002 ReadBlockBuffer* rbb,
5003 unsigned* offset_ptr,
5004 unsigned max_chars) {
5005 unsigned chars_read = 0;
5006 unsigned offset = *offset_ptr;
5007 const uint16_t* data = resource()->data();
5008 while (chars_read < max_chars) {
5009 uint16_t c = data[offset];
5010 if (c <= kMaxAsciiCharCode) {
ager@chromium.org80787b72009-04-17 10:24:24 +00005011 // Fast case for ASCII characters. Cursor is an input output argument.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005012 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5013 rbb->util_buffer,
5014 rbb->capacity,
5015 rbb->cursor))
5016 break;
5017 } else {
5018 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5019 rbb->util_buffer,
5020 rbb->capacity,
5021 rbb->cursor))
5022 break;
5023 }
5024 offset++;
5025 chars_read++;
5026 }
5027 *offset_ptr = offset;
5028 rbb->remaining += chars_read;
5029}
5030
5031
ager@chromium.org7c537e22008-10-16 08:43:32 +00005032void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005033 unsigned* offset_ptr,
5034 unsigned max_chars) {
5035 unsigned capacity = rbb->capacity - rbb->cursor;
5036 if (max_chars > capacity) max_chars = capacity;
5037 memcpy(rbb->util_buffer + rbb->cursor,
5038 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5039 *offset_ptr * kCharSize,
5040 max_chars);
5041 rbb->remaining += max_chars;
5042 *offset_ptr += max_chars;
5043 rbb->cursor += max_chars;
5044}
5045
5046
5047void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5048 ReadBlockBuffer* rbb,
5049 unsigned* offset_ptr,
5050 unsigned max_chars) {
5051 unsigned capacity = rbb->capacity - rbb->cursor;
5052 if (max_chars > capacity) max_chars = capacity;
5053 memcpy(rbb->util_buffer + rbb->cursor,
5054 resource()->data() + *offset_ptr,
5055 max_chars);
5056 rbb->remaining += max_chars;
5057 *offset_ptr += max_chars;
5058 rbb->cursor += max_chars;
5059}
5060
5061
5062// This method determines the type of string involved and then copies
5063// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5064// where they can be found. The pointer is not necessarily valid across a GC
5065// (see AsciiStringReadBlock).
5066const unibrow::byte* String::ReadBlock(String* input,
5067 ReadBlockBuffer* rbb,
5068 unsigned* offset_ptr,
5069 unsigned max_chars) {
5070 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5071 if (max_chars == 0) {
5072 rbb->remaining = 0;
5073 return NULL;
5074 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005075 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005076 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005077 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005078 SeqAsciiString* str = SeqAsciiString::cast(input);
5079 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5080 offset_ptr,
5081 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005082 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005083 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5084 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5085 offset_ptr,
5086 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005087 return rbb->util_buffer;
5088 }
5089 case kConsStringTag:
5090 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5091 offset_ptr,
5092 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005094 if (input->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5096 &rbb->remaining,
5097 offset_ptr,
5098 max_chars);
5099 } else {
5100 ExternalTwoByteString::cast(input)->
5101 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5102 offset_ptr,
5103 max_chars);
5104 return rbb->util_buffer;
5105 }
5106 default:
5107 break;
5108 }
5109
5110 UNREACHABLE();
5111 return 0;
5112}
5113
5114
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005115void Relocatable::PostGarbageCollectionProcessing() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005116 Isolate* isolate = Isolate::Current();
5117 Relocatable* current = isolate->relocatable_top();
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005118 while (current != NULL) {
5119 current->PostGarbageCollection();
5120 current = current->prev_;
5121 }
5122}
5123
5124
5125// Reserve space for statics needing saving and restoring.
5126int Relocatable::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127 return sizeof(Isolate::Current()->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005128}
5129
5130
5131// Archive statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005132char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5134 isolate->set_relocatable_top(NULL);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005135 return to + ArchiveSpacePerThread();
5136}
5137
5138
5139// Restore statics that are thread local.
lrn@chromium.org1c092762011-05-09 09:42:16 +00005140char* Relocatable::RestoreState(Isolate* isolate, char* from) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005141 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005142 return from + ArchiveSpacePerThread();
5143}
5144
5145
5146char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5147 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5148 Iterate(v, top);
5149 return thread_storage + ArchiveSpacePerThread();
5150}
5151
5152
5153void Relocatable::Iterate(ObjectVisitor* v) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005154 Isolate* isolate = Isolate::Current();
5155 Iterate(v, isolate->relocatable_top());
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005156}
5157
5158
5159void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5160 Relocatable* current = top;
5161 while (current != NULL) {
5162 current->IterateInstance(v);
5163 current = current->prev_;
5164 }
5165}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005166
5167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005168FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5169 : Relocatable(isolate),
5170 str_(str.location()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005171 length_(str->length()) {
5172 PostGarbageCollection();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005173}
5174
5175
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005176FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5177 : Relocatable(isolate),
5178 str_(0),
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005179 is_ascii_(true),
5180 length_(input.length()),
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005181 start_(input.start()) { }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005182
5183
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005184void FlatStringReader::PostGarbageCollection() {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005185 if (str_ == NULL) return;
5186 Handle<String> str(str_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005187 ASSERT(str->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00005188 is_ascii_ = str->IsAsciiRepresentation();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005189 if (is_ascii_) {
5190 start_ = str->ToAsciiVector().start();
5191 } else {
5192 start_ = str->ToUC16Vector().start();
5193 }
5194}
5195
5196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005197void StringInputBuffer::Seek(unsigned pos) {
5198 Reset(pos, input_);
5199}
5200
5201
5202void SafeStringInputBuffer::Seek(unsigned pos) {
5203 Reset(pos, input_);
5204}
5205
5206
5207// This method determines the type of string involved and then copies
5208// a whole chunk of characters into a buffer. It can be used with strings
5209// that have been glued together to form a ConsString and which must cooperate
5210// to fill up a buffer.
5211void String::ReadBlockIntoBuffer(String* input,
5212 ReadBlockBuffer* rbb,
5213 unsigned* offset_ptr,
5214 unsigned max_chars) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005215 ASSERT(*offset_ptr <= (unsigned)input->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005216 if (max_chars == 0) return;
5217
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005218 switch (StringShape(input).representation_tag()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005219 case kSeqStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005220 if (input->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005221 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005222 offset_ptr,
5223 max_chars);
5224 return;
5225 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005226 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005227 offset_ptr,
5228 max_chars);
5229 return;
5230 }
5231 case kConsStringTag:
5232 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5233 offset_ptr,
5234 max_chars);
5235 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005236 case kExternalStringTag:
ager@chromium.org5ec48922009-05-05 07:25:34 +00005237 if (input->IsAsciiRepresentation()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005238 ExternalAsciiString::cast(input)->
5239 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5240 } else {
5241 ExternalTwoByteString::cast(input)->
5242 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5243 offset_ptr,
5244 max_chars);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005245 }
5246 return;
5247 default:
5248 break;
5249 }
5250
5251 UNREACHABLE();
5252 return;
5253}
5254
5255
5256const unibrow::byte* String::ReadBlock(String* input,
5257 unibrow::byte* util_buffer,
5258 unsigned capacity,
5259 unsigned* remaining,
5260 unsigned* offset_ptr) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005261 ASSERT(*offset_ptr <= (unsigned)input->length());
5262 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5264 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005265 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005266 *remaining = rbb.remaining;
5267 return answer;
5268}
5269
5270
5271const unibrow::byte* String::ReadBlock(String** raw_input,
5272 unibrow::byte* util_buffer,
5273 unsigned capacity,
5274 unsigned* remaining,
5275 unsigned* offset_ptr) {
5276 Handle<String> input(raw_input);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005277 ASSERT(*offset_ptr <= (unsigned)input->length());
5278 unsigned chars = input->length() - *offset_ptr;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005279 if (chars > capacity) chars = capacity;
5280 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5281 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005282 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005283 *remaining = rbb.remaining;
5284 return rbb.util_buffer;
5285}
5286
5287
5288// This will iterate unless the block of string data spans two 'halves' of
5289// a ConsString, in which case it will recurse. Since the block of string
5290// data to be read has a maximum size this limits the maximum recursion
5291// depth to something sane. Since C++ does not have tail call recursion
5292// elimination, the iteration must be explicit.
5293void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5294 unsigned* offset_ptr,
5295 unsigned max_chars) {
5296 ConsString* current = this;
5297 unsigned offset = *offset_ptr;
5298 int offset_correction = 0;
5299
5300 while (true) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005301 String* left = current->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005302 unsigned left_length = (unsigned)left->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005303 if (left_length > offset &&
5304 max_chars <= left_length - offset) {
5305 // Left hand side only - iterate unless we have reached the bottom of
5306 // the cons tree.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005307 if (StringShape(left).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005308 current = ConsString::cast(left);
5309 continue;
5310 } else {
5311 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5312 *offset_ptr = offset + offset_correction;
5313 return;
5314 }
5315 } else if (left_length <= offset) {
5316 // Right hand side only - iterate unless we have reached the bottom of
5317 // the cons tree.
5318 offset -= left_length;
5319 offset_correction += left_length;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005320 String* right = current->second();
5321 if (StringShape(right).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005322 current = ConsString::cast(right);
5323 continue;
5324 } else {
5325 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5326 *offset_ptr = offset + offset_correction;
5327 return;
5328 }
5329 } else {
5330 // The block to be read spans two sides of the ConsString, so we recurse.
5331 // First recurse on the left.
5332 max_chars -= left_length - offset;
5333 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5334 // We may have reached the max or there may not have been enough space
5335 // in the buffer for the characters in the left hand side.
5336 if (offset == left_length) {
5337 // Recurse on the right.
5338 String* right = String::cast(current->second());
5339 offset -= left_length;
5340 offset_correction += left_length;
5341 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5342 }
5343 *offset_ptr = offset + offset_correction;
5344 return;
5345 }
5346 }
5347}
5348
5349
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005350uint16_t ConsString::ConsStringGet(int index) {
5351 ASSERT(index >= 0 && index < this->length());
5352
5353 // Check for a flattened cons string
ager@chromium.org870a0b62008-11-04 11:43:05 +00005354 if (second()->length() == 0) {
5355 String* left = first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005356 return left->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005357 }
5358
5359 String* string = String::cast(this);
5360
5361 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005362 if (StringShape(string).IsCons()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005363 ConsString* cons_string = ConsString::cast(string);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005364 String* left = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005365 if (left->length() > index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005366 string = left;
5367 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005368 index -= left->length();
ager@chromium.org870a0b62008-11-04 11:43:05 +00005369 string = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 }
5371 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005372 return string->Get(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005373 }
5374 }
5375
5376 UNREACHABLE();
5377 return 0;
5378}
5379
5380
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005381template <typename sinkchar>
5382void String::WriteToFlat(String* src,
5383 sinkchar* sink,
5384 int f,
5385 int t) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005386 String* source = src;
5387 int from = f;
5388 int to = t;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005389 while (true) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005390 ASSERT(0 <= from && from <= to && to <= source->length());
5391 switch (StringShape(source).full_representation_tag()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005392 case kAsciiStringTag | kExternalStringTag: {
5393 CopyChars(sink,
5394 ExternalAsciiString::cast(source)->resource()->data() + from,
5395 to - from);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 return;
5397 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005398 case kTwoByteStringTag | kExternalStringTag: {
5399 const uc16* data =
5400 ExternalTwoByteString::cast(source)->resource()->data();
5401 CopyChars(sink,
5402 data + from,
5403 to - from);
5404 return;
5405 }
5406 case kAsciiStringTag | kSeqStringTag: {
5407 CopyChars(sink,
5408 SeqAsciiString::cast(source)->GetChars() + from,
5409 to - from);
5410 return;
5411 }
5412 case kTwoByteStringTag | kSeqStringTag: {
5413 CopyChars(sink,
5414 SeqTwoByteString::cast(source)->GetChars() + from,
5415 to - from);
5416 return;
5417 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005418 case kAsciiStringTag | kConsStringTag:
5419 case kTwoByteStringTag | kConsStringTag: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420 ConsString* cons_string = ConsString::cast(source);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005421 String* first = cons_string->first();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005422 int boundary = first->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005423 if (to - boundary >= boundary - from) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 // Right hand side is longer. Recurse over left.
5425 if (from < boundary) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 WriteToFlat(first, sink, from, boundary);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005427 sink += boundary - from;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005428 from = 0;
5429 } else {
5430 from -= boundary;
5431 }
5432 to -= boundary;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005433 source = cons_string->second();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005434 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005435 // Left hand side is longer. Recurse over right.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005436 if (to > boundary) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005437 String* second = cons_string->second();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005438 WriteToFlat(second,
5439 sink + boundary - from,
5440 0,
5441 to - boundary);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005442 to = boundary;
5443 }
5444 source = first;
5445 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005446 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005448 }
5449 }
5450}
5451
5452
ager@chromium.org7c537e22008-10-16 08:43:32 +00005453template <typename IteratorA, typename IteratorB>
5454static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5455 // General slow case check. We know that the ia and ib iterators
5456 // have the same length.
5457 while (ia->has_more()) {
5458 uc32 ca = ia->GetNext();
5459 uc32 cb = ib->GetNext();
5460 if (ca != cb)
5461 return false;
5462 }
5463 return true;
5464}
5465
5466
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005467// Compares the contents of two strings by reading and comparing
5468// int-sized blocks of characters.
5469template <typename Char>
5470static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5471 int length = a.length();
5472 ASSERT_EQ(length, b.length());
5473 const Char* pa = a.start();
5474 const Char* pb = b.start();
5475 int i = 0;
ager@chromium.org9085a012009-05-11 19:22:57 +00005476#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005477 // If this architecture isn't comfortable reading unaligned ints
5478 // then we have to check that the strings are aligned before
5479 // comparing them blockwise.
5480 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5481 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5482 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005483 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005484#endif
5485 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5486 int endpoint = length - kStepSize;
5487 // Compare blocks until we reach near the end of the string.
5488 for (; i <= endpoint; i += kStepSize) {
5489 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5490 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5491 if (wa != wb) {
5492 return false;
5493 }
5494 }
ager@chromium.org9085a012009-05-11 19:22:57 +00005495#ifndef V8_HOST_CAN_READ_UNALIGNED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005496 }
5497#endif
5498 // Compare the remaining characters that didn't fit into a block.
5499 for (; i < length; i++) {
5500 if (a[i] != b[i]) {
5501 return false;
5502 }
5503 }
5504 return true;
5505}
5506
5507
ager@chromium.org7c537e22008-10-16 08:43:32 +00005508template <typename IteratorA>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005509static inline bool CompareStringContentsPartial(Isolate* isolate,
5510 IteratorA* ia,
5511 String* b) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005512 if (b->IsFlat()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005513 if (b->IsAsciiRepresentation()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005514 VectorIterator<char> ib(b->ToAsciiVector());
5515 return CompareStringContents(ia, &ib);
5516 } else {
ager@chromium.org9085a012009-05-11 19:22:57 +00005517 VectorIterator<uc16> ib(b->ToUC16Vector());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005518 return CompareStringContents(ia, &ib);
5519 }
5520 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005521 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5522 return CompareStringContents(ia,
5523 isolate->objects_string_compare_buffer_b());
ager@chromium.org7c537e22008-10-16 08:43:32 +00005524 }
5525}
5526
5527
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005528bool String::SlowEquals(String* other) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005529 // Fast check: negative check with lengths.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005530 int len = length();
5531 if (len != other->length()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005532 if (len == 0) return true;
5533
5534 // Fast check: if hash code is computed for both strings
5535 // a fast negative check can be performed.
5536 if (HasHashCode() && other->HasHashCode()) {
5537 if (Hash() != other->Hash()) return false;
5538 }
5539
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005540 // We know the strings are both non-empty. Compare the first chars
5541 // before we try to flatten the strings.
5542 if (this->Get(0) != other->Get(0)) return false;
5543
5544 String* lhs = this->TryFlattenGetString();
5545 String* rhs = other->TryFlattenGetString();
5546
5547 if (StringShape(lhs).IsSequentialAscii() &&
5548 StringShape(rhs).IsSequentialAscii()) {
5549 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5550 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005551 return CompareRawStringContents(Vector<const char>(str1, len),
5552 Vector<const char>(str2, len));
5553 }
5554
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005555 Isolate* isolate = GetIsolate();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005556 if (lhs->IsFlat()) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00005557 if (lhs->IsAsciiRepresentation()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005558 Vector<const char> vec1 = lhs->ToAsciiVector();
5559 if (rhs->IsFlat()) {
5560 if (rhs->IsAsciiRepresentation()) {
5561 Vector<const char> vec2 = rhs->ToAsciiVector();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005562 return CompareRawStringContents(vec1, vec2);
5563 } else {
5564 VectorIterator<char> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005565 VectorIterator<uc16> ib(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005566 return CompareStringContents(&buf1, &ib);
5567 }
5568 } else {
5569 VectorIterator<char> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005570 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5571 return CompareStringContents(&buf1,
5572 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005573 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005574 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005575 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5576 if (rhs->IsFlat()) {
5577 if (rhs->IsAsciiRepresentation()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005578 VectorIterator<uc16> buf1(vec1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005579 VectorIterator<char> ib(rhs->ToAsciiVector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005580 return CompareStringContents(&buf1, &ib);
5581 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00005582 Vector<const uc16> vec2(rhs->ToUC16Vector());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005583 return CompareRawStringContents(vec1, vec2);
5584 }
5585 } else {
5586 VectorIterator<uc16> buf1(vec1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005587 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5588 return CompareStringContents(&buf1,
5589 isolate->objects_string_compare_buffer_b());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005590 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005591 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005592 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005593 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5594 return CompareStringContentsPartial(isolate,
5595 isolate->objects_string_compare_buffer_a(), rhs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005596 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005597}
5598
5599
5600bool String::MarkAsUndetectable() {
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00005601 if (StringShape(this).IsSymbol()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005602
5603 Map* map = this->map();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005604 Heap* heap = map->heap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005605 if (map == heap->string_map()) {
5606 this->set_map(heap->undetectable_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005607 return true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005608 } else if (map == heap->ascii_string_map()) {
5609 this->set_map(heap->undetectable_ascii_string_map());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005610 return true;
5611 }
5612 // Rest cannot be marked as undetectable
5613 return false;
5614}
5615
5616
5617bool String::IsEqualTo(Vector<const char> str) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618 Isolate* isolate = GetIsolate();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005619 int slen = length();
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005620 Access<UnicodeCache::Utf8Decoder>
5621 decoder(isolate->unicode_cache()->utf8_decoder());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005622 decoder->Reset(str.start(), str.length());
5623 int i;
5624 for (i = 0; i < slen && decoder->has_more(); i++) {
5625 uc32 r = decoder->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005626 if (Get(i) != r) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005627 }
5628 return i == slen && !decoder->has_more();
5629}
5630
5631
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005632bool String::IsAsciiEqualTo(Vector<const char> str) {
5633 int slen = length();
5634 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005635 if (IsFlat() && IsAsciiRepresentation()) {
5636 return CompareChars(ToAsciiVector().start(), str.start(), slen) == 0;
5637 }
5638 for (int i = 0; i < slen; i++) {
5639 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005640 }
5641 return true;
5642}
5643
5644
5645bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
5646 int slen = length();
5647 if (str.length() != slen) return false;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005648 if (IsFlat() && IsTwoByteRepresentation()) {
5649 return CompareChars(ToUC16Vector().start(), str.start(), slen) == 0;
5650 }
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00005651 for (int i = 0; i < slen; i++) {
5652 if (Get(i) != str[i]) return false;
5653 }
5654 return true;
5655}
5656
5657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005658uint32_t String::ComputeAndSetHash() {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005659 // Should only be called if hash code has not yet been computed.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005660 ASSERT(!HasHashCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005661
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00005662 const int len = length();
5663
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005664 // Compute the hash code.
ricow@chromium.orgaa1b6162010-03-29 07:44:58 +00005665 uint32_t field = 0;
5666 if (StringShape(this).IsSequentialAscii()) {
5667 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
5668 } else if (StringShape(this).IsSequentialTwoByte()) {
5669 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
5670 } else {
5671 StringInputBuffer buffer(this);
5672 field = ComputeHashField(&buffer, len);
5673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005674
5675 // Store the hash code in the object.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005676 set_hash_field(field);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005677
5678 // Check the hash code is there.
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005679 ASSERT(HasHashCode());
ager@chromium.org3b45ab52009-03-19 22:21:34 +00005680 uint32_t result = field >> kHashShift;
5681 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
5682 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005683}
5684
5685
5686bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
5687 uint32_t* index,
5688 int length) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005689 if (length == 0 || length > kMaxArrayIndexSize) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005690 uc32 ch = buffer->GetNext();
5691
5692 // If the string begins with a '0' character, it must only consist
5693 // of it to be a legal array index.
5694 if (ch == '0') {
5695 *index = 0;
5696 return length == 1;
5697 }
5698
5699 // Convert string to uint32 array index; character by character.
5700 int d = ch - '0';
5701 if (d < 0 || d > 9) return false;
5702 uint32_t result = d;
5703 while (buffer->has_more()) {
5704 d = buffer->GetNext() - '0';
5705 if (d < 0 || d > 9) return false;
5706 // Check that the new result is below the 32 bit limit.
5707 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
5708 result = (result * 10) + d;
5709 }
5710
5711 *index = result;
5712 return true;
5713}
5714
5715
5716bool String::SlowAsArrayIndex(uint32_t* index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005717 if (length() <= kMaxCachedArrayIndexLength) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005718 Hash(); // force computation of hash code
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005719 uint32_t field = hash_field();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00005720 if ((field & kIsNotArrayIndexMask) != 0) return false;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005721 // Isolate the array index form the full hash field.
5722 *index = (kArrayIndexHashMask & field) >> kHashShift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005723 return true;
5724 } else {
5725 StringInputBuffer buffer(this);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005726 return ComputeArrayIndex(&buffer, index, length());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005727 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005728}
5729
5730
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005731uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005732 // For array indexes mix the length into the hash as an array index could
5733 // be zero.
5734 ASSERT(length > 0);
5735 ASSERT(length <= String::kMaxArrayIndexSize);
5736 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5737 (1 << String::kArrayIndexValueBits));
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005738
5739 value <<= String::kHashShift;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005740 value |= length << String::kArrayIndexHashLengthShift;
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005741
5742 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
5743 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
5744 (value & String::kContainsCachedArrayIndexMask) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005745 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005746}
5747
5748
ager@chromium.org7c537e22008-10-16 08:43:32 +00005749uint32_t StringHasher::GetHashField() {
5750 ASSERT(is_valid());
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005751 if (length_ <= String::kMaxHashCalcLength) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005752 if (is_array_index()) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005753 return MakeArrayIndexHash(array_index(), length_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00005754 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005755 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005756 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005757 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005758 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005759}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005761
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00005762uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
5763 int length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005764 StringHasher hasher(length);
5765
5766 // Very long strings have a trivial hash that doesn't inspect the
5767 // string contents.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005768 if (hasher.has_trivial_hash()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005769 return hasher.GetHashField();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005770 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005771
5772 // Do the iterative array index computation as long as there is a
5773 // chance this is an array index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005774 while (buffer->has_more() && hasher.is_array_index()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005775 hasher.AddCharacter(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005776 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005777
5778 // Process the remaining characters without updating the array
5779 // index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005780 while (buffer->has_more()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005781 hasher.AddCharacterNoIndex(buffer->GetNext());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005782 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00005783
5784 return hasher.GetHashField();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005785}
5786
5787
lrn@chromium.org303ada72010-10-27 09:33:13 +00005788MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005789 Heap* heap = GetHeap();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005790 if (start == 0 && end == length()) return this;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005792 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005793}
5794
5795
5796void String::PrintOn(FILE* file) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005797 int length = this->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005798 for (int i = 0; i < length; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005799 fprintf(file, "%c", Get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005800 }
5801}
5802
5803
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005804void Map::CreateBackPointers() {
5805 DescriptorArray* descriptors = instance_descriptors();
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005806 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00005807 if (descriptors->GetType(i) == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005808 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00005809 descriptors->GetType(i) == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005810 // Get target.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005811 Map* target = Map::cast(descriptors->GetValue(i));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005812#ifdef DEBUG
5813 // Verify target.
5814 Object* source_prototype = prototype();
5815 Object* target_prototype = target->prototype();
5816 ASSERT(source_prototype->IsJSObject() ||
5817 source_prototype->IsMap() ||
5818 source_prototype->IsNull());
5819 ASSERT(target_prototype->IsJSObject() ||
5820 target_prototype->IsNull());
5821 ASSERT(source_prototype->IsMap() ||
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00005822 source_prototype == target_prototype);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005823#endif
5824 // Point target back to source. set_prototype() will not let us set
5825 // the prototype to a map, as we do here.
5826 *RawField(target, kPrototypeOffset) = this;
5827 }
5828 }
5829}
5830
5831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005832void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005833 // Live DescriptorArray objects will be marked, so we must use
5834 // low-level accessors to get and modify their data.
5835 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
danno@chromium.org40cb8782011-05-25 07:58:50 +00005836 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
5837 if (d->IsEmpty()) return;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005838 Smi* NullDescriptorDetails =
5839 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
5840 FixedArray* contents = reinterpret_cast<FixedArray*>(
5841 d->get(DescriptorArray::kContentArrayIndex));
5842 ASSERT(contents->length() >= 2);
5843 for (int i = 0; i < contents->length(); i += 2) {
5844 // If the pair (value, details) is a map transition,
5845 // check if the target is live. If not, null the descriptor.
5846 // Also drop the back pointer for that map transition, so that this
5847 // map is not reached again by following a back pointer from a
5848 // non-live object.
5849 PropertyDetails details(Smi::cast(contents->get(i + 1)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00005850 if (details.type() == MAP_TRANSITION ||
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005851 details.type() == EXTERNAL_ARRAY_TRANSITION ||
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00005852 details.type() == CONSTANT_TRANSITION) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005853 Map* target = reinterpret_cast<Map*>(contents->get(i));
5854 ASSERT(target->IsHeapObject());
5855 if (!target->IsMarked()) {
5856 ASSERT(target->IsMap());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00005857 contents->set_unchecked(i + 1, NullDescriptorDetails);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005858 contents->set_null_unchecked(heap, i);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005859 ASSERT(target->prototype() == this ||
5860 target->prototype() == real_prototype);
5861 // Getter prototype() is read-only, set_prototype() has side effects.
5862 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5863 }
5864 }
5865 }
5866}
5867
5868
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00005869void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5870 // Iterate over all fields in the body but take care in dealing with
5871 // the code entry.
5872 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5873 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5874 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5875}
5876
5877
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005878void JSFunction::MarkForLazyRecompilation() {
5879 ASSERT(is_compiled() && !IsOptimized());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005880 ASSERT(shared()->allows_lazy_compilation() ||
5881 code()->optimizable());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005882 Builtins* builtins = GetIsolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005883 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005884}
5885
5886
5887uint32_t JSFunction::SourceHash() {
5888 uint32_t hash = 0;
5889 Object* script = shared()->script();
5890 if (!script->IsUndefined()) {
5891 Object* source = Script::cast(script)->source();
5892 if (source->IsUndefined()) hash = String::cast(source)->Hash();
5893 }
5894 hash ^= ComputeIntegerHash(shared()->start_position_and_type());
5895 hash += ComputeIntegerHash(shared()->end_position());
5896 return hash;
5897}
5898
5899
5900bool JSFunction::IsInlineable() {
5901 if (IsBuiltin()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00005902 SharedFunctionInfo* shared_info = shared();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005903 // Check that the function has a script associated with it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00005904 if (!shared_info->script()->IsScript()) return false;
5905 if (shared_info->optimization_disabled()) return false;
5906 Code* code = shared_info->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005907 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
5908 // If we never ran this (unlikely) then lets try to optimize it.
5909 if (code->kind() != Code::FUNCTION) return true;
5910 return code->optimizable();
5911}
5912
5913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005914Object* JSFunction::SetInstancePrototype(Object* value) {
5915 ASSERT(value->IsJSObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005916 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005917 if (has_initial_map()) {
5918 initial_map()->set_prototype(value);
5919 } else {
5920 // Put the value in the initial map field until an initial map is
5921 // needed. At that point, a new initial map is created and the
5922 // prototype is put into the initial map where it belongs.
5923 set_prototype_or_initial_map(value);
5924 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005925 heap->ClearInstanceofCache();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005926 return value;
5927}
5928
5929
lrn@chromium.org303ada72010-10-27 09:33:13 +00005930MaybeObject* JSFunction::SetPrototype(Object* value) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005931 ASSERT(should_have_prototype());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005932 Object* construct_prototype = value;
5933
5934 // If the value is not a JSObject, store the value in the map's
5935 // constructor field so it can be accessed. Also, set the prototype
5936 // used for constructing objects to the original object prototype.
5937 // See ECMA-262 13.2.2.
5938 if (!value->IsJSObject()) {
5939 // Copy the map so this does not affect unrelated functions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005940 // Remove map transitions because they point to maps with a
5941 // different prototype.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005942 Object* new_object;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005943 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005944 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
lrn@chromium.org303ada72010-10-27 09:33:13 +00005945 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005946 Map* new_map = Map::cast(new_object);
5947 Heap* heap = new_map->heap();
5948 set_map(new_map);
5949 new_map->set_constructor(value);
5950 new_map->set_non_instance_prototype(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005951 construct_prototype =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005952 heap->isolate()->context()->global_context()->
5953 initial_object_prototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005954 } else {
5955 map()->set_non_instance_prototype(false);
5956 }
5957
5958 return SetInstancePrototype(construct_prototype);
5959}
5960
5961
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005962Object* JSFunction::RemovePrototype() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005963 Context* global_context = context()->global_context();
5964 Map* no_prototype_map = shared()->strict_mode()
5965 ? global_context->strict_mode_function_without_prototype_map()
5966 : global_context->function_without_prototype_map();
5967
5968 if (map() == no_prototype_map) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00005969 // Be idempotent.
5970 return this;
5971 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005972
5973 ASSERT(!shared()->strict_mode() ||
5974 map() == global_context->strict_mode_function_map());
5975 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
5976
5977 set_map(no_prototype_map);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005978 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00005979 return this;
5980}
5981
5982
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983Object* JSFunction::SetInstanceClassName(String* name) {
5984 shared()->set_instance_class_name(name);
5985 return this;
5986}
5987
5988
whesse@chromium.org023421e2010-12-21 12:19:12 +00005989void JSFunction::PrintName(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005990 SmartPointer<char> name = shared()->DebugName()->ToCString();
whesse@chromium.org023421e2010-12-21 12:19:12 +00005991 PrintF(out, "%s", *name);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005992}
5993
5994
ager@chromium.org236ad962008-09-25 09:45:57 +00005995Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
5996 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
5997}
5998
5999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006000MaybeObject* Oddball::Initialize(const char* to_string,
6001 Object* to_number,
6002 byte kind) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006003 Object* symbol;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006004 { MaybeObject* maybe_symbol =
6005 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006006 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6007 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006008 set_to_string(String::cast(symbol));
6009 set_to_number(to_number);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006010 set_kind(kind);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 return this;
6012}
6013
6014
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00006015String* SharedFunctionInfo::DebugName() {
6016 Object* n = name();
6017 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6018 return String::cast(n);
6019}
6020
6021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022bool SharedFunctionInfo::HasSourceCode() {
6023 return !script()->IsUndefined() &&
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00006024 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025}
6026
6027
6028Object* SharedFunctionInfo::GetSourceCode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006029 Isolate* isolate = GetIsolate();
6030 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6031 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006032 Object* source = Script::cast(script())->source();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006033 return *SubString(Handle<String>(String::cast(source), isolate),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006034 start_position(), end_position());
6035}
6036
6037
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006038int SharedFunctionInfo::SourceSize() {
6039 return end_position() - start_position();
6040}
6041
6042
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006043int SharedFunctionInfo::CalculateInstanceSize() {
6044 int instance_size =
6045 JSObject::kHeaderSize +
6046 expected_nof_properties() * kPointerSize;
6047 if (instance_size > JSObject::kMaxInstanceSize) {
6048 instance_size = JSObject::kMaxInstanceSize;
6049 }
6050 return instance_size;
6051}
6052
6053
6054int SharedFunctionInfo::CalculateInObjectProperties() {
6055 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6056}
6057
6058
ager@chromium.org5c838252010-02-19 08:53:10 +00006059bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6060 // Check the basic conditions for generating inline constructor code.
6061 if (!FLAG_inline_new
6062 || !has_only_simple_this_property_assignments()
6063 || this_property_assignments_count() == 0) {
6064 return false;
6065 }
6066
6067 // If the prototype is null inline constructors cause no problems.
6068 if (!prototype->IsJSObject()) {
6069 ASSERT(prototype->IsNull());
6070 return true;
6071 }
6072
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006073 Heap* heap = GetHeap();
6074
ager@chromium.org5c838252010-02-19 08:53:10 +00006075 // Traverse the proposed prototype chain looking for setters for properties of
6076 // the same names as are set by the inline constructor.
6077 for (Object* obj = prototype;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006078 obj != heap->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00006079 obj = obj->GetPrototype()) {
6080 JSObject* js_object = JSObject::cast(obj);
6081 for (int i = 0; i < this_property_assignments_count(); i++) {
6082 LookupResult result;
6083 String* name = GetThisPropertyAssignmentName(i);
6084 js_object->LocalLookupRealNamedProperty(name, &result);
6085 if (result.IsProperty() && result.type() == CALLBACKS) {
6086 return false;
6087 }
6088 }
6089 }
6090
6091 return true;
6092}
6093
6094
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00006095void SharedFunctionInfo::ForbidInlineConstructor() {
6096 set_compiler_hints(BooleanBit::set(compiler_hints(),
6097 kHasOnlySimpleThisPropertyAssignments,
6098 false));
6099}
6100
6101
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006102void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006103 bool only_simple_this_property_assignments,
6104 FixedArray* assignments) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006105 set_compiler_hints(BooleanBit::set(compiler_hints(),
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006106 kHasOnlySimpleThisPropertyAssignments,
6107 only_simple_this_property_assignments));
6108 set_this_property_assignments(assignments);
6109 set_this_property_assignments_count(assignments->length() / 3);
6110}
6111
6112
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006113void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006114 Heap* heap = GetHeap();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006115 set_compiler_hints(BooleanBit::set(compiler_hints(),
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006116 kHasOnlySimpleThisPropertyAssignments,
6117 false));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006118 set_this_property_assignments(heap->undefined_value());
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006119 set_this_property_assignments_count(0);
6120}
6121
6122
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006123String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6124 Object* obj = this_property_assignments();
6125 ASSERT(obj->IsFixedArray());
6126 ASSERT(index < this_property_assignments_count());
6127 obj = FixedArray::cast(obj)->get(index * 3);
6128 ASSERT(obj->IsString());
6129 return String::cast(obj);
6130}
6131
6132
ager@chromium.org18ad94b2009-09-02 08:22:29 +00006133bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6134 Object* obj = this_property_assignments();
6135 ASSERT(obj->IsFixedArray());
6136 ASSERT(index < this_property_assignments_count());
6137 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6138 return Smi::cast(obj)->value() != -1;
6139}
6140
6141
6142int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6143 ASSERT(IsThisPropertyAssignmentArgument(index));
6144 Object* obj =
6145 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6146 return Smi::cast(obj)->value();
6147}
6148
6149
6150Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6151 ASSERT(!IsThisPropertyAssignmentArgument(index));
6152 Object* obj =
6153 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6154 return obj;
6155}
6156
6157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006158// Support function for printing the source code to a StringStream
6159// without any allocation in the heap.
6160void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6161 int max_length) {
6162 // For some native functions there is no source.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006163 if (!HasSourceCode()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006164 accumulator->Add("<No Source>");
6165 return;
6166 }
6167
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006168 // Get the source for the script which this function came from.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169 // Don't use String::cast because we don't want more assertion errors while
6170 // we are already creating a stack dump.
6171 String* script_source =
6172 reinterpret_cast<String*>(Script::cast(script())->source());
6173
6174 if (!script_source->LooksValid()) {
6175 accumulator->Add("<Invalid Source>");
6176 return;
6177 }
6178
6179 if (!is_toplevel()) {
6180 accumulator->Add("function ");
6181 Object* name = this->name();
6182 if (name->IsString() && String::cast(name)->length() > 0) {
6183 accumulator->PrintName(name);
6184 }
6185 }
6186
6187 int len = end_position() - start_position();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006188 if (len <= max_length || max_length < 0) {
6189 accumulator->Put(script_source, start_position(), end_position());
6190 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006191 accumulator->Put(script_source,
6192 start_position(),
6193 start_position() + max_length);
6194 accumulator->Add("...\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006195 }
6196}
6197
6198
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006199static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6200 if (code->instruction_size() != recompiled->instruction_size()) return false;
6201 ByteArray* code_relocation = code->relocation_info();
6202 ByteArray* recompiled_relocation = recompiled->relocation_info();
6203 int length = code_relocation->length();
6204 if (length != recompiled_relocation->length()) return false;
6205 int compare = memcmp(code_relocation->GetDataStartAddress(),
6206 recompiled_relocation->GetDataStartAddress(),
6207 length);
6208 return compare == 0;
6209}
6210
6211
6212void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6213 ASSERT(!has_deoptimization_support());
6214 AssertNoAllocation no_allocation;
6215 Code* code = this->code();
6216 if (IsCodeEquivalent(code, recompiled)) {
6217 // Copy the deoptimization data from the recompiled code.
6218 code->set_deoptimization_data(recompiled->deoptimization_data());
6219 code->set_has_deoptimization_support(true);
6220 } else {
6221 // TODO(3025757): In case the recompiled isn't equivalent to the
6222 // old code, we have to replace it. We should try to avoid this
6223 // altogether because it flushes valuable type feedback by
6224 // effectively resetting all IC state.
6225 set_code(recompiled);
6226 }
6227 ASSERT(has_deoptimization_support());
6228}
6229
6230
ager@chromium.orgea91cc52011-05-23 06:06:11 +00006231void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6232 // Disable optimization for the shared function info and mark the
6233 // code as non-optimizable. The marker on the shared function info
6234 // is there because we flush non-optimized code thereby loosing the
6235 // non-optimizable information for the code. When the code is
6236 // regenerated and set on the shared function info it is marked as
6237 // non-optimizable if optimization is disabled for the shared
6238 // function info.
6239 set_optimization_disabled(true);
6240 // Code should be the lazy compilation stub or else unoptimized. If the
6241 // latter, disable optimization for the code too.
6242 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6243 if (code()->kind() == Code::FUNCTION) {
6244 code()->set_optimizable(false);
6245 }
6246 if (FLAG_trace_opt) {
6247 PrintF("[disabled optimization for: ");
6248 function->PrintName();
6249 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6250 }
6251}
6252
6253
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006254bool SharedFunctionInfo::VerifyBailoutId(int id) {
6255 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6256 // we are always bailing out on ARM.
6257
6258 ASSERT(id != AstNode::kNoNumber);
6259 Code* unoptimized = code();
6260 DeoptimizationOutputData* data =
6261 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6262 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6263 USE(ignore);
6264 return true; // Return true if there was no ASSERT.
6265}
6266
6267
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006268void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6269 ASSERT(!IsInobjectSlackTrackingInProgress());
6270
6271 // Only initiate the tracking the first time.
6272 if (live_objects_may_exist()) return;
6273 set_live_objects_may_exist(true);
6274
6275 // No tracking during the snapshot construction phase.
6276 if (Serializer::enabled()) return;
6277
6278 if (map->unused_property_fields() == 0) return;
6279
6280 // Nonzero counter is a leftover from the previous attempt interrupted
6281 // by GC, keep it.
6282 if (construction_count() == 0) {
6283 set_construction_count(kGenerousAllocationCount);
6284 }
6285 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006286 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006287 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006288 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006289 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006290}
6291
6292
6293// Called from GC, hence reinterpret_cast and unchecked accessors.
6294void SharedFunctionInfo::DetachInitialMap() {
6295 Map* map = reinterpret_cast<Map*>(initial_map());
6296
6297 // Make the map remember to restore the link if it survives the GC.
6298 map->set_bit_field2(
6299 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6300
6301 // Undo state changes made by StartInobjectTracking (except the
6302 // construction_count). This way if the initial map does not survive the GC
6303 // then StartInobjectTracking will be called again the next time the
6304 // constructor is called. The countdown will continue and (possibly after
6305 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006306 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6307 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006308 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006309 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006310 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006311 // It is safe to clear the flag: it will be set again if the map is live.
6312 set_live_objects_may_exist(false);
6313}
6314
6315
6316// Called from GC, hence reinterpret_cast and unchecked accessors.
6317void SharedFunctionInfo::AttachInitialMap(Map* map) {
6318 map->set_bit_field2(
6319 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6320
6321 // Resume inobject slack tracking.
6322 set_initial_map(map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006323 Builtins* builtins = map->heap()->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006324 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006325 *RawField(this, kConstructStubOffset));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006326 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006327 // The map survived the gc, so there may be objects referencing it.
6328 set_live_objects_may_exist(true);
6329}
6330
6331
6332static void GetMinInobjectSlack(Map* map, void* data) {
6333 int slack = map->unused_property_fields();
6334 if (*reinterpret_cast<int*>(data) > slack) {
6335 *reinterpret_cast<int*>(data) = slack;
6336 }
6337}
6338
6339
6340static void ShrinkInstanceSize(Map* map, void* data) {
6341 int slack = *reinterpret_cast<int*>(data);
6342 map->set_inobject_properties(map->inobject_properties() - slack);
6343 map->set_unused_property_fields(map->unused_property_fields() - slack);
6344 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6345
6346 // Visitor id might depend on the instance size, recalculate it.
6347 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6348}
6349
6350
6351void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6352 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6353 Map* map = Map::cast(initial_map());
6354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006355 Heap* heap = map->heap();
6356 set_initial_map(heap->undefined_value());
6357 Builtins* builtins = heap->isolate()->builtins();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006358 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006359 construct_stub());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006360 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00006361
6362 int slack = map->unused_property_fields();
6363 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6364 if (slack != 0) {
6365 // Resize the initial map and all maps in its transition tree.
6366 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
6367 // Give the correct expected_nof_properties to initial maps created later.
6368 ASSERT(expected_nof_properties() >= slack);
6369 set_expected_nof_properties(expected_nof_properties() - slack);
6370 }
6371}
6372
6373
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006374void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006375 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006376 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6377 Object* old_target = target;
6378 VisitPointer(&target);
6379 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006380}
6381
6382
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00006383void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6384 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6385 Object* old_code = code;
6386 VisitPointer(&code);
6387 if (code != old_code) {
6388 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6389 }
6390}
6391
6392
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006393void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6394 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6395 Object* cell = rinfo->target_cell();
6396 Object* old_cell = cell;
6397 VisitPointer(&cell);
6398 if (cell != old_cell) {
6399 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6400 }
6401}
6402
6403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006404void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00006405 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6406 rinfo->IsPatchedReturnSequence()) ||
6407 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6408 rinfo->IsPatchedDebugBreakSlotSequence()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00006409 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6410 Object* old_target = target;
6411 VisitPointer(&target);
6412 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006413}
6414
6415
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006416void Code::InvalidateRelocation() {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006417 set_relocation_info(heap()->empty_byte_array());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006418}
6419
6420
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006421void Code::Relocate(intptr_t delta) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6423 it.rinfo()->apply(delta);
6424 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006425 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006426}
6427
6428
6429void Code::CopyFrom(const CodeDesc& desc) {
6430 // copy code
6431 memmove(instruction_start(), desc.buffer, desc.instr_size);
6432
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433 // copy reloc info
6434 memmove(relocation_start(),
6435 desc.buffer + desc.buffer_size - desc.reloc_size,
6436 desc.reloc_size);
6437
6438 // unbox handles and relocate
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006439 intptr_t delta = instruction_start() - desc.buffer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006440 int mode_mask = RelocInfo::kCodeTargetMask |
ager@chromium.org236ad962008-09-25 09:45:57 +00006441 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006442 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006443 RelocInfo::kApplyMask;
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006444 Assembler* origin = desc.origin; // Needed to find target_object on X64.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006445 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006446 RelocInfo::Mode mode = it.rinfo()->rmode();
6447 if (mode == RelocInfo::EMBEDDED_OBJECT) {
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006448 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449 it.rinfo()->set_target_object(*p);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006450 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006451 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006452 it.rinfo()->set_target_cell(*cell);
ager@chromium.org236ad962008-09-25 09:45:57 +00006453 } else if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006454 // rewrite code handles in inline cache targets to direct
6455 // pointers to the first instruction in the code object
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00006456 Handle<Object> p = it.rinfo()->target_object_handle(origin);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006457 Code* code = Code::cast(*p);
6458 it.rinfo()->set_target_address(code->instruction_start());
6459 } else {
6460 it.rinfo()->apply(delta);
6461 }
6462 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006463 CPU::FlushICache(instruction_start(), instruction_size());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006464}
6465
6466
6467// Locate the source position which is closest to the address in the code. This
6468// is using the source position information embedded in the relocation info.
6469// The position returned is relative to the beginning of the script where the
6470// source for this function is found.
6471int Code::SourcePosition(Address pc) {
6472 int distance = kMaxInt;
ager@chromium.org236ad962008-09-25 09:45:57 +00006473 int position = RelocInfo::kNoPosition; // Initially no position found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 // Run through all the relocation info to find the best matching source
6475 // position. All the code needs to be considered as the sequence of the
6476 // instructions in the code does not necessarily follow the same order as the
6477 // source.
6478 RelocIterator it(this, RelocInfo::kPositionMask);
6479 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006480 // Only look at positions after the current pc.
6481 if (it.rinfo()->pc() < pc) {
6482 // Get position and distance.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006483
6484 int dist = static_cast<int>(pc - it.rinfo()->pc());
6485 int pos = static_cast<int>(it.rinfo()->data());
ager@chromium.org236ad962008-09-25 09:45:57 +00006486 // If this position is closer than the current candidate or if it has the
6487 // same distance as the current candidate and the position is higher then
6488 // this position is the new candidate.
6489 if ((dist < distance) ||
6490 (dist == distance && pos > position)) {
6491 position = pos;
6492 distance = dist;
6493 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006494 }
6495 it.next();
6496 }
6497 return position;
6498}
6499
6500
6501// Same as Code::SourcePosition above except it only looks for statement
6502// positions.
6503int Code::SourceStatementPosition(Address pc) {
6504 // First find the position as close as possible using all position
6505 // information.
6506 int position = SourcePosition(pc);
6507 // Now find the closest statement position before the position.
6508 int statement_position = 0;
6509 RelocIterator it(this, RelocInfo::kPositionMask);
6510 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00006511 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006512 int p = static_cast<int>(it.rinfo()->data());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513 if (statement_position < p && p <= position) {
6514 statement_position = p;
6515 }
6516 }
6517 it.next();
6518 }
6519 return statement_position;
6520}
6521
6522
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006523SafepointEntry Code::GetSafepointEntry(Address pc) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006524 SafepointTable table(this);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006525 return table.FindEntry(pc);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006526}
6527
6528
6529void Code::SetNoStackCheckTable() {
6530 // Indicate the absence of a stack-check table by a table start after the
6531 // end of the instructions. Table start must be aligned, so round up.
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006532 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006533}
6534
6535
6536Map* Code::FindFirstMap() {
6537 ASSERT(is_inline_cache_stub());
6538 AssertNoAllocation no_allocation;
6539 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6540 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6541 RelocInfo* info = it.rinfo();
6542 Object* object = info->target_object();
6543 if (object->IsMap()) return Map::cast(object);
6544 }
6545 return NULL;
6546}
6547
6548
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006549#ifdef ENABLE_DISASSEMBLER
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006550
whesse@chromium.org023421e2010-12-21 12:19:12 +00006551#ifdef OBJECT_PRINT
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006552
whesse@chromium.org023421e2010-12-21 12:19:12 +00006553void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006554 disasm::NameConverter converter;
6555 int deopt_count = DeoptCount();
whesse@chromium.org023421e2010-12-21 12:19:12 +00006556 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006557 if (0 == deopt_count) return;
6558
whesse@chromium.org023421e2010-12-21 12:19:12 +00006559 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006560 for (int i = 0; i < deopt_count; i++) {
6561 int command_count = 0;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006562 PrintF(out, "%6d %6d %6d",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006563 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
6564 int translation_index = TranslationIndex(i)->value();
6565 TranslationIterator iterator(TranslationByteArray(), translation_index);
6566 Translation::Opcode opcode =
6567 static_cast<Translation::Opcode>(iterator.Next());
6568 ASSERT(Translation::BEGIN == opcode);
6569 int frame_count = iterator.Next();
6570 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006571 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6572 frame_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006573 }
6574
6575 for (int i = 0; i < frame_count; ++i) {
6576 opcode = static_cast<Translation::Opcode>(iterator.Next());
6577 ASSERT(Translation::FRAME == opcode);
6578 int ast_id = iterator.Next();
6579 int function_id = iterator.Next();
6580 JSFunction* function =
6581 JSFunction::cast(LiteralArray()->get(function_id));
6582 unsigned height = iterator.Next();
6583 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006584 PrintF(out, "%24s %s {ast_id=%d, function=",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006585 "", Translation::StringFor(opcode), ast_id);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006586 function->PrintName(out);
6587 PrintF(out, ", height=%u}\n", height);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006588 }
6589
6590 // Size of translation is height plus all incoming arguments including
6591 // receiver.
6592 int size = height + function->shared()->formal_parameter_count() + 1;
6593 command_count += size;
6594 for (int j = 0; j < size; ++j) {
6595 opcode = static_cast<Translation::Opcode>(iterator.Next());
6596 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006597 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006598 }
6599
6600 if (opcode == Translation::DUPLICATE) {
6601 opcode = static_cast<Translation::Opcode>(iterator.Next());
6602 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006603 PrintF(out, "%s ", Translation::StringFor(opcode));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006604 }
6605 --j; // Two commands share the same frame index.
6606 }
6607
6608 switch (opcode) {
6609 case Translation::BEGIN:
6610 case Translation::FRAME:
6611 case Translation::DUPLICATE:
6612 UNREACHABLE();
6613 break;
6614
6615 case Translation::REGISTER: {
6616 int reg_code = iterator.Next();
6617 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006618 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006619 }
6620 break;
6621 }
6622
6623 case Translation::INT32_REGISTER: {
6624 int reg_code = iterator.Next();
6625 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006626 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006627 }
6628 break;
6629 }
6630
6631 case Translation::DOUBLE_REGISTER: {
6632 int reg_code = iterator.Next();
6633 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006634 PrintF(out, "{input=%s}",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006635 DoubleRegister::AllocationIndexToString(reg_code));
6636 }
6637 break;
6638 }
6639
6640 case Translation::STACK_SLOT: {
6641 int input_slot_index = iterator.Next();
6642 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006643 PrintF(out, "{input=%d}", input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006644 }
6645 break;
6646 }
6647
6648 case Translation::INT32_STACK_SLOT: {
6649 int input_slot_index = iterator.Next();
6650 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006651 PrintF(out, "{input=%d}", input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006652 }
6653 break;
6654 }
6655
6656 case Translation::DOUBLE_STACK_SLOT: {
6657 int input_slot_index = iterator.Next();
6658 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006659 PrintF(out, "{input=%d}", input_slot_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006660 }
6661 break;
6662 }
6663
6664 case Translation::LITERAL: {
6665 unsigned literal_index = iterator.Next();
6666 if (FLAG_print_code_verbose) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006667 PrintF(out, "{literal_id=%u}", literal_index);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006668 }
6669 break;
6670 }
6671
6672 case Translation::ARGUMENTS_OBJECT:
6673 break;
6674 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006675 if (FLAG_print_code_verbose) PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006676 }
6677 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006678 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006679 }
6680}
6681
6682
whesse@chromium.org023421e2010-12-21 12:19:12 +00006683void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
6684 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006685 this->DeoptPoints());
6686 if (this->DeoptPoints() == 0) return;
6687
6688 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
6689 for (int i = 0; i < this->DeoptPoints(); i++) {
6690 int pc_and_state = this->PcAndState(i)->value();
6691 PrintF("%6d %8d %s\n",
6692 this->AstId(i)->value(),
6693 FullCodeGenerator::PcField::decode(pc_and_state),
6694 FullCodeGenerator::State2String(
6695 FullCodeGenerator::StateField::decode(pc_and_state)));
6696 }
6697}
6698
6699#endif
6700
6701
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006702// Identify kind of code.
6703const char* Code::Kind2String(Kind kind) {
6704 switch (kind) {
6705 case FUNCTION: return "FUNCTION";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006706 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006707 case STUB: return "STUB";
6708 case BUILTIN: return "BUILTIN";
6709 case LOAD_IC: return "LOAD_IC";
6710 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
6711 case STORE_IC: return "STORE_IC";
6712 case KEYED_STORE_IC: return "KEYED_STORE_IC";
6713 case CALL_IC: return "CALL_IC";
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00006714 case KEYED_CALL_IC: return "KEYED_CALL_IC";
danno@chromium.org40cb8782011-05-25 07:58:50 +00006715 case UNARY_OP_IC: return "UNARY_OP_IC";
6716 case BINARY_OP_IC: return "BINARY_OP_IC";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006717 case COMPARE_IC: return "COMPARE_IC";
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006718 }
6719 UNREACHABLE();
6720 return NULL;
6721}
mads.s.ager31e71382008-08-13 09:32:07 +00006722
6723
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00006724const char* Code::ICState2String(InlineCacheState state) {
6725 switch (state) {
6726 case UNINITIALIZED: return "UNINITIALIZED";
6727 case PREMONOMORPHIC: return "PREMONOMORPHIC";
6728 case MONOMORPHIC: return "MONOMORPHIC";
6729 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
6730 case MEGAMORPHIC: return "MEGAMORPHIC";
6731 case DEBUG_BREAK: return "DEBUG_BREAK";
6732 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
6733 }
6734 UNREACHABLE();
6735 return NULL;
6736}
6737
6738
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006739const char* Code::PropertyType2String(PropertyType type) {
6740 switch (type) {
6741 case NORMAL: return "NORMAL";
6742 case FIELD: return "FIELD";
6743 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
6744 case CALLBACKS: return "CALLBACKS";
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00006745 case HANDLER: return "HANDLER";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006746 case INTERCEPTOR: return "INTERCEPTOR";
6747 case MAP_TRANSITION: return "MAP_TRANSITION";
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00006748 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006749 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
6750 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
6751 }
6752 UNREACHABLE();
6753 return NULL;
6754}
6755
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006756
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00006757void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
6758 const char* name = NULL;
6759 switch (kind) {
6760 case CALL_IC:
6761 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
6762 name = "STRING_INDEX_OUT_OF_BOUNDS";
6763 }
6764 break;
6765 case STORE_IC:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00006766 case KEYED_STORE_IC:
6767 if (extra == kStrictMode) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00006768 name = "STRICT";
6769 }
6770 break;
6771 default:
6772 break;
6773 }
6774 if (name != NULL) {
6775 PrintF(out, "extra_ic_state = %s\n", name);
6776 } else {
6777 PrintF(out, "etra_ic_state = %d\n", extra);
6778 }
6779}
6780
6781
whesse@chromium.org023421e2010-12-21 12:19:12 +00006782void Code::Disassemble(const char* name, FILE* out) {
6783 PrintF(out, "kind = %s\n", Kind2String(kind()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006784 if (is_inline_cache_stub()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006785 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00006786 PrintExtraICState(out, kind(), extra_ic_state());
whesse@chromium.org023421e2010-12-21 12:19:12 +00006787 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006788 if (ic_state() == MONOMORPHIC) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006789 PrintF(out, "type = %s\n", PropertyType2String(type()));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00006790 }
6791 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006792 if ((name != NULL) && (name[0] != '\0')) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006793 PrintF(out, "name = %s\n", name);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006794 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006795 if (kind() == OPTIMIZED_FUNCTION) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006796 PrintF(out, "stack_slots = %d\n", stack_slots());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006797 }
mads.s.ager31e71382008-08-13 09:32:07 +00006798
whesse@chromium.org023421e2010-12-21 12:19:12 +00006799 PrintF(out, "Instructions (size = %d)\n", instruction_size());
6800 Disassembler::Decode(out, this);
6801 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00006802
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006803#ifdef DEBUG
6804 if (kind() == FUNCTION) {
6805 DeoptimizationOutputData* data =
6806 DeoptimizationOutputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00006807 data->DeoptimizationOutputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006808 } else if (kind() == OPTIMIZED_FUNCTION) {
6809 DeoptimizationInputData* data =
6810 DeoptimizationInputData::cast(this->deoptimization_data());
whesse@chromium.org023421e2010-12-21 12:19:12 +00006811 data->DeoptimizationInputDataPrint(out);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006812 }
6813 PrintF("\n");
6814#endif
6815
6816 if (kind() == OPTIMIZED_FUNCTION) {
6817 SafepointTable table(this);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006818 PrintF(out, "Safepoints (size = %u)\n", table.size());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006819 for (unsigned i = 0; i < table.length(); i++) {
6820 unsigned pc_offset = table.GetPcOffset(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006821 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006822 table.PrintEntry(i);
whesse@chromium.org023421e2010-12-21 12:19:12 +00006823 PrintF(out, " (sp -> fp)");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006824 SafepointEntry entry = table.GetEntry(i);
6825 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
6826 PrintF(out, " %6d", entry.deoptimization_index());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006827 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00006828 PrintF(out, " <none>");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006829 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00006830 if (entry.argument_count() > 0) {
6831 PrintF(out, " argc: %d", entry.argument_count());
6832 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006833 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006834 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006835 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006836 } else if (kind() == FUNCTION) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00006837 unsigned offset = stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006838 // If there is no stack check table, the "table start" will at or after
6839 // (due to alignment) the end of the instruction stream.
6840 if (static_cast<int>(offset) < instruction_size()) {
6841 unsigned* address =
6842 reinterpret_cast<unsigned*>(instruction_start() + offset);
6843 unsigned length = address[0];
whesse@chromium.org023421e2010-12-21 12:19:12 +00006844 PrintF(out, "Stack checks (size = %u)\n", length);
6845 PrintF(out, "ast_id pc_offset\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006846 for (unsigned i = 0; i < length; ++i) {
6847 unsigned index = (2 * i) + 1;
whesse@chromium.org023421e2010-12-21 12:19:12 +00006848 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006849 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00006850 PrintF(out, "\n");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006851 }
6852 }
6853
mads.s.ager31e71382008-08-13 09:32:07 +00006854 PrintF("RelocInfo (size = %d)\n", relocation_size());
whesse@chromium.org023421e2010-12-21 12:19:12 +00006855 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
6856 PrintF(out, "\n");
mads.s.ager31e71382008-08-13 09:32:07 +00006857}
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00006858#endif // ENABLE_DISASSEMBLER
6859
6860
lrn@chromium.org303ada72010-10-27 09:33:13 +00006861MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
6862 int length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006863 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00006864 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006865 ASSERT(!HasExternalArrayElements());
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006866
lrn@chromium.org303ada72010-10-27 09:33:13 +00006867 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006868 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006869 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6870 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006871 FixedArray* elems = FixedArray::cast(obj);
6872
lrn@chromium.org303ada72010-10-27 09:33:13 +00006873 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
6874 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6875 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006876 Map* new_map = Map::cast(obj);
6877
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006878 AssertNoAllocation no_gc;
6879 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006880 switch (GetElementsKind()) {
6881 case FAST_ELEMENTS: {
6882 FixedArray* old_elements = FixedArray::cast(elements());
6883 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
6884 // Fill out the new array with this content and array holes.
6885 for (uint32_t i = 0; i < old_length; i++) {
6886 elems->set(i, old_elements->get(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006887 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006888 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006889 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006890 case DICTIONARY_ELEMENTS: {
6891 NumberDictionary* dictionary = NumberDictionary::cast(elements());
6892 for (int i = 0; i < dictionary->Capacity(); i++) {
6893 Object* key = dictionary->KeyAt(i);
6894 if (key->IsNumber()) {
6895 uint32_t entry = static_cast<uint32_t>(key->Number());
6896 elems->set(entry, dictionary->ValueAt(i), mode);
6897 }
6898 }
6899 break;
6900 }
6901 default:
6902 UNREACHABLE();
6903 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006905
6906 set_map(new_map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006907 set_elements(elems);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00006908
6909 if (IsJSArray()) {
6910 JSArray::cast(this)->set_length(Smi::FromInt(length));
6911 }
6912
6913 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914}
6915
6916
lrn@chromium.org303ada72010-10-27 09:33:13 +00006917MaybeObject* JSObject::SetSlowElements(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006918 // We should never end in here with a pixel or external array.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00006919 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006920
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006921 uint32_t new_length = static_cast<uint32_t>(len->Number());
6922
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006923 switch (GetElementsKind()) {
6924 case FAST_ELEMENTS: {
6925 // Make sure we never try to shrink dense arrays into sparse arrays.
6926 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
6927 new_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006928 Object* obj;
6929 { MaybeObject* maybe_obj = NormalizeElements();
6930 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6931 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006932
6933 // Update length for JSArrays.
6934 if (IsJSArray()) JSArray::cast(this)->set_length(len);
6935 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006936 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006937 case DICTIONARY_ELEMENTS: {
6938 if (IsJSArray()) {
6939 uint32_t old_length =
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006940 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006941 element_dictionary()->RemoveNumberEntries(new_length, old_length),
6942 JSArray::cast(this)->set_length(len);
6943 }
6944 break;
6945 }
6946 default:
6947 UNREACHABLE();
6948 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950 return this;
6951}
6952
6953
lrn@chromium.org303ada72010-10-27 09:33:13 +00006954MaybeObject* JSArray::Initialize(int capacity) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006955 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006956 ASSERT(capacity >= 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006957 set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006958 FixedArray* new_elements;
6959 if (capacity == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006960 new_elements = heap->empty_fixed_array();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006961 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006962 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006963 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006964 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006966 new_elements = FixedArray::cast(obj);
6967 }
6968 set_elements(new_elements);
6969 return this;
6970}
6971
6972
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006973void JSArray::Expand(int required_size) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006974 Handle<JSArray> self(this);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006975 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006976 int old_size = old_backing->length();
ager@chromium.org6141cbe2009-11-20 12:14:52 +00006977 int new_size = required_size > old_size ? required_size : old_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006978 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00006979 // Can't use this any more now because we may have had a GC!
6980 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
6981 self->SetContent(*new_backing);
6982}
6983
6984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006985static Failure* ArrayLengthRangeError(Heap* heap) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006987 return heap->isolate()->Throw(
6988 *FACTORY->NewRangeError("invalid_array_length",
6989 HandleVector<Object>(NULL, 0)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006990}
6991
6992
lrn@chromium.org303ada72010-10-27 09:33:13 +00006993MaybeObject* JSObject::SetElementsLength(Object* len) {
ager@chromium.org3811b432009-10-28 14:53:37 +00006994 // We should never end in here with a pixel or external array.
ager@chromium.org5c838252010-02-19 08:53:10 +00006995 ASSERT(AllowsSetElementsLength());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00006996
lrn@chromium.org303ada72010-10-27 09:33:13 +00006997 MaybeObject* maybe_smi_length = len->ToSmi();
6998 Object* smi_length = Smi::FromInt(0);
6999 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00007000 const int value = Smi::cast(smi_length)->value();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007001 if (value < 0) return ArrayLengthRangeError(GetHeap());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007002 switch (GetElementsKind()) {
7003 case FAST_ELEMENTS: {
7004 int old_capacity = FixedArray::cast(elements())->length();
7005 if (value <= old_capacity) {
7006 if (IsJSArray()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007007 Object* obj;
7008 { MaybeObject* maybe_obj = EnsureWritableFastElements();
7009 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7010 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007011 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
7012 // NOTE: We may be able to optimize this by removing the
7013 // last part of the elements backing storage array and
7014 // setting the capacity to the new size.
7015 for (int i = value; i < old_length; i++) {
7016 FixedArray::cast(elements())->set_the_hole(i);
7017 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007018 JSArray::cast(this)->set_length(Smi::cast(smi_length));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007019 }
7020 return this;
7021 }
7022 int min = NewElementsCapacity(old_capacity);
7023 int new_capacity = value > min ? value : min;
7024 if (new_capacity <= kMaxFastElementsLength ||
7025 !ShouldConvertToSlowElements(new_capacity)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007026 Object* obj;
7027 { MaybeObject* maybe_obj =
7028 SetFastElementsCapacityAndLength(new_capacity, value);
7029 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7030 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007031 return this;
7032 }
7033 break;
7034 }
7035 case DICTIONARY_ELEMENTS: {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 if (IsJSArray()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007037 if (value == 0) {
7038 // If the length of a slow array is reset to zero, we clear
7039 // the array and flush backing storage. This has the added
7040 // benefit that the array returns to fast mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007041 Object* obj;
7042 { MaybeObject* maybe_obj = ResetElements();
7043 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7044 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007045 } else {
7046 // Remove deleted elements.
7047 uint32_t old_length =
7048 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7049 element_dictionary()->RemoveNumberEntries(value, old_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007050 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007051 JSArray::cast(this)->set_length(Smi::cast(smi_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052 }
7053 return this;
7054 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007055 default:
7056 UNREACHABLE();
7057 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007058 }
7059 }
7060
7061 // General slow case.
7062 if (len->IsNumber()) {
7063 uint32_t length;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007064 if (len->ToArrayIndex(&length)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065 return SetSlowElements(len);
7066 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067 return ArrayLengthRangeError(GetHeap());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 }
7069 }
7070
7071 // len is not a number so make the array size one and
7072 // set only element to len.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007073 Object* obj;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007074 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007075 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7076 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007077 FixedArray::cast(obj)->set(0, len);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007078 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007079 set_elements(FixedArray::cast(obj));
7080 return this;
7081}
7082
7083
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007084Object* Map::GetPrototypeTransition(Object* prototype) {
7085 FixedArray* cache = prototype_transitions();
7086 int capacity = cache->length();
7087 if (capacity == 0) return NULL;
7088 int finger = Smi::cast(cache->get(0))->value();
7089 for (int i = 1; i < finger; i += 2) {
7090 if (cache->get(i) == prototype) return cache->get(i + 1);
7091 }
7092 return NULL;
7093}
7094
7095
7096MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
7097 // Don't cache prototype transition if this map is shared.
7098 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7099
7100 FixedArray* cache = prototype_transitions();
7101
7102 int capacity = cache->length();
7103
7104 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value();
7105
7106 if (finger >= capacity) {
7107 if (capacity > kMaxCachedPrototypeTransitions) return this;
7108
7109 FixedArray* new_cache;
7110 { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1);
7111 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7112 }
7113
7114 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i));
7115 cache = new_cache;
7116 set_prototype_transitions(cache);
7117 }
7118
7119 cache->set(finger, prototype);
7120 cache->set(finger + 1, map);
7121 cache->set(0, Smi::FromInt(finger + 2));
7122
7123 return cache;
7124}
7125
7126
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007127MaybeObject* JSReceiver::SetPrototype(Object* value,
7128 bool skip_hidden_prototypes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007129 Heap* heap = GetHeap();
ager@chromium.org5c838252010-02-19 08:53:10 +00007130 // Silently ignore the change if value is not a JSObject or null.
7131 // SpiderMonkey behaves this way.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007132 if (!value->IsJSReceiver() && !value->IsNull()) return value;
ager@chromium.org5c838252010-02-19 08:53:10 +00007133
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007134 // From 8.6.2 Object Internal Methods
7135 // ...
7136 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7137 // [[Prototype]] internal properties of the object may not be modified.
7138 // ...
7139 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7140 // or [[Extensible]] must not violate the invariants defined in the preceding
7141 // paragraph.
7142 if (!this->map()->is_extensible()) {
7143 HandleScope scope;
7144 Handle<Object> handle(this, heap->isolate());
7145 return heap->isolate()->Throw(
7146 *FACTORY->NewTypeError("non_extensible_proto",
7147 HandleVector<Object>(&handle, 1)));
7148 }
7149
ager@chromium.org5c838252010-02-19 08:53:10 +00007150 // Before we can set the prototype we need to be sure
7151 // prototype cycles are prevented.
7152 // It is sufficient to validate that the receiver is not in the new prototype
7153 // chain.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007154 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00007155 if (JSObject::cast(pt) == this) {
7156 // Cycle detected.
7157 HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007158 return heap->isolate()->Throw(
7159 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
ager@chromium.org5c838252010-02-19 08:53:10 +00007160 }
7161 }
7162
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007163 JSReceiver* real_receiver = this;
ager@chromium.org5c838252010-02-19 08:53:10 +00007164
7165 if (skip_hidden_prototypes) {
7166 // Find the first object in the chain whose prototype object is not
7167 // hidden and set the new prototype on that object.
7168 Object* current_proto = real_receiver->GetPrototype();
7169 while (current_proto->IsJSObject() &&
7170 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7171 real_receiver = JSObject::cast(current_proto);
7172 current_proto = current_proto->GetPrototype();
7173 }
7174 }
7175
7176 // Set the new prototype of the object.
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007177 Map* map = real_receiver->map();
7178
7179 // Nothing to do if prototype is already set.
7180 if (map->prototype() == value) return value;
7181
7182 Object* new_map = map->GetPrototypeTransition(value);
7183 if (new_map == NULL) {
7184 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7185 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7186 }
7187
7188 { MaybeObject* maybe_new_cache =
7189 map->PutPrototypeTransition(value, Map::cast(new_map));
7190 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7191 }
7192
7193 Map::cast(new_map)->set_prototype(value);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007194 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007195 ASSERT(Map::cast(new_map)->prototype() == value);
ager@chromium.org5c838252010-02-19 08:53:10 +00007196 real_receiver->set_map(Map::cast(new_map));
7197
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007198 heap->ClearInstanceofCache();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00007199
ager@chromium.org5c838252010-02-19 08:53:10 +00007200 return value;
7201}
7202
7203
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007204bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007205 switch (GetElementsKind()) {
7206 case FAST_ELEMENTS: {
7207 uint32_t length = IsJSArray() ?
7208 static_cast<uint32_t>
7209 (Smi::cast(JSArray::cast(this)->length())->value()) :
7210 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7211 if ((index < length) &&
7212 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7213 return true;
7214 }
7215 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007216 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007217 case EXTERNAL_PIXEL_ELEMENTS: {
7218 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007219 if (index < static_cast<uint32_t>(pixels->length())) {
7220 return true;
7221 }
7222 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007223 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007224 case EXTERNAL_BYTE_ELEMENTS:
7225 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7226 case EXTERNAL_SHORT_ELEMENTS:
7227 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7228 case EXTERNAL_INT_ELEMENTS:
7229 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007230 case EXTERNAL_FLOAT_ELEMENTS:
7231 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007232 ExternalArray* array = ExternalArray::cast(elements());
7233 if (index < static_cast<uint32_t>(array->length())) {
7234 return true;
7235 }
7236 break;
7237 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007238 case DICTIONARY_ELEMENTS: {
7239 if (element_dictionary()->FindEntry(index)
7240 != NumberDictionary::kNotFound) {
7241 return true;
7242 }
7243 break;
7244 }
7245 default:
7246 UNREACHABLE();
7247 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007248 }
7249
7250 // Handle [] on String objects.
7251 if (this->IsStringObjectWithCharacterAt(index)) return true;
7252
7253 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007254 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007255 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7256}
7257
7258
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007259bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007260 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 // Make sure that the top context does not change when doing
7262 // callbacks or interceptor calls.
7263 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007264 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007266 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267 Handle<JSObject> holder_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007268 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007269 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270 if (!interceptor->query()->IsUndefined()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007271 v8::IndexedPropertyQuery query =
7272 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007273 LOG(isolate,
7274 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007275 v8::Handle<v8::Integer> result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007276 {
7277 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007278 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007279 result = query(index, info);
7280 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007281 if (!result.IsEmpty()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00007282 ASSERT(result->IsInt32());
7283 return true; // absence of property is signaled by empty handle.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007284 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007285 } else if (!interceptor->getter()->IsUndefined()) {
7286 v8::IndexedPropertyGetter getter =
7287 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007288 LOG(isolate,
7289 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290 v8::Handle<v8::Value> result;
7291 {
7292 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007293 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 result = getter(index, info);
7295 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007296 if (!result.IsEmpty()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297 }
7298 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7299}
7300
7301
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007302JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007303 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007304 if (IsAccessCheckNeeded()) {
7305 Heap* heap = GetHeap();
7306 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7307 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7308 return UNDEFINED_ELEMENT;
7309 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007310 }
7311
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007312 if (IsJSGlobalProxy()) {
7313 Object* proto = GetPrototype();
7314 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7315 ASSERT(proto->IsJSGlobalObject());
7316 return JSObject::cast(proto)->HasLocalElement(index);
7317 }
7318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319 // Check for lookup interceptor
7320 if (HasIndexedInterceptor()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007321 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7322 : UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007323 }
7324
7325 // Handle [] on String objects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007326 if (this->IsStringObjectWithCharacterAt(index)) {
7327 return STRING_CHARACTER_ELEMENT;
7328 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007329
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007330 switch (GetElementsKind()) {
7331 case FAST_ELEMENTS: {
7332 uint32_t length = IsJSArray() ?
7333 static_cast<uint32_t>
7334 (Smi::cast(JSArray::cast(this)->length())->value()) :
7335 static_cast<uint32_t>(FixedArray::cast(elements())->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007336 if ((index < length) &&
7337 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7338 return FAST_ELEMENT;
7339 }
7340 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007341 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007342 case EXTERNAL_PIXEL_ELEMENTS: {
7343 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007344 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7345 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007346 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007347 case EXTERNAL_BYTE_ELEMENTS:
7348 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7349 case EXTERNAL_SHORT_ELEMENTS:
7350 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7351 case EXTERNAL_INT_ELEMENTS:
7352 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007353 case EXTERNAL_FLOAT_ELEMENTS:
7354 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007355 ExternalArray* array = ExternalArray::cast(elements());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007356 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7357 break;
ager@chromium.org3811b432009-10-28 14:53:37 +00007358 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007359 case DICTIONARY_ELEMENTS: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007360 if (element_dictionary()->FindEntry(index) !=
7361 NumberDictionary::kNotFound) {
7362 return DICTIONARY_ELEMENT;
7363 }
7364 break;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007365 }
7366 default:
7367 UNREACHABLE();
7368 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007369 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007370
7371 return UNDEFINED_ELEMENT;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007372}
7373
7374
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00007375bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007376 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007377 if (IsAccessCheckNeeded()) {
7378 Heap* heap = GetHeap();
7379 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7380 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7381 return false;
7382 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007383 }
7384
7385 // Check for lookup interceptor
7386 if (HasIndexedInterceptor()) {
7387 return HasElementWithInterceptor(receiver, index);
7388 }
7389
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007390 switch (GetElementsKind()) {
7391 case FAST_ELEMENTS: {
7392 uint32_t length = IsJSArray() ?
7393 static_cast<uint32_t>
7394 (Smi::cast(JSArray::cast(this)->length())->value()) :
7395 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7396 if ((index < length) &&
7397 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
7398 break;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00007399 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007400 case EXTERNAL_PIXEL_ELEMENTS: {
7401 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007402 if (index < static_cast<uint32_t>(pixels->length())) {
7403 return true;
7404 }
7405 break;
7406 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007407 case EXTERNAL_BYTE_ELEMENTS:
7408 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7409 case EXTERNAL_SHORT_ELEMENTS:
7410 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7411 case EXTERNAL_INT_ELEMENTS:
7412 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007413 case EXTERNAL_FLOAT_ELEMENTS:
7414 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00007415 ExternalArray* array = ExternalArray::cast(elements());
7416 if (index < static_cast<uint32_t>(array->length())) {
7417 return true;
7418 }
7419 break;
7420 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007421 case DICTIONARY_ELEMENTS: {
7422 if (element_dictionary()->FindEntry(index)
7423 != NumberDictionary::kNotFound) {
7424 return true;
7425 }
7426 break;
7427 }
7428 default:
7429 UNREACHABLE();
7430 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007431 }
7432
7433 // Handle [] on String objects.
7434 if (this->IsStringObjectWithCharacterAt(index)) return true;
7435
7436 Object* pt = GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007437 if (pt->IsNull()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007438 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7439}
7440
7441
lrn@chromium.org303ada72010-10-27 09:33:13 +00007442MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007443 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007444 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007445 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447 // Make sure that the top context does not change when doing
7448 // callbacks or interceptor calls.
7449 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007450 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007451 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7452 Handle<JSObject> this_handle(this);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007453 Handle<Object> value_handle(value, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 if (!interceptor->setter()->IsUndefined()) {
7455 v8::IndexedPropertySetter setter =
7456 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007457 LOG(isolate,
7458 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
7459 CustomArguments args(isolate, interceptor->data(), this, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007460 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007461 v8::Handle<v8::Value> result;
7462 {
7463 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007464 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007465 result = setter(index, v8::Utils::ToLocal(value_handle), info);
7466 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007467 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007468 if (!result.IsEmpty()) return *value_handle;
7469 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007470 MaybeObject* raw_result =
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007471 this_handle->SetElementWithoutInterceptor(index,
7472 *value_handle,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007473 strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007474 check_prototype);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007475 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007476 return raw_result;
7477}
7478
7479
lrn@chromium.org303ada72010-10-27 09:33:13 +00007480MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
7481 Object* structure,
7482 uint32_t index,
7483 Object* holder) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007484 Isolate* isolate = GetIsolate();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007485 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007486
7487 // api style callbacks.
7488 if (structure->IsAccessorInfo()) {
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007489 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007490 Object* fun_obj = data->getter();
7491 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007493 Handle<JSObject> self(JSObject::cast(receiver));
7494 Handle<JSObject> holder_handle(JSObject::cast(holder));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007495 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7496 Handle<String> key(isolate->factory()->NumberToString(number));
7497 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
7498 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007499 v8::AccessorInfo info(args.end());
7500 v8::Handle<v8::Value> result;
7501 {
7502 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007503 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007504 result = call_fun(v8::Utils::ToLocal(key), info);
7505 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007506 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
7507 if (result.IsEmpty()) return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007508 return *v8::Utils::OpenHandle(*result);
7509 }
7510
7511 // __defineGetter__ callback
7512 if (structure->IsFixedArray()) {
7513 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
7514 if (getter->IsJSFunction()) {
7515 return Object::GetPropertyWithDefinedGetter(receiver,
7516 JSFunction::cast(getter));
7517 }
7518 // Getter is not a function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007519 return isolate->heap()->undefined_value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007520 }
7521
7522 UNREACHABLE();
7523 return NULL;
7524}
7525
7526
lrn@chromium.org303ada72010-10-27 09:33:13 +00007527MaybeObject* JSObject::SetElementWithCallback(Object* structure,
7528 uint32_t index,
7529 Object* value,
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007530 JSObject* holder,
7531 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007532 Isolate* isolate = GetIsolate();
7533 HandleScope scope(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007534
7535 // We should never get here to initialize a const with the hole
7536 // value since a const declaration would conflict with the setter.
7537 ASSERT(!value->IsTheHole());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007538 Handle<Object> value_handle(value, isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007539
7540 // To accommodate both the old and the new api we switch on the
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007541 // data structure used to store the callbacks. Eventually foreign
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007542 // callbacks should be phased out.
ager@chromium.orgea91cc52011-05-23 06:06:11 +00007543 ASSERT(!structure->IsForeign());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007544
7545 if (structure->IsAccessorInfo()) {
7546 // api style callbacks
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007547 Handle<JSObject> self(this);
7548 Handle<JSObject> holder_handle(JSObject::cast(holder));
7549 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007550 Object* call_obj = data->setter();
7551 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
7552 if (call_fun == NULL) return value;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007553 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7554 Handle<String> key(isolate->factory()->NumberToString(number));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007555 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
7556 CustomArguments args(isolate, data->data(), *self, *holder_handle);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007557 v8::AccessorInfo info(args.end());
7558 {
7559 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007560 VMState state(isolate, EXTERNAL);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007561 call_fun(v8::Utils::ToLocal(key),
7562 v8::Utils::ToLocal(value_handle),
7563 info);
7564 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007565 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007566 return *value_handle;
7567 }
7568
7569 if (structure->IsFixedArray()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007570 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007571 if (setter->IsJSFunction()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007572 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007573 } else {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007574 if (strict_mode == kNonStrictMode) {
7575 return value;
7576 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007577 Handle<Object> holder_handle(holder, isolate);
7578 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007579 Handle<Object> args[2] = { key, holder_handle };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007580 return isolate->Throw(
7581 *isolate->factory()->NewTypeError("no_setter_in_callback",
7582 HandleVector(args, 2)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007583 }
7584 }
7585
7586 UNREACHABLE();
7587 return NULL;
7588}
7589
7590
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007591// Adding n elements in fast case is O(n*n).
7592// Note: revisit design to have dual undefined values to capture absent
7593// elements.
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007594MaybeObject* JSObject::SetFastElement(uint32_t index,
7595 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007596 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007597 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007598 ASSERT(HasFastElements());
7599
lrn@chromium.org303ada72010-10-27 09:33:13 +00007600 Object* elms_obj;
7601 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements();
7602 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
7603 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007604 FixedArray* elms = FixedArray::cast(elms_obj);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007605 uint32_t elms_length = static_cast<uint32_t>(elms->length());
7606
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007607 if (check_prototype &&
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007608 (index >= elms_length || elms->get(index)->IsTheHole())) {
7609 bool found;
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007610 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
7611 value,
7612 &found,
7613 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007614 if (found) return result;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007615 }
7616
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007618 // Check whether there is extra space in fixed array..
7619 if (index < elms_length) {
7620 elms->set(index, value);
7621 if (IsJSArray()) {
7622 // Update the length of the array if needed.
7623 uint32_t array_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007624 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007625 if (index >= array_length) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007626 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007627 }
7628 }
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00007629 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007630 }
7631
7632 // Allow gap in fast case.
7633 if ((index - elms_length) < kMaxGap) {
7634 // Try allocating extra space.
7635 int new_capacity = NewElementsCapacity(index+1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007636 if (new_capacity <= kMaxFastElementsLength ||
7637 !ShouldConvertToSlowElements(new_capacity)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007638 ASSERT(static_cast<uint32_t>(new_capacity) > index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007639 Object* obj;
7640 { MaybeObject* maybe_obj =
7641 SetFastElementsCapacityAndLength(new_capacity, index + 1);
7642 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007644 FixedArray::cast(elements())->set(index, value);
ager@chromium.orgbdf2f942008-10-17 07:23:00 +00007645 return value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007646 }
7647 }
7648
7649 // Otherwise default to slow case.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007650 Object* obj;
7651 { MaybeObject* maybe_obj = NormalizeElements();
7652 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7653 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007654 ASSERT(HasDictionaryElements());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007655 return SetElement(index, value, strict_mode, check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007656}
7657
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007658
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007659MaybeObject* JSObject::SetElement(uint32_t index,
7660 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007661 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007662 bool check_prototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007663 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007664 if (IsAccessCheckNeeded()) {
7665 Heap* heap = GetHeap();
7666 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
7667 HandleScope scope;
7668 Handle<Object> value_handle(value);
7669 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
7670 return *value_handle;
7671 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007672 }
7673
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007674 if (IsJSGlobalProxy()) {
7675 Object* proto = GetPrototype();
7676 if (proto->IsNull()) return value;
7677 ASSERT(proto->IsJSGlobalObject());
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007678 return JSObject::cast(proto)->SetElement(index,
7679 value,
7680 strict_mode,
7681 check_prototype);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007682 }
7683
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007684 // Check for lookup interceptor
7685 if (HasIndexedInterceptor()) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007686 return SetElementWithInterceptor(index,
7687 value,
7688 strict_mode,
7689 check_prototype);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007690 }
7691
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007692 return SetElementWithoutInterceptor(index,
7693 value,
7694 strict_mode,
7695 check_prototype);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007696}
7697
7698
lrn@chromium.org303ada72010-10-27 09:33:13 +00007699MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007700 Object* value,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007701 StrictModeFlag strict_mode,
lrn@chromium.org5d00b602011-01-05 09:51:43 +00007702 bool check_prototype) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007703 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007704 switch (GetElementsKind()) {
7705 case FAST_ELEMENTS:
7706 // Fast case.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007707 return SetFastElement(index, value, strict_mode, check_prototype);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007708 case EXTERNAL_PIXEL_ELEMENTS: {
7709 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007710 return pixels->SetValue(index, value);
7711 }
ager@chromium.org3811b432009-10-28 14:53:37 +00007712 case EXTERNAL_BYTE_ELEMENTS: {
7713 ExternalByteArray* array = ExternalByteArray::cast(elements());
7714 return array->SetValue(index, value);
7715 }
7716 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7717 ExternalUnsignedByteArray* array =
7718 ExternalUnsignedByteArray::cast(elements());
7719 return array->SetValue(index, value);
7720 }
7721 case EXTERNAL_SHORT_ELEMENTS: {
7722 ExternalShortArray* array = ExternalShortArray::cast(elements());
7723 return array->SetValue(index, value);
7724 }
7725 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7726 ExternalUnsignedShortArray* array =
7727 ExternalUnsignedShortArray::cast(elements());
7728 return array->SetValue(index, value);
7729 }
7730 case EXTERNAL_INT_ELEMENTS: {
7731 ExternalIntArray* array = ExternalIntArray::cast(elements());
7732 return array->SetValue(index, value);
7733 }
7734 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7735 ExternalUnsignedIntArray* array =
7736 ExternalUnsignedIntArray::cast(elements());
7737 return array->SetValue(index, value);
7738 }
7739 case EXTERNAL_FLOAT_ELEMENTS: {
7740 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7741 return array->SetValue(index, value);
7742 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007743 case EXTERNAL_DOUBLE_ELEMENTS: {
7744 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
7745 return array->SetValue(index, value);
7746 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007747 case DICTIONARY_ELEMENTS: {
7748 // Insert element in the dictionary.
7749 FixedArray* elms = FixedArray::cast(elements());
7750 NumberDictionary* dictionary = NumberDictionary::cast(elms);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007751
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007752 int entry = dictionary->FindEntry(index);
7753 if (entry != NumberDictionary::kNotFound) {
7754 Object* element = dictionary->ValueAt(entry);
7755 PropertyDetails details = dictionary->DetailsAt(entry);
7756 if (details.type() == CALLBACKS) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007757 return SetElementWithCallback(element,
7758 index,
7759 value,
7760 this,
7761 strict_mode);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007762 } else {
7763 dictionary->UpdateMaxNumberKey(index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007764 // If put fails instrict mode, throw exception.
7765 if (!dictionary->ValueAtPut(entry, value) &&
7766 strict_mode == kStrictMode) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007767 Handle<Object> holder(this);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00007768 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007769 Handle<Object> args[2] = { number, holder };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007770 return isolate->Throw(
7771 *isolate->factory()->NewTypeError("strict_read_only_property",
7772 HandleVector(args, 2)));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007773 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007774 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007775 } else {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007776 // Index not already used. Look for an accessor in the prototype chain.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007777 if (check_prototype) {
7778 bool found;
7779 MaybeObject* result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00007780 // Strict mode not needed. No-setter case already handled.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00007781 SetElementWithCallbackSetterInPrototypes(index,
7782 value,
7783 &found,
7784 strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007785 if (found) return result;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007786 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00007787 // When we set the is_extensible flag to false we always force
7788 // the element into dictionary mode (and force them to stay there).
7789 if (!map()->is_extensible()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007790 if (strict_mode == kNonStrictMode) {
7791 return isolate->heap()->undefined_value();
7792 } else {
7793 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
7794 Handle<String> index_string(
7795 isolate->factory()->NumberToString(number));
7796 Handle<Object> args[1] = { index_string };
7797 return isolate->Throw(
7798 *isolate->factory()->NewTypeError("object_not_extensible",
7799 HandleVector(args, 1)));
7800 }
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00007801 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007802 Object* result;
7803 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
7804 if (!maybe_result->ToObject(&result)) return maybe_result;
7805 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007806 if (elms != FixedArray::cast(result)) {
7807 set_elements(FixedArray::cast(result));
7808 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007809 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007810
7811 // Update the array length if this JSObject is an array.
7812 if (IsJSArray()) {
7813 JSArray* array = JSArray::cast(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007814 Object* return_value;
7815 { MaybeObject* maybe_return_value =
7816 array->JSArrayUpdateLengthFromIndex(index, value);
7817 if (!maybe_return_value->ToObject(&return_value)) {
7818 return maybe_return_value;
7819 }
7820 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007821 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007822
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007823 // Attempt to put this object back in fast case.
7824 if (ShouldConvertToFastElements()) {
7825 uint32_t new_length = 0;
7826 if (IsJSArray()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007827 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007828 } else {
7829 new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
7830 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00007831 Object* obj;
7832 { MaybeObject* maybe_obj =
7833 SetFastElementsCapacityAndLength(new_length, new_length);
7834 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007836#ifdef DEBUG
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007837 if (FLAG_trace_normalization) {
7838 PrintF("Object elements are fast case again:\n");
7839 Print();
7840 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007841#endif
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007842 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007843
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007844 return value;
7845 }
7846 default:
7847 UNREACHABLE();
7848 break;
7849 }
7850 // All possible cases have been handled above. Add a return to avoid the
7851 // complaints from the compiler.
7852 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007853 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007854}
7855
7856
lrn@chromium.org303ada72010-10-27 09:33:13 +00007857MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
7858 Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007859 uint32_t old_len = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007860 CHECK(length()->ToArrayIndex(&old_len));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007861 // Check to see if we need to update the length. For now, we make
7862 // sure that the length stays within 32-bits (unsigned).
7863 if (index >= old_len && index != 0xffffffff) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007864 Object* len;
7865 { MaybeObject* maybe_len =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007866 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007867 if (!maybe_len->ToObject(&len)) return maybe_len;
7868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007869 set_length(len);
7870 }
7871 return value;
7872}
7873
7874
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007875MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007876 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007877 // Get element works for both JSObject and JSArray since
7878 // JSArray::length cannot change.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007879 switch (GetElementsKind()) {
7880 case FAST_ELEMENTS: {
7881 FixedArray* elms = FixedArray::cast(elements());
7882 if (index < static_cast<uint32_t>(elms->length())) {
7883 Object* value = elms->get(index);
7884 if (!value->IsTheHole()) return value;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00007885 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007886 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007888 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00007889 case EXTERNAL_BYTE_ELEMENTS:
7890 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7891 case EXTERNAL_SHORT_ELEMENTS:
7892 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7893 case EXTERNAL_INT_ELEMENTS:
7894 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007895 case EXTERNAL_FLOAT_ELEMENTS:
7896 case EXTERNAL_DOUBLE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007897 MaybeObject* maybe_value = GetExternalElement(index);
7898 Object* value;
7899 if (!maybe_value->ToObject(&value)) return maybe_value;
7900 if (!value->IsUndefined()) return value;
ager@chromium.org3811b432009-10-28 14:53:37 +00007901 break;
7902 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007903 case DICTIONARY_ELEMENTS: {
7904 NumberDictionary* dictionary = element_dictionary();
7905 int entry = dictionary->FindEntry(index);
7906 if (entry != NumberDictionary::kNotFound) {
7907 Object* element = dictionary->ValueAt(entry);
7908 PropertyDetails details = dictionary->DetailsAt(entry);
7909 if (details.type() == CALLBACKS) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00007910 return GetElementWithCallback(receiver,
7911 element,
7912 index,
7913 this);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007914 }
7915 return element;
7916 }
7917 break;
7918 }
7919 default:
7920 UNREACHABLE();
7921 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007922 }
7923
7924 // Continue searching via the prototype chain.
7925 Object* pt = GetPrototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007926 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007927 return pt->GetElementWithReceiver(receiver, index);
7928}
7929
7930
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007931MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007932 uint32_t index) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007933 Isolate* isolate = GetIsolate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007934 // Make sure that the top context does not change when doing
7935 // callbacks or interceptor calls.
7936 AssertNoContextChange ncc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007937 HandleScope scope(isolate);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00007938 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
7939 Handle<Object> this_handle(receiver, isolate);
7940 Handle<JSObject> holder_handle(this, isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007941 if (!interceptor->getter()->IsUndefined()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007942 v8::IndexedPropertyGetter getter =
7943 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007944 LOG(isolate,
7945 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
7946 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00007947 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007948 v8::Handle<v8::Value> result;
7949 {
7950 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007951 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007952 result = getter(index, info);
7953 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007954 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007955 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
7956 }
7957
lrn@chromium.org303ada72010-10-27 09:33:13 +00007958 MaybeObject* raw_result =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007959 holder_handle->GetElementPostInterceptor(*this_handle, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007960 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007961 return raw_result;
7962}
7963
7964
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007965MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00007966 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007967 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007968 if (IsAccessCheckNeeded()) {
7969 Heap* heap = GetHeap();
7970 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
7971 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
7972 return heap->undefined_value();
7973 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007974 }
7975
7976 if (HasIndexedInterceptor()) {
7977 return GetElementWithInterceptor(receiver, index);
7978 }
7979
7980 // Get element works for both JSObject and JSArray since
7981 // JSArray::length cannot change.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007982 switch (GetElementsKind()) {
7983 case FAST_ELEMENTS: {
7984 FixedArray* elms = FixedArray::cast(elements());
7985 if (index < static_cast<uint32_t>(elms->length())) {
7986 Object* value = elms->get(index);
7987 if (!value->IsTheHole()) return value;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007988 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00007989 break;
7990 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00007991 case EXTERNAL_PIXEL_ELEMENTS:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00007992 case EXTERNAL_BYTE_ELEMENTS:
7993 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7994 case EXTERNAL_SHORT_ELEMENTS:
7995 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7996 case EXTERNAL_INT_ELEMENTS:
7997 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007998 case EXTERNAL_FLOAT_ELEMENTS:
7999 case EXTERNAL_DOUBLE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008000 MaybeObject* maybe_value = GetExternalElement(index);
8001 Object* value;
8002 if (!maybe_value->ToObject(&value)) return maybe_value;
8003 if (!value->IsUndefined()) return value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008004 break;
8005 }
8006 case DICTIONARY_ELEMENTS: {
8007 NumberDictionary* dictionary = element_dictionary();
8008 int entry = dictionary->FindEntry(index);
8009 if (entry != NumberDictionary::kNotFound) {
8010 Object* element = dictionary->ValueAt(entry);
8011 PropertyDetails details = dictionary->DetailsAt(entry);
8012 if (details.type() == CALLBACKS) {
8013 return GetElementWithCallback(receiver,
8014 element,
8015 index,
8016 this);
8017 }
8018 return element;
8019 }
8020 break;
8021 }
8022 }
8023
8024 Object* pt = GetPrototype();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008025 Heap* heap = GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008026 if (pt == heap->null_value()) return heap->undefined_value();
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008027 return pt->GetElementWithReceiver(receiver, index);
8028}
8029
8030
8031MaybeObject* JSObject::GetExternalElement(uint32_t index) {
8032 // Get element works for both JSObject and JSArray since
8033 // JSArray::length cannot change.
8034 switch (GetElementsKind()) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008035 case EXTERNAL_PIXEL_ELEMENTS: {
8036 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008037 if (index < static_cast<uint32_t>(pixels->length())) {
8038 uint8_t value = pixels->get(index);
8039 return Smi::FromInt(value);
8040 }
8041 break;
8042 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008043 case EXTERNAL_BYTE_ELEMENTS: {
8044 ExternalByteArray* array = ExternalByteArray::cast(elements());
8045 if (index < static_cast<uint32_t>(array->length())) {
8046 int8_t value = array->get(index);
8047 return Smi::FromInt(value);
8048 }
8049 break;
8050 }
8051 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8052 ExternalUnsignedByteArray* array =
8053 ExternalUnsignedByteArray::cast(elements());
8054 if (index < static_cast<uint32_t>(array->length())) {
8055 uint8_t value = array->get(index);
8056 return Smi::FromInt(value);
8057 }
8058 break;
8059 }
8060 case EXTERNAL_SHORT_ELEMENTS: {
8061 ExternalShortArray* array = ExternalShortArray::cast(elements());
8062 if (index < static_cast<uint32_t>(array->length())) {
8063 int16_t value = array->get(index);
8064 return Smi::FromInt(value);
8065 }
8066 break;
8067 }
8068 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8069 ExternalUnsignedShortArray* array =
8070 ExternalUnsignedShortArray::cast(elements());
8071 if (index < static_cast<uint32_t>(array->length())) {
8072 uint16_t value = array->get(index);
8073 return Smi::FromInt(value);
8074 }
8075 break;
8076 }
8077 case EXTERNAL_INT_ELEMENTS: {
8078 ExternalIntArray* array = ExternalIntArray::cast(elements());
8079 if (index < static_cast<uint32_t>(array->length())) {
8080 int32_t value = array->get(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 return GetHeap()->NumberFromInt32(value);
ager@chromium.org3811b432009-10-28 14:53:37 +00008082 }
8083 break;
8084 }
8085 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8086 ExternalUnsignedIntArray* array =
8087 ExternalUnsignedIntArray::cast(elements());
8088 if (index < static_cast<uint32_t>(array->length())) {
8089 uint32_t value = array->get(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008090 return GetHeap()->NumberFromUint32(value);
ager@chromium.org3811b432009-10-28 14:53:37 +00008091 }
8092 break;
8093 }
8094 case EXTERNAL_FLOAT_ELEMENTS: {
8095 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8096 if (index < static_cast<uint32_t>(array->length())) {
8097 float value = array->get(index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008098 return GetHeap()->AllocateHeapNumber(value);
ager@chromium.org3811b432009-10-28 14:53:37 +00008099 }
8100 break;
8101 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008102 case EXTERNAL_DOUBLE_ELEMENTS: {
8103 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8104 if (index < static_cast<uint32_t>(array->length())) {
8105 double value = array->get(index);
8106 return GetHeap()->AllocateHeapNumber(value);
8107 }
8108 break;
8109 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00008110 case FAST_ELEMENTS:
8111 case DICTIONARY_ELEMENTS:
8112 UNREACHABLE();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008113 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008114 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008115 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008116}
8117
8118
8119bool JSObject::HasDenseElements() {
8120 int capacity = 0;
8121 int number_of_elements = 0;
8122
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008123 switch (GetElementsKind()) {
8124 case FAST_ELEMENTS: {
8125 FixedArray* elms = FixedArray::cast(elements());
8126 capacity = elms->length();
8127 for (int i = 0; i < capacity; i++) {
8128 if (!elms->get(i)->IsTheHole()) number_of_elements++;
8129 }
8130 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008131 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008132 case EXTERNAL_PIXEL_ELEMENTS:
ager@chromium.org3811b432009-10-28 14:53:37 +00008133 case EXTERNAL_BYTE_ELEMENTS:
8134 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8135 case EXTERNAL_SHORT_ELEMENTS:
8136 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8137 case EXTERNAL_INT_ELEMENTS:
8138 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008139 case EXTERNAL_FLOAT_ELEMENTS:
8140 case EXTERNAL_DOUBLE_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008141 return true;
8142 }
8143 case DICTIONARY_ELEMENTS: {
8144 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8145 capacity = dictionary->Capacity();
8146 number_of_elements = dictionary->NumberOfElements();
8147 break;
8148 }
8149 default:
8150 UNREACHABLE();
8151 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008152 }
8153
8154 if (capacity == 0) return true;
8155 return (number_of_elements > (capacity / 2));
8156}
8157
8158
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008159bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008160 ASSERT(HasFastElements());
8161 // Keep the array in fast case if the current backing storage is
8162 // almost filled and if the new capacity is no more than twice the
8163 // old capacity.
8164 int elements_length = FixedArray::cast(elements())->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008165 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008166}
8167
8168
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008169bool JSObject::ShouldConvertToFastElements() {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008170 ASSERT(HasDictionaryElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008171 NumberDictionary* dictionary = NumberDictionary::cast(elements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008172 // If the elements are sparse, we should not go back to fast case.
8173 if (!HasDenseElements()) return false;
8174 // If an element has been added at a very high index in the elements
8175 // dictionary, we cannot go back to fast case.
8176 if (dictionary->requires_slow_elements()) return false;
8177 // An object requiring access checks is never allowed to have fast
8178 // elements. If it had fast elements we would skip security checks.
8179 if (IsAccessCheckNeeded()) return false;
8180 // If the dictionary backing storage takes up roughly half as much
8181 // space as a fast-case backing storage would the array should have
8182 // fast elements.
8183 uint32_t length = 0;
8184 if (IsJSArray()) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008185 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008186 } else {
8187 length = dictionary->max_number_key();
8188 }
8189 return static_cast<uint32_t>(dictionary->Capacity()) >=
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008190 (length / (2 * NumberDictionary::kEntrySize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008191}
8192
8193
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008194// Certain compilers request function template instantiation when they
8195// see the definition of the other template functions in the
8196// class. This requires us to have the template functions put
8197// together, so even though this function belongs in objects-debug.cc,
8198// we keep it here instead to satisfy certain compilers.
whesse@chromium.org023421e2010-12-21 12:19:12 +00008199#ifdef OBJECT_PRINT
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008200template<typename Shape, typename Key>
whesse@chromium.org023421e2010-12-21 12:19:12 +00008201void Dictionary<Shape, Key>::Print(FILE* out) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008202 int capacity = HashTable<Shape, Key>::Capacity();
8203 for (int i = 0; i < capacity; i++) {
8204 Object* k = HashTable<Shape, Key>::KeyAt(i);
8205 if (HashTable<Shape, Key>::IsKey(k)) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008206 PrintF(out, " ");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008207 if (k->IsString()) {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008208 String::cast(k)->StringPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008209 } else {
whesse@chromium.org023421e2010-12-21 12:19:12 +00008210 k->ShortPrint(out);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008211 }
whesse@chromium.org023421e2010-12-21 12:19:12 +00008212 PrintF(out, ": ");
8213 ValueAt(i)->ShortPrint(out);
8214 PrintF(out, "\n");
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008215 }
8216 }
8217}
8218#endif
8219
8220
8221template<typename Shape, typename Key>
8222void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008223 int pos = 0;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008224 int capacity = HashTable<Shape, Key>::Capacity();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008225 AssertNoAllocation no_gc;
8226 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008227 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008228 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8229 if (Dictionary<Shape, Key>::IsKey(k)) {
8230 elements->set(pos++, ValueAt(i), mode);
8231 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008232 }
8233 ASSERT(pos == elements->length());
8234}
8235
8236
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008237InterceptorInfo* JSObject::GetNamedInterceptor() {
8238 ASSERT(map()->has_named_interceptor());
8239 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008240 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008241 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008242 constructor->shared()->get_api_func_data()->named_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243 return InterceptorInfo::cast(result);
8244}
8245
8246
8247InterceptorInfo* JSObject::GetIndexedInterceptor() {
8248 ASSERT(map()->has_indexed_interceptor());
8249 JSFunction* constructor = JSFunction::cast(map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008250 ASSERT(constructor->shared()->IsApiFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008251 Object* result =
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00008252 constructor->shared()->get_api_func_data()->indexed_property_handler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253 return InterceptorInfo::cast(result);
8254}
8255
8256
lrn@chromium.org303ada72010-10-27 09:33:13 +00008257MaybeObject* JSObject::GetPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008258 JSReceiver* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008259 String* name,
8260 PropertyAttributes* attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008261 // Check local property in holder, ignore interceptor.
8262 LookupResult result;
8263 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008264 if (result.IsProperty()) {
8265 return GetProperty(receiver, &result, name, attributes);
8266 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008267 // Continue searching via the prototype chain.
8268 Object* pt = GetPrototype();
8269 *attributes = ABSENT;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008270 if (pt->IsNull()) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008271 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8272}
8273
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008274
lrn@chromium.org303ada72010-10-27 09:33:13 +00008275MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008276 JSReceiver* receiver,
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008277 String* name,
8278 PropertyAttributes* attributes) {
8279 // Check local property in holder, ignore interceptor.
8280 LookupResult result;
8281 LocalLookupRealNamedProperty(name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008282 if (result.IsProperty()) {
8283 return GetProperty(receiver, &result, name, attributes);
8284 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008285 return GetHeap()->undefined_value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008286}
8287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008288
lrn@chromium.org303ada72010-10-27 09:33:13 +00008289MaybeObject* JSObject::GetPropertyWithInterceptor(
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008290 JSReceiver* receiver,
ager@chromium.orge2902be2009-06-08 12:21:35 +00008291 String* name,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008292 PropertyAttributes* attributes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008293 Isolate* isolate = GetIsolate();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008294 InterceptorInfo* interceptor = GetNamedInterceptor();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 HandleScope scope(isolate);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00008296 Handle<JSReceiver> receiver_handle(receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008297 Handle<JSObject> holder_handle(this);
8298 Handle<String> name_handle(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008299
8300 if (!interceptor->getter()->IsUndefined()) {
8301 v8::NamedPropertyGetter getter =
8302 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008303 LOG(isolate,
8304 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8305 CustomArguments args(isolate, interceptor->data(), receiver, this);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00008306 v8::AccessorInfo info(args.end());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008307 v8::Handle<v8::Value> result;
8308 {
8309 // Leaving JavaScript.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 VMState state(isolate, EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311 result = getter(v8::Utils::ToLocal(name_handle), info);
8312 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008313 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008314 if (!result.IsEmpty()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 *attributes = NONE;
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00008316 return *v8::Utils::OpenHandle(*result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008317 }
8318 }
8319
lrn@chromium.org303ada72010-10-27 09:33:13 +00008320 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008321 *receiver_handle,
8322 *name_handle,
8323 attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008324 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00008325 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008326}
8327
8328
8329bool JSObject::HasRealNamedProperty(String* key) {
8330 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008331 if (IsAccessCheckNeeded()) {
8332 Heap* heap = GetHeap();
8333 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8334 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8335 return false;
8336 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008337 }
8338
8339 LookupResult result;
8340 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008341 return result.IsProperty() && (result.type() != INTERCEPTOR);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008342}
8343
8344
8345bool JSObject::HasRealElementProperty(uint32_t index) {
8346 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008347 if (IsAccessCheckNeeded()) {
8348 Heap* heap = GetHeap();
8349 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8350 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8351 return false;
8352 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008353 }
8354
8355 // Handle [] on String objects.
8356 if (this->IsStringObjectWithCharacterAt(index)) return true;
8357
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008358 switch (GetElementsKind()) {
8359 case FAST_ELEMENTS: {
8360 uint32_t length = IsJSArray() ?
8361 static_cast<uint32_t>(
8362 Smi::cast(JSArray::cast(this)->length())->value()) :
8363 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8364 return (index < length) &&
8365 !FixedArray::cast(elements())->get(index)->IsTheHole();
8366 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008367 case EXTERNAL_PIXEL_ELEMENTS: {
8368 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008369 return index < static_cast<uint32_t>(pixels->length());
8370 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008371 case EXTERNAL_BYTE_ELEMENTS:
8372 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8373 case EXTERNAL_SHORT_ELEMENTS:
8374 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8375 case EXTERNAL_INT_ELEMENTS:
8376 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008377 case EXTERNAL_FLOAT_ELEMENTS:
8378 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008379 ExternalArray* array = ExternalArray::cast(elements());
8380 return index < static_cast<uint32_t>(array->length());
8381 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008382 case DICTIONARY_ELEMENTS: {
8383 return element_dictionary()->FindEntry(index)
8384 != NumberDictionary::kNotFound;
8385 }
8386 default:
8387 UNREACHABLE();
8388 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008389 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008390 // All possibilities have been handled above already.
8391 UNREACHABLE();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008392 return GetHeap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008393}
8394
8395
8396bool JSObject::HasRealNamedCallbackProperty(String* key) {
8397 // Check access rights if needed.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008398 if (IsAccessCheckNeeded()) {
8399 Heap* heap = GetHeap();
8400 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8401 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8402 return false;
8403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008404 }
8405
8406 LookupResult result;
8407 LocalLookupRealNamedProperty(key, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00008408 return result.IsProperty() && (result.type() == CALLBACKS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008409}
8410
8411
8412int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
8413 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008414 DescriptorArray* descs = map()->instance_descriptors();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008415 int result = 0;
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008416 for (int i = 0; i < descs->number_of_descriptors(); i++) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008417 PropertyDetails details(descs->GetDetails(i));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008418 if (details.IsProperty() && (details.attributes() & filter) == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008419 result++;
8420 }
8421 }
8422 return result;
8423 } else {
8424 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
8425 }
8426}
8427
8428
8429int JSObject::NumberOfEnumProperties() {
8430 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
8431}
8432
8433
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008434void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008435 Object* temp = get(i);
8436 set(i, get(j));
8437 set(j, temp);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008438 if (this != numbers) {
8439 temp = numbers->get(i);
8440 numbers->set(i, numbers->get(j));
8441 numbers->set(j, temp);
8442 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008443}
8444
8445
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008446static void InsertionSortPairs(FixedArray* content,
8447 FixedArray* numbers,
8448 int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008449 for (int i = 1; i < len; i++) {
8450 int j = i;
8451 while (j > 0 &&
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008452 (NumberToUint32(numbers->get(j - 1)) >
8453 NumberToUint32(numbers->get(j)))) {
8454 content->SwapPairs(numbers, j - 1, j);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008455 j--;
8456 }
8457 }
8458}
8459
8460
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008461void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008462 // In-place heap sort.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008463 ASSERT(content->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008464
8465 // Bottom-up max-heap construction.
8466 for (int i = 1; i < len; ++i) {
8467 int child_index = i;
8468 while (child_index > 0) {
8469 int parent_index = ((child_index + 1) >> 1) - 1;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008470 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8471 uint32_t child_value = NumberToUint32(numbers->get(child_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008472 if (parent_value < child_value) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008473 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474 } else {
8475 break;
8476 }
8477 child_index = parent_index;
8478 }
8479 }
8480
8481 // Extract elements and create sorted array.
8482 for (int i = len - 1; i > 0; --i) {
8483 // Put max element at the back of the array.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008484 content->SwapPairs(numbers, 0, i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008485 // Sift down the new top element.
8486 int parent_index = 0;
8487 while (true) {
8488 int child_index = ((parent_index + 1) << 1) - 1;
8489 if (child_index >= i) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008490 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
8491 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
8492 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008493 if (child_index + 1 >= i || child1_value > child2_value) {
8494 if (parent_value > child1_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008495 content->SwapPairs(numbers, parent_index, child_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008496 parent_index = child_index;
8497 } else {
8498 if (parent_value > child2_value) break;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008499 content->SwapPairs(numbers, parent_index, child_index + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008500 parent_index = child_index + 1;
8501 }
8502 }
8503 }
8504}
8505
8506
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008507// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
8508void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
8509 ASSERT(this->length() == numbers->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008510 // For small arrays, simply use insertion sort.
8511 if (len <= 10) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008512 InsertionSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008513 return;
8514 }
8515 // Check the range of indices.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008516 uint32_t min_index = NumberToUint32(numbers->get(0));
8517 uint32_t max_index = min_index;
8518 uint32_t i;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008519 for (i = 1; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008520 if (NumberToUint32(numbers->get(i)) < min_index) {
8521 min_index = NumberToUint32(numbers->get(i));
8522 } else if (NumberToUint32(numbers->get(i)) > max_index) {
8523 max_index = NumberToUint32(numbers->get(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008524 }
8525 }
8526 if (max_index - min_index + 1 == len) {
8527 // Indices form a contiguous range, unless there are duplicates.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008528 // Do an in-place linear time sort assuming distinct numbers, but
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008529 // avoid hanging in case they are not.
8530 for (i = 0; i < len; i++) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008531 uint32_t p;
8532 uint32_t j = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008533 // While the current element at i is not at its correct position p,
8534 // swap the elements at these two positions.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008535 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536 j++ < len) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008537 SwapPairs(numbers, i, p);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538 }
8539 }
8540 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008541 HeapSortPairs(this, numbers, len);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008542 return;
8543 }
8544}
8545
8546
8547// Fill in the names of local properties into the supplied storage. The main
8548// purpose of this function is to provide reflection information for the object
8549// mirrors.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008550void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008551 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008552 if (HasFastProperties()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00008553 DescriptorArray* descs = map()->instance_descriptors();
8554 for (int i = 0; i < descs->number_of_descriptors(); i++) {
8555 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008556 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008557 ASSERT(storage->length() >= index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008558 } else {
8559 property_dictionary()->CopyKeysTo(storage);
8560 }
8561}
8562
8563
8564int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
8565 return GetLocalElementKeys(NULL, filter);
8566}
8567
8568
8569int JSObject::NumberOfEnumElements() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008570 // Fast case for objects with no elements.
8571 if (!IsJSValue() && HasFastElements()) {
8572 uint32_t length = IsJSArray() ?
8573 static_cast<uint32_t>(
8574 Smi::cast(JSArray::cast(this)->length())->value()) :
8575 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8576 if (length == 0) return 0;
8577 }
8578 // Compute the number of enumerable elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008579 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
8580}
8581
8582
8583int JSObject::GetLocalElementKeys(FixedArray* storage,
8584 PropertyAttributes filter) {
8585 int counter = 0;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008586 switch (GetElementsKind()) {
8587 case FAST_ELEMENTS: {
8588 int length = IsJSArray() ?
8589 Smi::cast(JSArray::cast(this)->length())->value() :
8590 FixedArray::cast(elements())->length();
8591 for (int i = 0; i < length; i++) {
8592 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
8593 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008594 storage->set(counter, Smi::FromInt(i));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008595 }
8596 counter++;
8597 }
8598 }
8599 ASSERT(!storage || storage->length() >= counter);
8600 break;
8601 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008602 case EXTERNAL_PIXEL_ELEMENTS: {
8603 int length = ExternalPixelArray::cast(elements())->length();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008604 while (counter < length) {
8605 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008606 storage->set(counter, Smi::FromInt(counter));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008607 }
8608 counter++;
8609 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008610 ASSERT(!storage || storage->length() >= counter);
8611 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612 }
ager@chromium.org3811b432009-10-28 14:53:37 +00008613 case EXTERNAL_BYTE_ELEMENTS:
8614 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8615 case EXTERNAL_SHORT_ELEMENTS:
8616 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8617 case EXTERNAL_INT_ELEMENTS:
8618 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008619 case EXTERNAL_FLOAT_ELEMENTS:
8620 case EXTERNAL_DOUBLE_ELEMENTS: {
ager@chromium.org3811b432009-10-28 14:53:37 +00008621 int length = ExternalArray::cast(elements())->length();
8622 while (counter < length) {
8623 if (storage != NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008624 storage->set(counter, Smi::FromInt(counter));
ager@chromium.org3811b432009-10-28 14:53:37 +00008625 }
8626 counter++;
8627 }
8628 ASSERT(!storage || storage->length() >= counter);
8629 break;
8630 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008631 case DICTIONARY_ELEMENTS: {
8632 if (storage != NULL) {
8633 element_dictionary()->CopyKeysTo(storage, filter);
8634 }
8635 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
8636 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008637 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008638 default:
8639 UNREACHABLE();
8640 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008641 }
8642
8643 if (this->IsJSValue()) {
8644 Object* val = JSValue::cast(this)->value();
8645 if (val->IsString()) {
8646 String* str = String::cast(val);
8647 if (storage) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008648 for (int i = 0; i < str->length(); i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008649 storage->set(counter + i, Smi::FromInt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008650 }
8651 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008652 counter += str->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653 }
8654 }
8655 ASSERT(!storage || storage->length() == counter);
8656 return counter;
8657}
8658
8659
8660int JSObject::GetEnumElementKeys(FixedArray* storage) {
8661 return GetLocalElementKeys(storage,
8662 static_cast<PropertyAttributes>(DONT_ENUM));
8663}
8664
8665
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008666// StringKey simply carries a string object as key.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008667class StringKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008668 public:
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008669 explicit StringKey(String* string) :
8670 string_(string),
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008671 hash_(HashForObject(string)) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008672
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008673 bool IsMatch(Object* string) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008674 // We know that all entries in a hash table had their hash keys created.
8675 // Use that knowledge to have fast failure.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008676 if (hash_ != HashForObject(string)) {
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008677 return false;
8678 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008679 return string_->Equals(String::cast(string));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008680 }
8681
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008682 uint32_t Hash() { return hash_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008683
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008684 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008685
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008686 Object* AsObject() { return string_; }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008687
8688 String* string_;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008689 uint32_t hash_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690};
8691
ager@chromium.org381abbb2009-02-25 13:23:22 +00008692
8693// StringSharedKeys are used as keys in the eval cache.
8694class StringSharedKey : public HashTableKey {
8695 public:
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008696 StringSharedKey(String* source,
8697 SharedFunctionInfo* shared,
8698 StrictModeFlag strict_mode)
8699 : source_(source),
8700 shared_(shared),
8701 strict_mode_(strict_mode) { }
ager@chromium.org381abbb2009-02-25 13:23:22 +00008702
8703 bool IsMatch(Object* other) {
8704 if (!other->IsFixedArray()) return false;
8705 FixedArray* pair = FixedArray::cast(other);
8706 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8707 if (shared != shared_) return false;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008708 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8709 Smi::cast(pair->get(2))->value());
8710 if (strict_mode != strict_mode_) return false;
ager@chromium.org381abbb2009-02-25 13:23:22 +00008711 String* source = String::cast(pair->get(1));
8712 return source->Equals(source_);
8713 }
8714
ager@chromium.org381abbb2009-02-25 13:23:22 +00008715 static uint32_t StringSharedHashHelper(String* source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008716 SharedFunctionInfo* shared,
8717 StrictModeFlag strict_mode) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00008718 uint32_t hash = source->Hash();
8719 if (shared->HasSourceCode()) {
8720 // Instead of using the SharedFunctionInfo pointer in the hash
8721 // code computation, we use a combination of the hash of the
8722 // script source code and the start and end positions. We do
8723 // this to ensure that the cache entries can survive garbage
8724 // collection.
8725 Script* script = Script::cast(shared->script());
8726 hash ^= String::cast(script->source())->Hash();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008727 if (strict_mode == kStrictMode) hash ^= 0x8000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00008728 hash += shared->start_position();
8729 }
8730 return hash;
8731 }
8732
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008733 uint32_t Hash() {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008734 return StringSharedHashHelper(source_, shared_, strict_mode_);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008735 }
8736
8737 uint32_t HashForObject(Object* obj) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00008738 FixedArray* pair = FixedArray::cast(obj);
8739 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8740 String* source = String::cast(pair->get(1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008741 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8742 Smi::cast(pair->get(2))->value());
8743 return StringSharedHashHelper(source, shared, strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +00008744 }
8745
lrn@chromium.org303ada72010-10-27 09:33:13 +00008746 MUST_USE_RESULT MaybeObject* AsObject() {
8747 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008748 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008749 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8750 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00008751 FixedArray* pair = FixedArray::cast(obj);
8752 pair->set(0, shared_);
8753 pair->set(1, source_);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008754 pair->set(2, Smi::FromInt(strict_mode_));
ager@chromium.org381abbb2009-02-25 13:23:22 +00008755 return pair;
8756 }
8757
ager@chromium.org381abbb2009-02-25 13:23:22 +00008758 private:
8759 String* source_;
8760 SharedFunctionInfo* shared_;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008761 StrictModeFlag strict_mode_;
ager@chromium.org381abbb2009-02-25 13:23:22 +00008762};
8763
8764
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008765// RegExpKey carries the source and flags of a regular expression as key.
8766class RegExpKey : public HashTableKey {
8767 public:
8768 RegExpKey(String* string, JSRegExp::Flags flags)
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008769 : string_(string),
8770 flags_(Smi::FromInt(flags.value())) { }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008771
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00008772 // Rather than storing the key in the hash table, a pointer to the
8773 // stored value is stored where the key should be. IsMatch then
8774 // compares the search key to the found object, rather than comparing
8775 // a key to a key.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008776 bool IsMatch(Object* obj) {
8777 FixedArray* val = FixedArray::cast(obj);
8778 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
8779 && (flags_ == val->get(JSRegExp::kFlagsIndex));
8780 }
8781
8782 uint32_t Hash() { return RegExpHash(string_, flags_); }
8783
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008784 Object* AsObject() {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008785 // Plain hash maps, which is where regexp keys are used, don't
8786 // use this function.
8787 UNREACHABLE();
8788 return NULL;
8789 }
8790
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008791 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008792 FixedArray* val = FixedArray::cast(obj);
8793 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
8794 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
8795 }
8796
8797 static uint32_t RegExpHash(String* string, Smi* flags) {
8798 return string->Hash() + flags->value();
8799 }
8800
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008801 String* string_;
8802 Smi* flags_;
8803};
8804
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008805// Utf8SymbolKey carries a vector of chars as key.
8806class Utf8SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008807 public:
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008808 explicit Utf8SymbolKey(Vector<const char> string)
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008809 : string_(string), hash_field_(0) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008810
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008811 bool IsMatch(Object* string) {
8812 return String::cast(string)->IsEqualTo(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008813 }
8814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008815 uint32_t Hash() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008816 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008817 unibrow::Utf8InputBuffer<> buffer(string_.start(),
8818 static_cast<unsigned>(string_.length()));
8819 chars_ = buffer.Length();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008820 hash_field_ = String::ComputeHashField(&buffer, chars_);
8821 uint32_t result = hash_field_ >> String::kHashShift;
ager@chromium.org3b45ab52009-03-19 22:21:34 +00008822 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8823 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008824 }
8825
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008826 uint32_t HashForObject(Object* other) {
8827 return String::cast(other)->Hash();
8828 }
8829
lrn@chromium.org303ada72010-10-27 09:33:13 +00008830 MaybeObject* AsObject() {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008831 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008832 return Isolate::Current()->heap()->AllocateSymbol(
8833 string_, chars_, hash_field_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008834 }
8835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 Vector<const char> string_;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008837 uint32_t hash_field_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008838 int chars_; // Caches the number of characters when computing the hash code.
8839};
8840
8841
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008842template <typename Char>
8843class SequentialSymbolKey : public HashTableKey {
8844 public:
8845 explicit SequentialSymbolKey(Vector<const Char> string)
8846 : string_(string), hash_field_(0) { }
8847
8848 uint32_t Hash() {
8849 StringHasher hasher(string_.length());
8850
8851 // Very long strings have a trivial hash that doesn't inspect the
8852 // string contents.
8853 if (hasher.has_trivial_hash()) {
8854 hash_field_ = hasher.GetHashField();
8855 } else {
8856 int i = 0;
8857 // Do the iterative array index computation as long as there is a
8858 // chance this is an array index.
8859 while (i < string_.length() && hasher.is_array_index()) {
8860 hasher.AddCharacter(static_cast<uc32>(string_[i]));
8861 i++;
8862 }
8863
8864 // Process the remaining characters without updating the array
8865 // index.
8866 while (i < string_.length()) {
8867 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
8868 i++;
8869 }
8870 hash_field_ = hasher.GetHashField();
8871 }
8872
8873 uint32_t result = hash_field_ >> String::kHashShift;
8874 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8875 return result;
8876 }
8877
8878
8879 uint32_t HashForObject(Object* other) {
8880 return String::cast(other)->Hash();
8881 }
8882
8883 Vector<const Char> string_;
8884 uint32_t hash_field_;
8885};
8886
8887
8888
8889class AsciiSymbolKey : public SequentialSymbolKey<char> {
8890 public:
8891 explicit AsciiSymbolKey(Vector<const char> str)
8892 : SequentialSymbolKey<char>(str) { }
8893
8894 bool IsMatch(Object* string) {
8895 return String::cast(string)->IsAsciiEqualTo(string_);
8896 }
8897
8898 MaybeObject* AsObject() {
8899 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008900 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008901 }
8902};
8903
8904
danno@chromium.org40cb8782011-05-25 07:58:50 +00008905class SubStringAsciiSymbolKey : public HashTableKey {
8906 public:
8907 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
8908 int from,
8909 int length)
8910 : string_(string), from_(from), length_(length) { }
8911
8912 uint32_t Hash() {
8913 ASSERT(length_ >= 0);
8914 ASSERT(from_ + length_ <= string_->length());
8915 StringHasher hasher(length_);
8916
8917 // Very long strings have a trivial hash that doesn't inspect the
8918 // string contents.
8919 if (hasher.has_trivial_hash()) {
8920 hash_field_ = hasher.GetHashField();
8921 } else {
8922 int i = 0;
8923 // Do the iterative array index computation as long as there is a
8924 // chance this is an array index.
8925 while (i < length_ && hasher.is_array_index()) {
8926 hasher.AddCharacter(static_cast<uc32>(
8927 string_->SeqAsciiStringGet(i + from_)));
8928 i++;
8929 }
8930
8931 // Process the remaining characters without updating the array
8932 // index.
8933 while (i < length_) {
8934 hasher.AddCharacterNoIndex(static_cast<uc32>(
8935 string_->SeqAsciiStringGet(i + from_)));
8936 i++;
8937 }
8938 hash_field_ = hasher.GetHashField();
8939 }
8940
8941 uint32_t result = hash_field_ >> String::kHashShift;
8942 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8943 return result;
8944 }
8945
8946
8947 uint32_t HashForObject(Object* other) {
8948 return String::cast(other)->Hash();
8949 }
8950
8951 bool IsMatch(Object* string) {
8952 Vector<const char> chars(string_->GetChars() + from_, length_);
8953 return String::cast(string)->IsAsciiEqualTo(chars);
8954 }
8955
8956 MaybeObject* AsObject() {
8957 if (hash_field_ == 0) Hash();
8958 Vector<const char> chars(string_->GetChars() + from_, length_);
8959 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
8960 }
8961
8962 private:
8963 Handle<SeqAsciiString> string_;
8964 int from_;
8965 int length_;
8966 uint32_t hash_field_;
8967};
8968
8969
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008970class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
8971 public:
8972 explicit TwoByteSymbolKey(Vector<const uc16> str)
8973 : SequentialSymbolKey<uc16>(str) { }
8974
8975 bool IsMatch(Object* string) {
8976 return String::cast(string)->IsTwoByteEqualTo(string_);
8977 }
8978
8979 MaybeObject* AsObject() {
8980 if (hash_field_ == 0) Hash();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008981 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00008982 }
8983};
8984
8985
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008986// SymbolKey carries a string/symbol object as key.
8987class SymbolKey : public HashTableKey {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008988 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008989 explicit SymbolKey(String* string)
8990 : string_(string) { }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008991
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008992 bool IsMatch(Object* string) {
8993 return String::cast(string)->Equals(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008994 }
8995
8996 uint32_t Hash() { return string_->Hash(); }
8997
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00008998 uint32_t HashForObject(Object* other) {
8999 return String::cast(other)->Hash();
9000 }
9001
lrn@chromium.org303ada72010-10-27 09:33:13 +00009002 MaybeObject* AsObject() {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00009003 // Attempt to flatten the string, so that symbols will most often
9004 // be flat strings.
9005 string_ = string_->TryFlattenGetString();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009006 Heap* heap = string_->GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009007 // Transform string to symbol if possible.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008 Map* map = heap->SymbolMapForString(string_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009009 if (map != NULL) {
9010 string_->set_map(map);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00009011 ASSERT(string_->IsSymbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 return string_;
9013 }
9014 // Otherwise allocate a new symbol.
9015 StringInputBuffer buffer(string_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009016 return heap->AllocateInternalSymbol(&buffer,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009017 string_->length(),
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009018 string_->hash_field());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009019 }
9020
9021 static uint32_t StringHash(Object* obj) {
9022 return String::cast(obj)->Hash();
9023 }
9024
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009025 String* string_;
9026};
9027
9028
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009029template<typename Shape, typename Key>
9030void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 IteratePointers(v, 0, kElementsStartOffset);
9032}
9033
9034
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009035template<typename Shape, typename Key>
9036void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009037 IteratePointers(v,
9038 kElementsStartOffset,
9039 kHeaderSize + length() * kPointerSize);
9040}
9041
9042
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009043template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009044MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9045 PretenureFlag pretenure) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009046 const int kMinCapacity = 32;
9047 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
9048 if (capacity < kMinCapacity) {
9049 capacity = kMinCapacity; // Guarantee min capacity.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009050 } else if (capacity > HashTable::kMaxCapacity) {
9051 return Failure::OutOfMemoryException();
9052 }
9053
lrn@chromium.org303ada72010-10-27 09:33:13 +00009054 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009055 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9056 AllocateHashTable(EntryToIndex(capacity), pretenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009057 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009059 HashTable::cast(obj)->SetNumberOfElements(0);
9060 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9061 HashTable::cast(obj)->SetCapacity(capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009062 return obj;
9063}
9064
9065
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009066// Find entry for key otherwise return kNotFound.
ricow@chromium.org4980dff2010-07-19 08:33:45 +00009067int StringDictionary::FindEntry(String* key) {
9068 if (!key->IsSymbol()) {
9069 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9070 }
9071
9072 // Optimized for symbol key. Knowledge of the key type allows:
9073 // 1. Move the check if the key is a symbol out of the loop.
9074 // 2. Avoid comparing hash codes in symbol to symbol comparision.
9075 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9076 // In case of positive result the dictionary key may be replaced by
9077 // the symbol with minimal performance penalty. It gives a chance to
9078 // perform further lookups in code stubs (and significant performance boost
9079 // a certain style of code).
9080
9081 // EnsureCapacity will guarantee the hash table is never full.
9082 uint32_t capacity = Capacity();
9083 uint32_t entry = FirstProbe(key->Hash(), capacity);
9084 uint32_t count = 1;
9085
9086 while (true) {
9087 int index = EntryToIndex(entry);
9088 Object* element = get(index);
9089 if (element->IsUndefined()) break; // Empty entry.
9090 if (key == element) return entry;
9091 if (!element->IsSymbol() &&
9092 !element->IsNull() &&
9093 String::cast(element)->Equals(key)) {
9094 // Replace a non-symbol key by the equivalent symbol for faster further
9095 // lookups.
9096 set(index, key);
9097 return entry;
9098 }
9099 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9100 entry = NextProbe(entry, count++, capacity);
9101 }
9102 return kNotFound;
9103}
9104
9105
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009106template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009107MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009108 int capacity = Capacity();
9109 int nof = NumberOfElements() + n;
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009110 int nod = NumberOfDeletedElements();
9111 // Return if:
9112 // 50% is still free after adding n elements and
9113 // at most 50% of the free elements are deleted elements.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009114 if (nod <= (capacity - nof) >> 1) {
9115 int needed_free = nof >> 1;
9116 if (nof + needed_free <= capacity) return this;
9117 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009119 const int kMinCapacityForPretenure = 256;
9120 bool pretenure =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009121 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009122 Object* obj;
9123 { MaybeObject* maybe_obj =
9124 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9125 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9126 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009127
9128 AssertNoAllocation no_gc;
ager@chromium.org236ad962008-09-25 09:45:57 +00009129 HashTable* table = HashTable::cast(obj);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009130 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131
9132 // Copy prefix to new array.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009133 for (int i = kPrefixStartIndex;
9134 i < kPrefixStartIndex + Shape::kPrefixSize;
9135 i++) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009136 table->set(i, get(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 }
9138 // Rehash the elements.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139 for (int i = 0; i < capacity; i++) {
9140 uint32_t from_index = EntryToIndex(i);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009141 Object* k = get(from_index);
9142 if (IsKey(k)) {
9143 uint32_t hash = Shape::HashForObject(key, k);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009144 uint32_t insertion_index =
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009145 EntryToIndex(table->FindInsertionEntry(hash));
9146 for (int j = 0; j < Shape::kEntrySize; j++) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009147 table->set(insertion_index + j, get(from_index + j), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148 }
9149 }
9150 }
ager@chromium.org236ad962008-09-25 09:45:57 +00009151 table->SetNumberOfElements(NumberOfElements());
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009152 table->SetNumberOfDeletedElements(0);
ager@chromium.org236ad962008-09-25 09:45:57 +00009153 return table;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009154}
9155
9156
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009157template<typename Shape, typename Key>
9158uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 uint32_t capacity = Capacity();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009160 uint32_t entry = FirstProbe(hash, capacity);
9161 uint32_t count = 1;
9162 // EnsureCapacity will guarantee the hash table is never full.
9163 while (true) {
9164 Object* element = KeyAt(entry);
9165 if (element->IsUndefined() || element->IsNull()) break;
9166 entry = NextProbe(entry, count++, capacity);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009167 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009168 return entry;
9169}
9170
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009171// Force instantiation of template instances class.
9172// Please note this list is compiler dependent.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009173
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009174template class HashTable<SymbolTableShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009175
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009176template class HashTable<CompilationCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009178template class HashTable<MapCacheShape, HashTableKey*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009180template class Dictionary<StringDictionaryShape, String*>;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009181
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009182template class Dictionary<NumberDictionaryShape, uint32_t>;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009183
lrn@chromium.org303ada72010-10-27 09:33:13 +00009184template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009185 int);
9186
lrn@chromium.org303ada72010-10-27 09:33:13 +00009187template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009188 int);
9189
lrn@chromium.org303ada72010-10-27 09:33:13 +00009190template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009191 uint32_t, Object*);
9192
9193template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9194 Object*);
9195
9196template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9197 Object*);
9198
9199template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
9200 FixedArray*, PropertyAttributes);
9201
9202template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9203 int, JSObject::DeleteMode);
9204
9205template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
9206 int, JSObject::DeleteMode);
9207
9208template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
9209 FixedArray*);
9210
9211template int
9212Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
9213 PropertyAttributes);
9214
lrn@chromium.org303ada72010-10-27 09:33:13 +00009215template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009216 String*, Object*, PropertyDetails);
9217
lrn@chromium.org303ada72010-10-27 09:33:13 +00009218template MaybeObject*
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009219Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
9220
9221template int
9222Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
9223 PropertyAttributes);
9224
lrn@chromium.org303ada72010-10-27 09:33:13 +00009225template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009226 uint32_t, Object*, PropertyDetails);
9227
lrn@chromium.org303ada72010-10-27 09:33:13 +00009228template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
9229 EnsureCapacity(int, uint32_t);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009230
lrn@chromium.org303ada72010-10-27 09:33:13 +00009231template MaybeObject* Dictionary<StringDictionaryShape, String*>::
9232 EnsureCapacity(int, String*);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009233
lrn@chromium.org303ada72010-10-27 09:33:13 +00009234template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009235 uint32_t, Object*, PropertyDetails, uint32_t);
9236
lrn@chromium.org303ada72010-10-27 09:33:13 +00009237template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009238 String*, Object*, PropertyDetails, uint32_t);
9239
9240template
9241int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
9242
9243template
9244int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009245
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009246template
9247int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
9248
9249
ager@chromium.org5ec48922009-05-05 07:25:34 +00009250// Collates undefined and unexisting elements below limit from position
9251// zero of the elements. The object stays in Dictionary mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009252MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009253 ASSERT(HasDictionaryElements());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009254 // Must stay in dictionary mode, either because of requires_slow_elements,
9255 // or because we are not going to sort (and therefore compact) all of the
9256 // elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009257 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009258 HeapNumber* result_double = NULL;
9259 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9260 // Allocate space for result before we start mutating the object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009261 Object* new_double;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009262 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009263 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9264 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009265 result_double = HeapNumber::cast(new_double);
9266 }
9267
lrn@chromium.org303ada72010-10-27 09:33:13 +00009268 Object* obj;
9269 { MaybeObject* maybe_obj =
9270 NumberDictionary::Allocate(dict->NumberOfElements());
9271 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9272 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009273 NumberDictionary* new_dict = NumberDictionary::cast(obj);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009274
9275 AssertNoAllocation no_alloc;
9276
ager@chromium.org5ec48922009-05-05 07:25:34 +00009277 uint32_t pos = 0;
9278 uint32_t undefs = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009279 int capacity = dict->Capacity();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009280 for (int i = 0; i < capacity; i++) {
9281 Object* k = dict->KeyAt(i);
9282 if (dict->IsKey(k)) {
9283 ASSERT(k->IsNumber());
9284 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
9285 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
9286 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
9287 Object* value = dict->ValueAt(i);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009288 PropertyDetails details = dict->DetailsAt(i);
9289 if (details.type() == CALLBACKS) {
9290 // Bail out and do the sorting of undefineds and array holes in JS.
9291 return Smi::FromInt(-1);
9292 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009293 uint32_t key = NumberToUint32(k);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009294 // In the following we assert that adding the entry to the new dictionary
9295 // does not cause GC. This is the case because we made sure to allocate
9296 // the dictionary big enough above, so it need not grow.
ager@chromium.org5ec48922009-05-05 07:25:34 +00009297 if (key < limit) {
9298 if (value->IsUndefined()) {
9299 undefs++;
9300 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009301 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9302 // Adding an entry with the key beyond smi-range requires
9303 // allocation. Bailout.
9304 return Smi::FromInt(-1);
9305 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009306 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009307 pos++;
9308 }
9309 } else {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009310 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
9311 // Adding an entry with the key beyond smi-range requires
9312 // allocation. Bailout.
9313 return Smi::FromInt(-1);
9314 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009315 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009316 }
9317 }
9318 }
9319
9320 uint32_t result = pos;
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009321 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009322 Heap* heap = GetHeap();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009323 while (undefs > 0) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00009324 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9325 // Adding an entry with the key beyond smi-range requires
9326 // allocation. Bailout.
9327 return Smi::FromInt(-1);
9328 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009329 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
lrn@chromium.org303ada72010-10-27 09:33:13 +00009330 ToObjectUnchecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009331 pos++;
9332 undefs--;
9333 }
9334
9335 set_elements(new_dict);
9336
9337 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9338 return Smi::FromInt(static_cast<int>(result));
9339 }
9340
9341 ASSERT_NE(NULL, result_double);
9342 result_double->set_value(static_cast<double>(result));
9343 return result_double;
9344}
9345
9346
9347// Collects all defined (non-hole) and non-undefined (array) elements at
9348// the start of the elements array.
9349// If the object is in dictionary mode, it is converted to fast elements
9350// mode.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009351MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009352 ASSERT(!HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009353
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009354 Heap* heap = GetHeap();
9355
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009356 if (HasDictionaryElements()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009357 // Convert to fast elements containing only the existing properties.
9358 // Ordering is irrelevant, since we are going to sort anyway.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009359 NumberDictionary* dict = element_dictionary();
ager@chromium.org5ec48922009-05-05 07:25:34 +00009360 if (IsJSArray() || dict->requires_slow_elements() ||
9361 dict->max_number_key() >= limit) {
9362 return PrepareSlowElementsForSort(limit);
9363 }
9364 // Convert to fast elements.
9365
lrn@chromium.org303ada72010-10-27 09:33:13 +00009366 Object* obj;
9367 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
9368 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9369 }
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009370 Map* new_map = Map::cast(obj);
9371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009372 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009373 Object* new_array;
9374 { MaybeObject* maybe_new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009375 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009376 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
9377 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009378 FixedArray* fast_elements = FixedArray::cast(new_array);
9379 dict->CopyValuesTo(fast_elements);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009380
9381 set_map(new_map);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009382 set_elements(fast_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00009383 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009384 Object* obj;
9385 { MaybeObject* maybe_obj = EnsureWritableFastElements();
9386 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9387 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009388 }
9389 ASSERT(HasFastElements());
9390
9391 // Collect holes at the end, undefined before that and the rest at the
9392 // start, and return the number of non-hole, non-undefined values.
9393
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009394 FixedArray* elements = FixedArray::cast(this->elements());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009395 uint32_t elements_length = static_cast<uint32_t>(elements->length());
9396 if (limit > elements_length) {
9397 limit = elements_length ;
9398 }
9399 if (limit == 0) {
9400 return Smi::FromInt(0);
9401 }
9402
9403 HeapNumber* result_double = NULL;
9404 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9405 // Pessimistically allocate space for return value before
9406 // we start mutating the array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009407 Object* new_double;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009408 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009409 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9410 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00009411 result_double = HeapNumber::cast(new_double);
9412 }
9413
9414 AssertNoAllocation no_alloc;
9415
9416 // Split elements into defined, undefined and the_hole, in that order.
9417 // Only count locations for undefined and the hole, and fill them afterwards.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009418 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009419 unsigned int undefs = limit;
9420 unsigned int holes = limit;
9421 // Assume most arrays contain no holes and undefined values, so minimize the
9422 // number of stores of non-undefined, non-the-hole values.
9423 for (unsigned int i = 0; i < undefs; i++) {
9424 Object* current = elements->get(i);
9425 if (current->IsTheHole()) {
9426 holes--;
9427 undefs--;
9428 } else if (current->IsUndefined()) {
9429 undefs--;
9430 } else {
9431 continue;
9432 }
9433 // Position i needs to be filled.
9434 while (undefs > i) {
9435 current = elements->get(undefs);
9436 if (current->IsTheHole()) {
9437 holes--;
9438 undefs--;
9439 } else if (current->IsUndefined()) {
9440 undefs--;
9441 } else {
9442 elements->set(i, current, write_barrier);
9443 break;
9444 }
9445 }
9446 }
9447 uint32_t result = undefs;
9448 while (undefs < holes) {
9449 elements->set_undefined(undefs);
9450 undefs++;
9451 }
9452 while (holes < limit) {
9453 elements->set_the_hole(holes);
9454 holes++;
9455 }
9456
9457 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9458 return Smi::FromInt(static_cast<int>(result));
9459 }
9460 ASSERT_NE(NULL, result_double);
9461 result_double->set_value(static_cast<double>(result));
9462 return result_double;
9463}
9464
9465
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009466Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009467 uint8_t clamped_value = 0;
9468 if (index < static_cast<uint32_t>(length())) {
9469 if (value->IsSmi()) {
9470 int int_value = Smi::cast(value)->value();
9471 if (int_value < 0) {
9472 clamped_value = 0;
9473 } else if (int_value > 255) {
9474 clamped_value = 255;
9475 } else {
9476 clamped_value = static_cast<uint8_t>(int_value);
9477 }
9478 } else if (value->IsHeapNumber()) {
9479 double double_value = HeapNumber::cast(value)->value();
9480 if (!(double_value > 0)) {
9481 // NaN and less than zero clamp to zero.
9482 clamped_value = 0;
9483 } else if (double_value > 255) {
9484 // Greater than 255 clamp to 255.
9485 clamped_value = 255;
9486 } else {
9487 // Other doubles are rounded to the nearest integer.
9488 clamped_value = static_cast<uint8_t>(double_value + 0.5);
9489 }
9490 } else {
9491 // Clamp undefined to zero (default). All other types have been
9492 // converted to a number type further up in the call chain.
9493 ASSERT(value->IsUndefined());
9494 }
9495 set(index, clamped_value);
9496 }
9497 return Smi::FromInt(clamped_value);
9498}
9499
9500
ager@chromium.org3811b432009-10-28 14:53:37 +00009501template<typename ExternalArrayClass, typename ValueType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009502static MaybeObject* ExternalArrayIntSetter(Heap* heap,
9503 ExternalArrayClass* receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009504 uint32_t index,
9505 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009506 ValueType cast_value = 0;
9507 if (index < static_cast<uint32_t>(receiver->length())) {
9508 if (value->IsSmi()) {
9509 int int_value = Smi::cast(value)->value();
9510 cast_value = static_cast<ValueType>(int_value);
9511 } else if (value->IsHeapNumber()) {
9512 double double_value = HeapNumber::cast(value)->value();
9513 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
9514 } else {
9515 // Clamp undefined to zero (default). All other types have been
9516 // converted to a number type further up in the call chain.
9517 ASSERT(value->IsUndefined());
9518 }
9519 receiver->set(index, cast_value);
9520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521 return heap->NumberFromInt32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009522}
9523
9524
lrn@chromium.org303ada72010-10-27 09:33:13 +00009525MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009526 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009527 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009528}
9529
9530
lrn@chromium.org303ada72010-10-27 09:33:13 +00009531MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
9532 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009533 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009534 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009535}
9536
9537
lrn@chromium.org303ada72010-10-27 09:33:13 +00009538MaybeObject* ExternalShortArray::SetValue(uint32_t index,
9539 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009540 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009541 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009542}
9543
9544
lrn@chromium.org303ada72010-10-27 09:33:13 +00009545MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
9546 Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009547 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009549}
9550
9551
lrn@chromium.org303ada72010-10-27 09:33:13 +00009552MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009553 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 (GetHeap(), this, index, value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009555}
9556
9557
lrn@chromium.org303ada72010-10-27 09:33:13 +00009558MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009559 uint32_t cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009560 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00009561 if (index < static_cast<uint32_t>(length())) {
9562 if (value->IsSmi()) {
9563 int int_value = Smi::cast(value)->value();
9564 cast_value = static_cast<uint32_t>(int_value);
9565 } else if (value->IsHeapNumber()) {
9566 double double_value = HeapNumber::cast(value)->value();
9567 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
9568 } else {
9569 // Clamp undefined to zero (default). All other types have been
9570 // converted to a number type further up in the call chain.
9571 ASSERT(value->IsUndefined());
9572 }
9573 set(index, cast_value);
9574 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009575 return heap->NumberFromUint32(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009576}
9577
9578
lrn@chromium.org303ada72010-10-27 09:33:13 +00009579MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
ager@chromium.org3811b432009-10-28 14:53:37 +00009580 float cast_value = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009581 Heap* heap = GetHeap();
ager@chromium.org3811b432009-10-28 14:53:37 +00009582 if (index < static_cast<uint32_t>(length())) {
9583 if (value->IsSmi()) {
9584 int int_value = Smi::cast(value)->value();
9585 cast_value = static_cast<float>(int_value);
9586 } else if (value->IsHeapNumber()) {
9587 double double_value = HeapNumber::cast(value)->value();
9588 cast_value = static_cast<float>(double_value);
9589 } else {
9590 // Clamp undefined to zero (default). All other types have been
9591 // converted to a number type further up in the call chain.
9592 ASSERT(value->IsUndefined());
9593 }
9594 set(index, cast_value);
9595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 return heap->AllocateHeapNumber(cast_value);
ager@chromium.org3811b432009-10-28 14:53:37 +00009597}
9598
9599
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009600MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
9601 double double_value = 0;
9602 Heap* heap = GetHeap();
9603 if (index < static_cast<uint32_t>(length())) {
9604 if (value->IsSmi()) {
9605 int int_value = Smi::cast(value)->value();
9606 double_value = static_cast<double>(int_value);
9607 } else if (value->IsHeapNumber()) {
9608 double_value = HeapNumber::cast(value)->value();
9609 } else {
9610 // Clamp undefined to zero (default). All other types have been
9611 // converted to a number type further up in the call chain.
9612 ASSERT(value->IsUndefined());
9613 }
9614 set(index, double_value);
9615 }
9616 return heap->AllocateHeapNumber(double_value);
9617}
9618
9619
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009620JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009621 ASSERT(!HasFastProperties());
9622 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009623 return JSGlobalPropertyCell::cast(value);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009624}
9625
9626
lrn@chromium.org303ada72010-10-27 09:33:13 +00009627MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009628 ASSERT(!HasFastProperties());
9629 int entry = property_dictionary()->FindEntry(name);
9630 if (entry == StringDictionary::kNotFound) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009631 Heap* heap = GetHeap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009632 Object* cell;
9633 { MaybeObject* maybe_cell =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009634 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009635 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
9636 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009637 PropertyDetails details(NONE, NORMAL);
9638 details = details.AsDeleted();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009639 Object* dictionary;
9640 { MaybeObject* maybe_dictionary =
9641 property_dictionary()->Add(name, cell, details);
9642 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
9643 }
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00009644 set_properties(StringDictionary::cast(dictionary));
9645 return cell;
9646 } else {
9647 Object* value = property_dictionary()->ValueAt(entry);
9648 ASSERT(value->IsJSGlobalPropertyCell());
9649 return value;
9650 }
9651}
9652
9653
lrn@chromium.org303ada72010-10-27 09:33:13 +00009654MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009655 SymbolKey key(string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009656 return LookupKey(&key, s);
9657}
9658
9659
ager@chromium.org6141cbe2009-11-20 12:14:52 +00009660// This class is used for looking up two character strings in the symbol table.
9661// If we don't have a hit we don't want to waste much time so we unroll the
9662// string hash calculation loop here for speed. Doesn't work if the two
9663// characters form a decimal integer, since such strings have a different hash
9664// algorithm.
9665class TwoCharHashTableKey : public HashTableKey {
9666 public:
9667 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
9668 : c1_(c1), c2_(c2) {
9669 // Char 1.
9670 uint32_t hash = c1 + (c1 << 10);
9671 hash ^= hash >> 6;
9672 // Char 2.
9673 hash += c2;
9674 hash += hash << 10;
9675 hash ^= hash >> 6;
9676 // GetHash.
9677 hash += hash << 3;
9678 hash ^= hash >> 11;
9679 hash += hash << 15;
9680 if (hash == 0) hash = 27;
9681#ifdef DEBUG
9682 StringHasher hasher(2);
9683 hasher.AddCharacter(c1);
9684 hasher.AddCharacter(c2);
9685 // If this assert fails then we failed to reproduce the two-character
9686 // version of the string hashing algorithm above. One reason could be
9687 // that we were passed two digits as characters, since the hash
9688 // algorithm is different in that case.
9689 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
9690#endif
9691 hash_ = hash;
9692 }
9693
9694 bool IsMatch(Object* o) {
9695 if (!o->IsString()) return false;
9696 String* other = String::cast(o);
9697 if (other->length() != 2) return false;
9698 if (other->Get(0) != c1_) return false;
9699 return other->Get(1) == c2_;
9700 }
9701
9702 uint32_t Hash() { return hash_; }
9703 uint32_t HashForObject(Object* key) {
9704 if (!key->IsString()) return 0;
9705 return String::cast(key)->Hash();
9706 }
9707
9708 Object* AsObject() {
9709 // The TwoCharHashTableKey is only used for looking in the symbol
9710 // table, not for adding to it.
9711 UNREACHABLE();
9712 return NULL;
9713 }
9714 private:
9715 uint32_t c1_;
9716 uint32_t c2_;
9717 uint32_t hash_;
9718};
9719
9720
ager@chromium.org7c537e22008-10-16 08:43:32 +00009721bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
9722 SymbolKey key(string);
9723 int entry = FindEntry(&key);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009724 if (entry == kNotFound) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00009725 return false;
9726 } else {
9727 String* result = String::cast(KeyAt(entry));
ager@chromium.org870a0b62008-11-04 11:43:05 +00009728 ASSERT(StringShape(result).IsSymbol());
ager@chromium.org7c537e22008-10-16 08:43:32 +00009729 *symbol = result;
9730 return true;
9731 }
9732}
9733
9734
ager@chromium.org6141cbe2009-11-20 12:14:52 +00009735bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
9736 uint32_t c2,
9737 String** symbol) {
9738 TwoCharHashTableKey key(c1, c2);
9739 int entry = FindEntry(&key);
9740 if (entry == kNotFound) {
9741 return false;
9742 } else {
9743 String* result = String::cast(KeyAt(entry));
9744 ASSERT(StringShape(result).IsSymbol());
9745 *symbol = result;
9746 return true;
9747 }
9748}
9749
9750
lrn@chromium.org303ada72010-10-27 09:33:13 +00009751MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009752 Utf8SymbolKey key(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009753 return LookupKey(&key, s);
9754}
9755
9756
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009757MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
9758 Object** s) {
9759 AsciiSymbolKey key(str);
9760 return LookupKey(&key, s);
9761}
9762
9763
danno@chromium.org40cb8782011-05-25 07:58:50 +00009764MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
9765 int from,
9766 int length,
9767 Object** s) {
9768 SubStringAsciiSymbolKey key(str, from, length);
9769 return LookupKey(&key, s);
9770}
9771
9772
fschneider@chromium.org9e3e0b62011-01-03 10:16:46 +00009773MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
9774 Object** s) {
9775 TwoByteSymbolKey key(str);
9776 return LookupKey(&key, s);
9777}
9778
lrn@chromium.org303ada72010-10-27 09:33:13 +00009779MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009780 int entry = FindEntry(key);
9781
9782 // Symbol already in table.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009783 if (entry != kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009784 *s = KeyAt(entry);
9785 return this;
9786 }
9787
9788 // Adding new symbol. Grow table if needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009789 Object* obj;
9790 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9791 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9792 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009793
9794 // Create symbol object.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009795 Object* symbol;
9796 { MaybeObject* maybe_symbol = key->AsObject();
9797 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
9798 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009799
9800 // If the symbol table grew as part of EnsureCapacity, obj is not
9801 // the current symbol table and therefore we cannot use
9802 // SymbolTable::cast here.
9803 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
9804
9805 // Add the new symbol and return it along with the symbol table.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009806 entry = table->FindInsertionEntry(key->Hash());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009807 table->set(EntryToIndex(entry), symbol);
9808 table->ElementAdded();
9809 *s = symbol;
9810 return table;
9811}
9812
9813
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009814Object* CompilationCacheTable::Lookup(String* src) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009815 StringKey key(src);
9816 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009817 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009818 return get(EntryToIndex(entry) + 1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009819}
9820
9821
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009822Object* CompilationCacheTable::LookupEval(String* src,
9823 Context* context,
9824 StrictModeFlag strict_mode) {
9825 StringSharedKey key(src, context->closure()->shared(), strict_mode);
ager@chromium.org381abbb2009-02-25 13:23:22 +00009826 int entry = FindEntry(&key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009827 if (entry == kNotFound) return GetHeap()->undefined_value();
ager@chromium.org381abbb2009-02-25 13:23:22 +00009828 return get(EntryToIndex(entry) + 1);
9829}
9830
9831
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009832Object* CompilationCacheTable::LookupRegExp(String* src,
9833 JSRegExp::Flags flags) {
9834 RegExpKey key(src, flags);
9835 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009836 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009837 return get(EntryToIndex(entry) + 1);
9838}
9839
9840
lrn@chromium.org303ada72010-10-27 09:33:13 +00009841MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009842 StringKey key(src);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009843 Object* obj;
9844 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9845 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9846 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009847
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009848 CompilationCacheTable* cache =
9849 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009850 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009851 cache->set(EntryToIndex(entry), src);
9852 cache->set(EntryToIndex(entry) + 1, value);
9853 cache->ElementAdded();
9854 return cache;
9855}
9856
9857
lrn@chromium.org303ada72010-10-27 09:33:13 +00009858MaybeObject* CompilationCacheTable::PutEval(String* src,
9859 Context* context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009860 SharedFunctionInfo* value) {
9861 StringSharedKey key(src,
9862 context->closure()->shared(),
9863 value->strict_mode() ? kStrictMode : kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009864 Object* obj;
9865 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9866 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9867 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009868
9869 CompilationCacheTable* cache =
9870 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009871 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org381abbb2009-02-25 13:23:22 +00009872
lrn@chromium.org303ada72010-10-27 09:33:13 +00009873 Object* k;
9874 { MaybeObject* maybe_k = key.AsObject();
9875 if (!maybe_k->ToObject(&k)) return maybe_k;
9876 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00009877
9878 cache->set(EntryToIndex(entry), k);
9879 cache->set(EntryToIndex(entry) + 1, value);
9880 cache->ElementAdded();
9881 return cache;
9882}
9883
9884
lrn@chromium.org303ada72010-10-27 09:33:13 +00009885MaybeObject* CompilationCacheTable::PutRegExp(String* src,
9886 JSRegExp::Flags flags,
9887 FixedArray* value) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009888 RegExpKey key(src, flags);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009889 Object* obj;
9890 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9891 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9892 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009893
9894 CompilationCacheTable* cache =
9895 reinterpret_cast<CompilationCacheTable*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009896 int entry = cache->FindInsertionEntry(key.Hash());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00009897 // We store the value in the key slot, and compare the search key
9898 // to the stored value with a custon IsMatch function during lookups.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009899 cache->set(EntryToIndex(entry), value);
9900 cache->set(EntryToIndex(entry) + 1, value);
9901 cache->ElementAdded();
9902 return cache;
9903}
9904
9905
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009906void CompilationCacheTable::Remove(Object* value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009907 Object* null_value = GetHeap()->null_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009908 for (int entry = 0, size = Capacity(); entry < size; entry++) {
9909 int entry_index = EntryToIndex(entry);
9910 int value_index = entry_index + 1;
9911 if (get(value_index) == value) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009912 fast_set(this, entry_index, null_value);
9913 fast_set(this, value_index, null_value);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009914 ElementRemoved();
9915 }
9916 }
9917 return;
9918}
9919
9920
ager@chromium.org236ad962008-09-25 09:45:57 +00009921// SymbolsKey used for HashTable where key is array of symbols.
9922class SymbolsKey : public HashTableKey {
9923 public:
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009924 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
ager@chromium.org236ad962008-09-25 09:45:57 +00009925
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009926 bool IsMatch(Object* symbols) {
9927 FixedArray* o = FixedArray::cast(symbols);
ager@chromium.org236ad962008-09-25 09:45:57 +00009928 int len = symbols_->length();
9929 if (o->length() != len) return false;
9930 for (int i = 0; i < len; i++) {
9931 if (o->get(i) != symbols_->get(i)) return false;
9932 }
9933 return true;
9934 }
9935
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009936 uint32_t Hash() { return HashForObject(symbols_); }
ager@chromium.org236ad962008-09-25 09:45:57 +00009937
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009938 uint32_t HashForObject(Object* obj) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009939 FixedArray* symbols = FixedArray::cast(obj);
9940 int len = symbols->length();
9941 uint32_t hash = 0;
ager@chromium.org236ad962008-09-25 09:45:57 +00009942 for (int i = 0; i < len; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009943 hash ^= String::cast(symbols->get(i))->Hash();
ager@chromium.org236ad962008-09-25 09:45:57 +00009944 }
9945 return hash;
9946 }
9947
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009948 Object* AsObject() { return symbols_; }
ager@chromium.org236ad962008-09-25 09:45:57 +00009949
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009950 private:
ager@chromium.org236ad962008-09-25 09:45:57 +00009951 FixedArray* symbols_;
9952};
9953
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009954
ager@chromium.org236ad962008-09-25 09:45:57 +00009955Object* MapCache::Lookup(FixedArray* array) {
9956 SymbolsKey key(array);
9957 int entry = FindEntry(&key);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009958 if (entry == kNotFound) return GetHeap()->undefined_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009959 return get(EntryToIndex(entry) + 1);
ager@chromium.org236ad962008-09-25 09:45:57 +00009960}
9961
9962
lrn@chromium.org303ada72010-10-27 09:33:13 +00009963MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
ager@chromium.org236ad962008-09-25 09:45:57 +00009964 SymbolsKey key(array);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009965 Object* obj;
9966 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9967 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9968 }
ager@chromium.org236ad962008-09-25 09:45:57 +00009969
9970 MapCache* cache = reinterpret_cast<MapCache*>(obj);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009971 int entry = cache->FindInsertionEntry(key.Hash());
ager@chromium.org236ad962008-09-25 09:45:57 +00009972 cache->set(EntryToIndex(entry), array);
9973 cache->set(EntryToIndex(entry) + 1, value);
9974 cache->ElementAdded();
9975 return cache;
9976}
9977
9978
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009979template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009980MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
9981 Object* obj;
9982 { MaybeObject* maybe_obj =
9983 HashTable<Shape, Key>::Allocate(at_least_space_for);
9984 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009985 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009986 // Initialize the next enumeration index.
9987 Dictionary<Shape, Key>::cast(obj)->
9988 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 return obj;
9990}
9991
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009992
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009993template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +00009994MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 Heap* heap = Dictionary<Shape, Key>::GetHeap();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009996 int length = HashTable<Shape, Key>::NumberOfElements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009997
9998 // Allocate and initialize iteration order array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009999 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010000 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010001 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10002 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010003 FixedArray* iteration_order = FixedArray::cast(obj);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010004 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010005 iteration_order->set(i, Smi::FromInt(i));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010006 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010007
10008 // Allocate array with enumeration order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010009 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010010 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10011 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010012 FixedArray* enumeration_order = FixedArray::cast(obj);
10013
10014 // Fill the enumeration order array with property details.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010015 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010016 int pos = 0;
10017 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010018 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010019 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010020 }
10021 }
10022
10023 // Sort the arrays wrt. enumeration order.
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010024 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025
10026 // Overwrite the enumeration_order with the enumeration indices.
10027 for (int i = 0; i < length; i++) {
10028 int index = Smi::cast(iteration_order->get(i))->value();
10029 int enum_index = PropertyDetails::kInitialIndex + i;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010030 enumeration_order->set(index, Smi::FromInt(enum_index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010031 }
10032
10033 // Update the dictionary with new indices.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010034 capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035 pos = 0;
10036 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010037 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010038 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10039 PropertyDetails details = DetailsAt(i);
10040 PropertyDetails new_details =
10041 PropertyDetails(details.attributes(), details.type(), enum_index);
10042 DetailsAtPut(i, new_details);
10043 }
10044 }
10045
10046 // Set the next enumeration index.
10047 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10048 return this;
10049}
10050
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010051template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010052MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010053 // Check whether there are enough enumeration indices to add n elements.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010054 if (Shape::kIsEnumerable &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010055 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10056 // If not, we generate new indices for the properties.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010057 Object* result;
10058 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10059 if (!maybe_result->ToObject(&result)) return maybe_result;
10060 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010061 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010062 return HashTable<Shape, Key>::EnsureCapacity(n, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010063}
10064
10065
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010066void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010067 // Do nothing if the interval [from, to) is empty.
10068 if (from >= to) return;
10069
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010070 Heap* heap = GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010071 int removed_entries = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072 Object* sentinel = heap->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 int capacity = Capacity();
10074 for (int i = 0; i < capacity; i++) {
10075 Object* key = KeyAt(i);
10076 if (key->IsNumber()) {
10077 uint32_t number = static_cast<uint32_t>(key->Number());
10078 if (from <= number && number < to) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010079 SetEntry(i, sentinel, sentinel);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010080 removed_entries++;
10081 }
10082 }
10083 }
10084
10085 // Update the number of elements.
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +000010086 ElementsRemoved(removed_entries);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010087}
10088
10089
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010090template<typename Shape, typename Key>
10091Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
10092 JSObject::DeleteMode mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093 Heap* heap = Dictionary<Shape, Key>::GetHeap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010094 PropertyDetails details = DetailsAt(entry);
ager@chromium.orge2902be2009-06-08 12:21:35 +000010095 // Ignore attributes if forcing a deletion.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +000010096 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010097 return heap->false_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +000010098 }
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010099 SetEntry(entry, heap->null_value(), heap->null_value());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010100 HashTable<Shape, Key>::ElementRemoved();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010101 return heap->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010102}
10103
10104
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010105template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010106MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010107 int entry = this->FindEntry(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010108
10109 // If the entry is present set the value;
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010110 if (entry != Dictionary<Shape, Key>::kNotFound) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010111 ValueAtPut(entry, value);
10112 return this;
10113 }
10114
10115 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010116 Object* obj;
10117 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10118 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10119 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010120
lrn@chromium.org303ada72010-10-27 09:33:13 +000010121 Object* k;
10122 { MaybeObject* maybe_k = Shape::AsObject(key);
10123 if (!maybe_k->ToObject(&k)) return maybe_k;
10124 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010125 PropertyDetails details = PropertyDetails(NONE, NORMAL);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010126 return Dictionary<Shape, Key>::cast(obj)->
10127 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010128}
10129
10130
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010131template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010132MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10133 Object* value,
10134 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010135 // Valdate key is absent.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010136 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137 // Check whether the dictionary should be extended.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010138 Object* obj;
10139 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10140 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10141 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010142 return Dictionary<Shape, Key>::cast(obj)->
10143 AddEntry(key, value, details, Shape::Hash(key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144}
10145
10146
10147// Add a key, value pair to the dictionary.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010148template<typename Shape, typename Key>
lrn@chromium.org303ada72010-10-27 09:33:13 +000010149MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
10150 Object* value,
10151 PropertyDetails details,
10152 uint32_t hash) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010153 // Compute the key object.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010154 Object* k;
10155 { MaybeObject* maybe_k = Shape::AsObject(key);
10156 if (!maybe_k->ToObject(&k)) return maybe_k;
10157 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010158
10159 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160 // Insert element at empty or deleted entry
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010161 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162 // Assign an enumeration index to the property and update
10163 // SetNextEnumerationIndex.
10164 int index = NextEnumerationIndex();
10165 details = PropertyDetails(details.attributes(), details.type(), index);
10166 SetNextEnumerationIndex(index + 1);
10167 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010168 SetEntry(entry, k, value, details);
10169 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
10170 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
10171 HashTable<Shape, Key>::ElementAdded();
10172 return this;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010173}
10174
10175
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010176void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010177 // If the dictionary requires slow elements an element has already
10178 // been added at a high index.
10179 if (requires_slow_elements()) return;
10180 // Check if this index is high enough that we should require slow
10181 // elements.
10182 if (key > kRequiresSlowElementsLimit) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010183 set_requires_slow_elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010184 return;
10185 }
10186 // Update max key value.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000010187 Object* max_index_object = get(kMaxNumberKeyIndex);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 if (!max_index_object->IsSmi() || max_number_key() < key) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010189 FixedArray::set(kMaxNumberKeyIndex,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010190 Smi::FromInt(key << kRequiresSlowElementsTagSize));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010191 }
10192}
10193
10194
lrn@chromium.org303ada72010-10-27 09:33:13 +000010195MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
10196 Object* value,
10197 PropertyDetails details) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010198 UpdateMaxNumberKey(key);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010199 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010200 return Add(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010201}
10202
10203
lrn@chromium.org303ada72010-10-27 09:33:13 +000010204MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205 UpdateMaxNumberKey(key);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010206 return AtPut(key, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010207}
10208
10209
lrn@chromium.org303ada72010-10-27 09:33:13 +000010210MaybeObject* NumberDictionary::Set(uint32_t key,
10211 Object* value,
10212 PropertyDetails details) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010213 int entry = FindEntry(key);
10214 if (entry == kNotFound) return AddNumberEntry(key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010215 // Preserve enumeration index.
10216 details = PropertyDetails(details.attributes(),
10217 details.type(),
10218 DetailsAt(entry).index());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010219 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
10220 Object* object_key;
10221 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000010222 SetEntry(entry, object_key, value, details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223 return this;
10224}
10225
10226
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010227
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010228template<typename Shape, typename Key>
10229int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
10230 PropertyAttributes filter) {
10231 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010232 int result = 0;
10233 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010234 Object* k = HashTable<Shape, Key>::KeyAt(i);
10235 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010236 PropertyDetails details = DetailsAt(i);
10237 if (details.IsDeleted()) continue;
10238 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010239 if ((attr & filter) == 0) result++;
10240 }
10241 }
10242 return result;
10243}
10244
10245
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010246template<typename Shape, typename Key>
10247int Dictionary<Shape, Key>::NumberOfEnumElements() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010248 return NumberOfElementsFilterAttributes(
10249 static_cast<PropertyAttributes>(DONT_ENUM));
10250}
10251
10252
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010253template<typename Shape, typename Key>
10254void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
10255 PropertyAttributes filter) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010256 ASSERT(storage->length() >= NumberOfEnumElements());
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010257 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 int index = 0;
10259 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010260 Object* k = HashTable<Shape, Key>::KeyAt(i);
10261 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010262 PropertyDetails details = DetailsAt(i);
10263 if (details.IsDeleted()) continue;
10264 PropertyAttributes attr = details.attributes();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 if ((attr & filter) == 0) storage->set(index++, k);
10266 }
10267 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010268 storage->SortPairs(storage, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010269 ASSERT(storage->length() >= index);
10270}
10271
10272
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010273void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
10274 FixedArray* sort_array) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010275 ASSERT(storage->length() >= NumberOfEnumElements());
10276 int capacity = Capacity();
10277 int index = 0;
10278 for (int i = 0; i < capacity; i++) {
10279 Object* k = KeyAt(i);
10280 if (IsKey(k)) {
10281 PropertyDetails details = DetailsAt(i);
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010282 if (details.IsDeleted() || details.IsDontEnum()) continue;
10283 storage->set(index, k);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010284 sort_array->set(index, Smi::FromInt(details.index()));
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010285 index++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010286 }
10287 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010288 storage->SortPairs(sort_array, sort_array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010289 ASSERT(storage->length() >= index);
10290}
10291
10292
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010293template<typename Shape, typename Key>
10294void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010295 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
10296 static_cast<PropertyAttributes>(NONE)));
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010297 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 int index = 0;
10299 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010300 Object* k = HashTable<Shape, Key>::KeyAt(i);
10301 if (HashTable<Shape, Key>::IsKey(k)) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010302 PropertyDetails details = DetailsAt(i);
10303 if (details.IsDeleted()) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304 storage->set(index++, k);
10305 }
10306 }
10307 ASSERT(storage->length() >= index);
10308}
10309
10310
10311// Backwards lookup (slow).
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010312template<typename Shape, typename Key>
10313Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
10314 int capacity = HashTable<Shape, Key>::Capacity();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315 for (int i = 0; i < capacity; i++) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010316 Object* k = HashTable<Shape, Key>::KeyAt(i);
10317 if (Dictionary<Shape, Key>::IsKey(k)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010318 Object* e = ValueAt(i);
10319 if (e->IsJSGlobalPropertyCell()) {
10320 e = JSGlobalPropertyCell::cast(e)->value();
10321 }
10322 if (e == value) return k;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 }
10324 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010325 Heap* heap = Dictionary<Shape, Key>::GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327}
10328
10329
lrn@chromium.org303ada72010-10-27 09:33:13 +000010330MaybeObject* StringDictionary::TransformPropertiesToFastFor(
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010331 JSObject* obj, int unused_property_fields) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 // Make sure we preserve dictionary representation if there are too many
10333 // descriptors.
10334 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
10335
10336 // Figure out if it is necessary to generate new enumeration indices.
10337 int max_enumeration_index =
10338 NextEnumerationIndex() +
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010339 (DescriptorArray::kMaxNumberOfDescriptors -
10340 NumberOfElements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010341 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000010342 Object* result;
10343 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10344 if (!maybe_result->ToObject(&result)) return maybe_result;
10345 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010346 }
10347
10348 int instance_descriptor_length = 0;
10349 int number_of_fields = 0;
10350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010351 Heap* heap = GetHeap();
10352
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353 // Compute the length of the instance descriptor.
10354 int capacity = Capacity();
10355 for (int i = 0; i < capacity; i++) {
10356 Object* k = KeyAt(i);
10357 if (IsKey(k)) {
10358 Object* value = ValueAt(i);
10359 PropertyType type = DetailsAt(i).type();
10360 ASSERT(type != FIELD);
10361 instance_descriptor_length++;
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000010362 if (type == NORMAL &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010363 (!value->IsJSFunction() || heap->InNewSpace(value))) {
sgjesse@chromium.org846fb742009-12-18 08:56:33 +000010364 number_of_fields += 1;
10365 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010366 }
10367 }
10368
10369 // Allocate the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010370 Object* descriptors_unchecked;
10371 { MaybeObject* maybe_descriptors_unchecked =
10372 DescriptorArray::Allocate(instance_descriptor_length);
10373 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
10374 return maybe_descriptors_unchecked;
10375 }
10376 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010377 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010378
ager@chromium.org32912102009-01-16 10:38:43 +000010379 int inobject_props = obj->map()->inobject_properties();
10380 int number_of_allocated_fields =
10381 number_of_fields + unused_property_fields - inobject_props;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +000010382 if (number_of_allocated_fields < 0) {
10383 // There is enough inobject space for all fields (including unused).
10384 number_of_allocated_fields = 0;
10385 unused_property_fields = inobject_props - number_of_fields;
10386 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387
10388 // Allocate the fixed array for the fields.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010389 Object* fields;
10390 { MaybeObject* maybe_fields =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010391 heap->AllocateFixedArray(number_of_allocated_fields);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010392 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
10393 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010394
10395 // Fill in the instance descriptor and the fields.
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010396 int next_descriptor = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010397 int current_offset = 0;
10398 for (int i = 0; i < capacity; i++) {
10399 Object* k = KeyAt(i);
10400 if (IsKey(k)) {
10401 Object* value = ValueAt(i);
10402 // Ensure the key is a symbol before writing into the instance descriptor.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010403 Object* key;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010404 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010405 if (!maybe_key->ToObject(&key)) return maybe_key;
10406 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 PropertyDetails details = DetailsAt(i);
10408 PropertyType type = details.type();
ager@chromium.org32912102009-01-16 10:38:43 +000010409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010410 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411 ConstantFunctionDescriptor d(String::cast(key),
10412 JSFunction::cast(value),
10413 details.attributes(),
10414 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010415 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010416 } else if (type == NORMAL) {
ager@chromium.org32912102009-01-16 10:38:43 +000010417 if (current_offset < inobject_props) {
10418 obj->InObjectPropertyAtPut(current_offset,
10419 value,
10420 UPDATE_WRITE_BARRIER);
10421 } else {
10422 int offset = current_offset - inobject_props;
10423 FixedArray::cast(fields)->set(offset, value);
10424 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010425 FieldDescriptor d(String::cast(key),
10426 current_offset++,
10427 details.attributes(),
10428 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010429 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010430 } else if (type == CALLBACKS) {
10431 CallbacksDescriptor d(String::cast(key),
10432 value,
10433 details.attributes(),
10434 details.index());
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +000010435 descriptors->Set(next_descriptor++, &d);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010436 } else {
10437 UNREACHABLE();
10438 }
10439 }
10440 }
10441 ASSERT(current_offset == number_of_fields);
10442
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010443 descriptors->Sort();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010444 // Allocate new map.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010445 Object* new_map;
10446 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
10447 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10448 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449
10450 // Transform the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010451 obj->set_map(Map::cast(new_map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010452 obj->map()->set_instance_descriptors(descriptors);
10453 obj->map()->set_unused_property_fields(unused_property_fields);
10454
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455 obj->set_properties(FixedArray::cast(fields));
10456 ASSERT(obj->IsJSObject());
10457
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010458 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
ager@chromium.org32912102009-01-16 10:38:43 +000010459 // Check that it really works.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010460 ASSERT(obj->HasFastProperties());
ager@chromium.org32912102009-01-16 10:38:43 +000010461
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010462 return obj;
10463}
10464
10465
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010466#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467// Check if there is a break point at this code position.
10468bool DebugInfo::HasBreakPoint(int code_position) {
10469 // Get the break point info object for this code position.
10470 Object* break_point_info = GetBreakPointInfo(code_position);
10471
10472 // If there is no break point info object or no break points in the break
10473 // point info object there is no break point at this code position.
10474 if (break_point_info->IsUndefined()) return false;
10475 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
10476}
10477
10478
10479// Get the break point info object for this code position.
10480Object* DebugInfo::GetBreakPointInfo(int code_position) {
10481 // Find the index of the break point info object for this code position.
10482 int index = GetBreakPointInfoIndex(code_position);
10483
10484 // Return the break point info object if any.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010485 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010486 return BreakPointInfo::cast(break_points()->get(index));
10487}
10488
10489
10490// Clear a break point at the specified code position.
10491void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
10492 int code_position,
10493 Handle<Object> break_point_object) {
10494 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10495 if (break_point_info->IsUndefined()) return;
10496 BreakPointInfo::ClearBreakPoint(
10497 Handle<BreakPointInfo>::cast(break_point_info),
10498 break_point_object);
10499}
10500
10501
10502void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
10503 int code_position,
10504 int source_position,
10505 int statement_position,
10506 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010508 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10509 if (!break_point_info->IsUndefined()) {
10510 BreakPointInfo::SetBreakPoint(
10511 Handle<BreakPointInfo>::cast(break_point_info),
10512 break_point_object);
10513 return;
10514 }
10515
10516 // Adding a new break point for a code position which did not have any
10517 // break points before. Try to find a free slot.
10518 int index = kNoBreakPointInfo;
10519 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10520 if (debug_info->break_points()->get(i)->IsUndefined()) {
10521 index = i;
10522 break;
10523 }
10524 }
10525 if (index == kNoBreakPointInfo) {
10526 // No free slot - extend break point info array.
10527 Handle<FixedArray> old_break_points =
10528 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010529 Handle<FixedArray> new_break_points =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010530 isolate->factory()->NewFixedArray(
10531 old_break_points->length() +
10532 Debug::kEstimatedNofBreakPointsInFunction);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010533
10534 debug_info->set_break_points(*new_break_points);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010535 for (int i = 0; i < old_break_points->length(); i++) {
10536 new_break_points->set(i, old_break_points->get(i));
10537 }
10538 index = old_break_points->length();
10539 }
10540 ASSERT(index != kNoBreakPointInfo);
10541
10542 // Allocate new BreakPointInfo object and set the break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010543 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
10544 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010545 new_break_point_info->set_code_position(Smi::FromInt(code_position));
10546 new_break_point_info->set_source_position(Smi::FromInt(source_position));
10547 new_break_point_info->
10548 set_statement_position(Smi::FromInt(statement_position));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010549 new_break_point_info->set_break_point_objects(
10550 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
10552 debug_info->break_points()->set(index, *new_break_point_info);
10553}
10554
10555
10556// Get the break point objects for a code position.
10557Object* DebugInfo::GetBreakPointObjects(int code_position) {
10558 Object* break_point_info = GetBreakPointInfo(code_position);
10559 if (break_point_info->IsUndefined()) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010560 return GetHeap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561 }
10562 return BreakPointInfo::cast(break_point_info)->break_point_objects();
10563}
10564
10565
10566// Get the total number of break points.
10567int DebugInfo::GetBreakPointCount() {
10568 if (break_points()->IsUndefined()) return 0;
10569 int count = 0;
10570 for (int i = 0; i < break_points()->length(); i++) {
10571 if (!break_points()->get(i)->IsUndefined()) {
10572 BreakPointInfo* break_point_info =
10573 BreakPointInfo::cast(break_points()->get(i));
10574 count += break_point_info->GetBreakPointCount();
10575 }
10576 }
10577 return count;
10578}
10579
10580
10581Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
10582 Handle<Object> break_point_object) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010583 Heap* heap = debug_info->GetHeap();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010585 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10586 if (!debug_info->break_points()->get(i)->IsUndefined()) {
10587 Handle<BreakPointInfo> break_point_info =
10588 Handle<BreakPointInfo>(BreakPointInfo::cast(
10589 debug_info->break_points()->get(i)));
10590 if (BreakPointInfo::HasBreakPointObject(break_point_info,
10591 break_point_object)) {
10592 return *break_point_info;
10593 }
10594 }
10595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010596 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010597}
10598
10599
10600// Find the index of the break point info object for the specified code
10601// position.
10602int DebugInfo::GetBreakPointInfoIndex(int code_position) {
10603 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
10604 for (int i = 0; i < break_points()->length(); i++) {
10605 if (!break_points()->get(i)->IsUndefined()) {
10606 BreakPointInfo* break_point_info =
10607 BreakPointInfo::cast(break_points()->get(i));
10608 if (break_point_info->code_position()->value() == code_position) {
10609 return i;
10610 }
10611 }
10612 }
10613 return kNoBreakPointInfo;
10614}
10615
10616
10617// Remove the specified break point object.
10618void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
10619 Handle<Object> break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010620 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 // If there are no break points just ignore.
10622 if (break_point_info->break_point_objects()->IsUndefined()) return;
10623 // If there is a single break point clear it if it is the same.
10624 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10625 if (break_point_info->break_point_objects() == *break_point_object) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010626 break_point_info->set_break_point_objects(
10627 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010628 }
10629 return;
10630 }
10631 // If there are multiple break points shrink the array
10632 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
10633 Handle<FixedArray> old_array =
10634 Handle<FixedArray>(
10635 FixedArray::cast(break_point_info->break_point_objects()));
10636 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010637 isolate->factory()->NewFixedArray(old_array->length() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638 int found_count = 0;
10639 for (int i = 0; i < old_array->length(); i++) {
10640 if (old_array->get(i) == *break_point_object) {
10641 ASSERT(found_count == 0);
10642 found_count++;
10643 } else {
10644 new_array->set(i - found_count, old_array->get(i));
10645 }
10646 }
10647 // If the break point was found in the list change it.
10648 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
10649}
10650
10651
10652// Add the specified break point object.
10653void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
10654 Handle<Object> break_point_object) {
10655 // If there was no break point objects before just set it.
10656 if (break_point_info->break_point_objects()->IsUndefined()) {
10657 break_point_info->set_break_point_objects(*break_point_object);
10658 return;
10659 }
10660 // If the break point object is the same as before just ignore.
10661 if (break_point_info->break_point_objects() == *break_point_object) return;
10662 // If there was one break point object before replace with array.
10663 if (!break_point_info->break_point_objects()->IsFixedArray()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010664 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665 array->set(0, break_point_info->break_point_objects());
10666 array->set(1, *break_point_object);
10667 break_point_info->set_break_point_objects(*array);
10668 return;
10669 }
10670 // If there was more than one break point before extend array.
10671 Handle<FixedArray> old_array =
10672 Handle<FixedArray>(
10673 FixedArray::cast(break_point_info->break_point_objects()));
10674 Handle<FixedArray> new_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010675 FACTORY->NewFixedArray(old_array->length() + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010676 for (int i = 0; i < old_array->length(); i++) {
10677 // If the break point was there before just ignore.
10678 if (old_array->get(i) == *break_point_object) return;
10679 new_array->set(i, old_array->get(i));
10680 }
10681 // Add the new break point.
10682 new_array->set(old_array->length(), *break_point_object);
10683 break_point_info->set_break_point_objects(*new_array);
10684}
10685
10686
10687bool BreakPointInfo::HasBreakPointObject(
10688 Handle<BreakPointInfo> break_point_info,
10689 Handle<Object> break_point_object) {
10690 // No break point.
10691 if (break_point_info->break_point_objects()->IsUndefined()) return false;
10692 // Single beak point.
10693 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10694 return break_point_info->break_point_objects() == *break_point_object;
10695 }
10696 // Multiple break points.
10697 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
10698 for (int i = 0; i < array->length(); i++) {
10699 if (array->get(i) == *break_point_object) {
10700 return true;
10701 }
10702 }
10703 return false;
10704}
10705
10706
10707// Get the number of break points.
10708int BreakPointInfo::GetBreakPointCount() {
10709 // No break point.
10710 if (break_point_objects()->IsUndefined()) return 0;
10711 // Single beak point.
10712 if (!break_point_objects()->IsFixedArray()) return 1;
10713 // Multiple break points.
10714 return FixedArray::cast(break_point_objects())->length();
10715}
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010716#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010717
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719} } // namespace v8::internal