blob: a20548c64f9a8e680e48dc75f4a5580c48a938e4 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +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"
31#include "arguments.h"
32#include "bootstrapper.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "execution.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037#include "full-codegen.h"
38#include "hydrogen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "objects-inl.h"
Iain Merrick75681382010-08-19 15:07:18 +010040#include "objects-visiting.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000041#include "macro-assembler.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010042#include "safepoint-table.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080043#include "scanner-base.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "scopeinfo.h"
45#include "string-stream.h"
Steve Blockd0582a62009-12-15 09:54:21 +000046#include "utils.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010047#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000048
49#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010050#include "disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000051#include "disassembler.h"
52#endif
53
Steve Blocka7e24c12009-10-30 11:49:00 +000054namespace v8 {
55namespace internal {
56
57// Getters and setters are stored in a fixed array property. These are
58// constants for their indices.
59const int kGetterIndex = 0;
60const int kSetterIndex = 1;
61
62
John Reck59135872010-11-02 12:39:01 -070063MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
64 Object* value) {
65 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010066 { MaybeObject* maybe_result =
67 constructor->GetHeap()->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -070068 if (!maybe_result->ToObject(&result)) return maybe_result;
69 }
Steve Blocka7e24c12009-10-30 11:49:00 +000070 JSValue::cast(result)->set_value(value);
71 return result;
72}
73
74
John Reck59135872010-11-02 12:39:01 -070075MaybeObject* Object::ToObject(Context* global_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +000076 if (IsNumber()) {
77 return CreateJSValue(global_context->number_function(), this);
78 } else if (IsBoolean()) {
79 return CreateJSValue(global_context->boolean_function(), this);
80 } else if (IsString()) {
81 return CreateJSValue(global_context->string_function(), this);
82 }
83 ASSERT(IsJSObject());
84 return this;
85}
86
87
John Reck59135872010-11-02 12:39:01 -070088MaybeObject* Object::ToObject() {
Steve Blocka7e24c12009-10-30 11:49:00 +000089 if (IsJSObject()) {
90 return this;
91 } else if (IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010092 Isolate* isolate = Isolate::Current();
93 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000094 return CreateJSValue(global_context->number_function(), this);
95 } else if (IsBoolean()) {
Steve Block44f0eee2011-05-26 01:26:41 +010096 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
97 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000098 return CreateJSValue(global_context->boolean_function(), this);
99 } else if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100100 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
101 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000102 return CreateJSValue(global_context->string_function(), this);
103 }
104
105 // Throw a type error.
106 return Failure::InternalError();
107}
108
109
110Object* Object::ToBoolean() {
Steve Block44f0eee2011-05-26 01:26:41 +0100111 if (IsTrue()) return this;
112 if (IsFalse()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 if (IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100114 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000115 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100116 HeapObject* heap_object = HeapObject::cast(this);
117 if (heap_object->IsUndefined() || heap_object->IsNull()) {
118 return heap_object->GetHeap()->false_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100119 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000120 // Undetectable object is false
Ben Murdoch8b112d22011-06-08 16:22:53 +0100121 if (heap_object->IsUndetectableObject()) {
122 return heap_object->GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000123 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100124 if (heap_object->IsString()) {
125 return heap_object->GetHeap()->ToBoolean(
Steve Block44f0eee2011-05-26 01:26:41 +0100126 String::cast(this)->length() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100128 if (heap_object->IsHeapNumber()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 return HeapNumber::cast(this)->HeapNumberToBoolean();
130 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100131 return heap_object->GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000132}
133
134
135void Object::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000136 Object* holder = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100137 if (IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100138 Heap* heap = Isolate::Current()->heap();
139 Context* global_context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 holder = global_context->number_function()->instance_prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100141 } else {
142 HeapObject* heap_object = HeapObject::cast(this);
143 if (heap_object->IsJSObject()) {
144 return JSObject::cast(this)->Lookup(name, result);
145 }
146 Heap* heap = heap_object->GetHeap();
147 if (heap_object->IsString()) {
148 Context* global_context = heap->isolate()->context()->global_context();
149 holder = global_context->string_function()->instance_prototype();
150 } else if (heap_object->IsHeapNumber()) {
151 Context* global_context = heap->isolate()->context()->global_context();
152 holder = global_context->number_function()->instance_prototype();
153 } else if (heap_object->IsBoolean()) {
154 Context* global_context = heap->isolate()->context()->global_context();
155 holder = global_context->boolean_function()->instance_prototype();
156 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000157 }
158 ASSERT(holder != NULL); // Cannot handle null or undefined.
159 JSObject::cast(holder)->Lookup(name, result);
160}
161
162
John Reck59135872010-11-02 12:39:01 -0700163MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
164 String* name,
165 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 LookupResult result;
167 Lookup(name, &result);
John Reck59135872010-11-02 12:39:01 -0700168 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000169 ASSERT(*attributes <= ABSENT);
170 return value;
171}
172
173
John Reck59135872010-11-02 12:39:01 -0700174MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
175 Object* structure,
176 String* name,
177 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +0100178 Isolate* isolate = name->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 // To accommodate both the old and the new api we switch on the
180 // data structure used to store the callbacks. Eventually proxy
181 // callbacks should be phased out.
182 if (structure->IsProxy()) {
183 AccessorDescriptor* callback =
184 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
John Reck59135872010-11-02 12:39:01 -0700185 MaybeObject* value = (callback->getter)(receiver, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +0100186 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000187 return value;
188 }
189
190 // api style callbacks.
191 if (structure->IsAccessorInfo()) {
192 AccessorInfo* data = AccessorInfo::cast(structure);
193 Object* fun_obj = data->getter();
194 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
195 HandleScope scope;
196 JSObject* self = JSObject::cast(receiver);
197 JSObject* holder_handle = JSObject::cast(holder);
198 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100199 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
200 CustomArguments args(isolate, data->data(), self, holder_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +0000201 v8::AccessorInfo info(args.end());
202 v8::Handle<v8::Value> result;
203 {
204 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +0100205 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000206 result = call_fun(v8::Utils::ToLocal(key), info);
207 }
Steve Block44f0eee2011-05-26 01:26:41 +0100208 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
209 if (result.IsEmpty()) {
210 return isolate->heap()->undefined_value();
211 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 return *v8::Utils::OpenHandle(*result);
213 }
214
215 // __defineGetter__ callback
216 if (structure->IsFixedArray()) {
217 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
218 if (getter->IsJSFunction()) {
219 return Object::GetPropertyWithDefinedGetter(receiver,
220 JSFunction::cast(getter));
221 }
222 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +0100223 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 }
225
226 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +0100227 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000228}
229
230
John Reck59135872010-11-02 12:39:01 -0700231MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
232 JSFunction* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 HandleScope scope;
234 Handle<JSFunction> fun(JSFunction::cast(getter));
235 Handle<Object> self(receiver);
236#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100237 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 // Handle stepping into a getter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +0100239 if (debug->StepInActive()) {
240 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000241 }
242#endif
243 bool has_pending_exception;
244 Handle<Object> result =
245 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
246 // Check for pending exception and return the result.
247 if (has_pending_exception) return Failure::Exception();
248 return *result;
249}
250
251
252// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700253MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000254 Object* receiver,
255 LookupResult* result,
256 String* name,
257 PropertyAttributes* attributes) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000258 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 switch (result->type()) {
260 case CALLBACKS: {
261 // Only allow API accessors.
262 Object* obj = result->GetCallbackObject();
263 if (obj->IsAccessorInfo()) {
264 AccessorInfo* info = AccessorInfo::cast(obj);
265 if (info->all_can_read()) {
266 *attributes = result->GetAttributes();
267 return GetPropertyWithCallback(receiver,
268 result->GetCallbackObject(),
269 name,
270 result->holder());
271 }
272 }
273 break;
274 }
275 case NORMAL:
276 case FIELD:
277 case CONSTANT_FUNCTION: {
278 // Search ALL_CAN_READ accessors in prototype chain.
279 LookupResult r;
280 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000281 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000282 return GetPropertyWithFailedAccessCheck(receiver,
283 &r,
284 name,
285 attributes);
286 }
287 break;
288 }
289 case INTERCEPTOR: {
290 // If the object has an interceptor, try real named properties.
291 // No access check in GetPropertyAttributeWithInterceptor.
292 LookupResult r;
293 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000294 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 return GetPropertyWithFailedAccessCheck(receiver,
296 &r,
297 name,
298 attributes);
299 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000300 break;
301 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000302 default:
303 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000304 }
305 }
306
307 // No accessible property found.
308 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100309 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100310 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
311 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000312}
313
314
315PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
316 Object* receiver,
317 LookupResult* result,
318 String* name,
319 bool continue_search) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000320 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 switch (result->type()) {
322 case CALLBACKS: {
323 // Only allow API accessors.
324 Object* obj = result->GetCallbackObject();
325 if (obj->IsAccessorInfo()) {
326 AccessorInfo* info = AccessorInfo::cast(obj);
327 if (info->all_can_read()) {
328 return result->GetAttributes();
329 }
330 }
331 break;
332 }
333
334 case NORMAL:
335 case FIELD:
336 case CONSTANT_FUNCTION: {
337 if (!continue_search) break;
338 // Search ALL_CAN_READ accessors in prototype chain.
339 LookupResult r;
340 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000341 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 return GetPropertyAttributeWithFailedAccessCheck(receiver,
343 &r,
344 name,
345 continue_search);
346 }
347 break;
348 }
349
350 case INTERCEPTOR: {
351 // If the object has an interceptor, try real named properties.
352 // No access check in GetPropertyAttributeWithInterceptor.
353 LookupResult r;
354 if (continue_search) {
355 result->holder()->LookupRealNamedProperty(name, &r);
356 } else {
357 result->holder()->LocalLookupRealNamedProperty(name, &r);
358 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000359 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000360 return GetPropertyAttributeWithFailedAccessCheck(receiver,
361 &r,
362 name,
363 continue_search);
364 }
365 break;
366 }
367
Andrei Popescu402d9372010-02-26 13:31:12 +0000368 default:
369 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 }
371 }
372
Ben Murdoch8b112d22011-06-08 16:22:53 +0100373 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000374 return ABSENT;
375}
376
377
Steve Blocka7e24c12009-10-30 11:49:00 +0000378Object* JSObject::GetNormalizedProperty(LookupResult* result) {
379 ASSERT(!HasFastProperties());
380 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
381 if (IsGlobalObject()) {
382 value = JSGlobalPropertyCell::cast(value)->value();
383 }
384 ASSERT(!value->IsJSGlobalPropertyCell());
385 return value;
386}
387
388
389Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
390 ASSERT(!HasFastProperties());
391 if (IsGlobalObject()) {
392 JSGlobalPropertyCell* cell =
393 JSGlobalPropertyCell::cast(
394 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
395 cell->set_value(value);
396 } else {
397 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
398 }
399 return value;
400}
401
402
John Reck59135872010-11-02 12:39:01 -0700403MaybeObject* JSObject::SetNormalizedProperty(String* name,
404 Object* value,
405 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 ASSERT(!HasFastProperties());
407 int entry = property_dictionary()->FindEntry(name);
408 if (entry == StringDictionary::kNotFound) {
409 Object* store_value = value;
410 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100411 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100412 MaybeObject* maybe_store_value =
413 heap->AllocateJSGlobalPropertyCell(value);
414 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000415 }
John Reck59135872010-11-02 12:39:01 -0700416 Object* dict;
417 { MaybeObject* maybe_dict =
418 property_dictionary()->Add(name, store_value, details);
419 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
420 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 set_properties(StringDictionary::cast(dict));
422 return value;
423 }
424 // Preserve enumeration index.
425 details = PropertyDetails(details.attributes(),
426 details.type(),
427 property_dictionary()->DetailsAt(entry).index());
428 if (IsGlobalObject()) {
429 JSGlobalPropertyCell* cell =
430 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
431 cell->set_value(value);
432 // Please note we have to update the property details.
433 property_dictionary()->DetailsAtPut(entry, details);
434 } else {
435 property_dictionary()->SetEntry(entry, name, value, details);
436 }
437 return value;
438}
439
440
John Reck59135872010-11-02 12:39:01 -0700441MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000442 ASSERT(!HasFastProperties());
443 StringDictionary* dictionary = property_dictionary();
444 int entry = dictionary->FindEntry(name);
445 if (entry != StringDictionary::kNotFound) {
446 // If we have a global object set the cell to the hole.
447 if (IsGlobalObject()) {
448 PropertyDetails details = dictionary->DetailsAt(entry);
449 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100450 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000451 // When forced to delete global properties, we have to make a
452 // map change to invalidate any ICs that think they can load
453 // from the DontDelete cell without checking if it contains
454 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700455 Object* new_map;
456 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
457 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
458 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000459 set_map(Map::cast(new_map));
460 }
461 JSGlobalPropertyCell* cell =
462 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100463 cell->set_value(cell->heap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000464 dictionary->DetailsAtPut(entry, details.AsDeleted());
465 } else {
466 return dictionary->DeleteProperty(entry, mode);
467 }
468 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100469 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000470}
471
472
473bool JSObject::IsDirty() {
474 Object* cons_obj = map()->constructor();
475 if (!cons_obj->IsJSFunction())
476 return true;
477 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100478 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000479 return true;
480 // If the object is fully fast case and has the same map it was
481 // created with then no changes can have been made to it.
482 return map() != fun->initial_map()
483 || !HasFastElements()
484 || !HasFastProperties();
485}
486
487
John Reck59135872010-11-02 12:39:01 -0700488MaybeObject* Object::GetProperty(Object* receiver,
489 LookupResult* result,
490 String* name,
491 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000492 // Make sure that the top context does not change when doing
493 // callbacks or interceptor calls.
494 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100495 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000496
497 // Traverse the prototype chain from the current object (this) to
498 // the holder and check for access rights. This avoid traversing the
499 // objects more than once in case of interceptors, because the
500 // holder will always be the interceptor holder and the search may
501 // only continue with a current object just after the interceptor
502 // holder in the prototype chain.
Steve Block44f0eee2011-05-26 01:26:41 +0100503 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000504 for (Object* current = this; true; current = current->GetPrototype()) {
505 if (current->IsAccessCheckNeeded()) {
506 // Check if we're allowed to read from the current object. Note
507 // that even though we may not actually end up loading the named
508 // property from the current object, we still check that we have
509 // access to it.
510 JSObject* checked = JSObject::cast(current);
Steve Block44f0eee2011-05-26 01:26:41 +0100511 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 return checked->GetPropertyWithFailedAccessCheck(receiver,
513 result,
514 name,
515 attributes);
516 }
517 }
518 // Stop traversing the chain once we reach the last object in the
519 // chain; either the holder of the result or null in case of an
520 // absent property.
521 if (current == last) break;
522 }
523
524 if (!result->IsProperty()) {
525 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100526 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 }
528 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000529 Object* value;
530 JSObject* holder = result->holder();
531 switch (result->type()) {
532 case NORMAL:
533 value = holder->GetNormalizedProperty(result);
534 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100535 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000536 case FIELD:
537 value = holder->FastPropertyAt(result->GetFieldIndex());
538 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100539 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000540 case CONSTANT_FUNCTION:
541 return result->GetConstantFunction();
542 case CALLBACKS:
543 return GetPropertyWithCallback(receiver,
544 result->GetCallbackObject(),
545 name,
546 holder);
547 case INTERCEPTOR: {
548 JSObject* recvr = JSObject::cast(receiver);
549 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
550 }
551 default:
552 UNREACHABLE();
553 return NULL;
554 }
555}
556
557
John Reck59135872010-11-02 12:39:01 -0700558MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100559 Object* holder = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100560 if (IsSmi()) {
561 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100562 holder = global_context->number_function()->instance_prototype();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100563 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100564 HeapObject* heap_object = HeapObject::cast(this);
565
566 if (heap_object->IsJSObject()) {
567 return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
568 }
569 Heap* heap = heap_object->GetHeap();
570 Isolate* isolate = heap->isolate();
571
572 Context* global_context = isolate->context()->global_context();
573 if (heap_object->IsString()) {
574 holder = global_context->string_function()->instance_prototype();
575 } else if (heap_object->IsHeapNumber()) {
576 holder = global_context->number_function()->instance_prototype();
577 } else if (heap_object->IsBoolean()) {
578 holder = global_context->boolean_function()->instance_prototype();
579 } else {
580 // Undefined and null have no indexed properties.
581 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
582 return heap->undefined_value();
583 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100584 }
585
586 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000587}
588
589
590Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100591 if (IsSmi()) {
592 Heap* heap = Isolate::Current()->heap();
593 Context* context = heap->isolate()->context()->global_context();
594 return context->number_function()->instance_prototype();
595 }
596
597 HeapObject* heap_object = HeapObject::cast(this);
598
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 // The object is either a number, a string, a boolean, or a real JS object.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100600 if (heap_object->IsJSObject()) {
601 return JSObject::cast(this)->map()->prototype();
602 }
603 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100604 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000605
Ben Murdoch8b112d22011-06-08 16:22:53 +0100606 if (heap_object->IsHeapNumber()) {
607 return context->number_function()->instance_prototype();
608 }
609 if (heap_object->IsString()) {
610 return context->string_function()->instance_prototype();
611 }
612 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 return context->boolean_function()->instance_prototype();
614 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100615 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000616 }
617}
618
619
Ben Murdochb0fe1622011-05-05 13:52:32 +0100620void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 HeapStringAllocator allocator;
622 StringStream accumulator(&allocator);
623 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100624 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000625}
626
627
628void Object::ShortPrint(StringStream* accumulator) {
629 if (IsSmi()) {
630 Smi::cast(this)->SmiPrint(accumulator);
631 } else if (IsFailure()) {
632 Failure::cast(this)->FailurePrint(accumulator);
633 } else {
634 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
635 }
636}
637
638
Ben Murdochb0fe1622011-05-05 13:52:32 +0100639void Smi::SmiPrint(FILE* out) {
640 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000641}
642
643
644void Smi::SmiPrint(StringStream* accumulator) {
645 accumulator->Add("%d", value());
646}
647
648
649void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000650 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000651}
652
653
Ben Murdochb0fe1622011-05-05 13:52:32 +0100654void Failure::FailurePrint(FILE* out) {
655 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000656}
657
658
Steve Blocka7e24c12009-10-30 11:49:00 +0000659// Should a word be prefixed by 'a' or 'an' in order to read naturally in
660// English? Returns false for non-ASCII or words that don't start with
661// a capital letter. The a/an rule follows pronunciation in English.
662// We don't use the BBC's overcorrect "an historic occasion" though if
663// you speak a dialect you may well say "an 'istoric occasion".
664static bool AnWord(String* str) {
665 if (str->length() == 0) return false; // A nothing.
666 int c0 = str->Get(0);
667 int c1 = str->length() > 1 ? str->Get(1) : 0;
668 if (c0 == 'U') {
669 if (c1 > 'Z') {
670 return true; // An Umpire, but a UTF8String, a U.
671 }
672 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
673 return true; // An Ape, an ABCBook.
674 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
675 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
676 c0 == 'S' || c0 == 'X')) {
677 return true; // An MP3File, an M.
678 }
679 return false;
680}
681
682
John Reck59135872010-11-02 12:39:01 -0700683MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000684#ifdef DEBUG
685 // Do not attempt to flatten in debug mode when allocation is not
686 // allowed. This is to avoid an assertion failure when allocating.
687 // Flattening strings is the only case where we always allow
688 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100689 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000690#endif
691
Steve Block44f0eee2011-05-26 01:26:41 +0100692 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000693 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000694 case kConsStringTag: {
695 ConsString* cs = ConsString::cast(this);
696 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100697 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000698 }
699 // There's little point in putting the flat string in new space if the
700 // cons string is in old space. It can never get GCed until there is
701 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100702 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000703 int len = length();
704 Object* object;
705 String* result;
706 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100707 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700708 if (!maybe_object->ToObject(&object)) return maybe_object;
709 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000710 result = String::cast(object);
711 String* first = cs->first();
712 int first_length = first->length();
713 char* dest = SeqAsciiString::cast(result)->GetChars();
714 WriteToFlat(first, dest, 0, first_length);
715 String* second = cs->second();
716 WriteToFlat(second,
717 dest + first_length,
718 0,
719 len - first_length);
720 } else {
John Reck59135872010-11-02 12:39:01 -0700721 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100722 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700723 if (!maybe_object->ToObject(&object)) return maybe_object;
724 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000725 result = String::cast(object);
726 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
727 String* first = cs->first();
728 int first_length = first->length();
729 WriteToFlat(first, dest, 0, first_length);
730 String* second = cs->second();
731 WriteToFlat(second,
732 dest + first_length,
733 0,
734 len - first_length);
735 }
736 cs->set_first(result);
Steve Block44f0eee2011-05-26 01:26:41 +0100737 cs->set_second(heap->empty_string());
Leon Clarkef7060e22010-06-03 12:02:55 +0100738 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000739 }
740 default:
741 return this;
742 }
743}
744
745
746bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100747 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100748 // prohibited by the API.
749 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000750#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000751 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 // Assert that the resource and the string are equivalent.
753 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100754 ScopedVector<uc16> smart_chars(this->length());
755 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
756 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000757 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100758 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 }
760#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100761 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 int size = this->Size(); // Byte size of the original string.
763 if (size < ExternalString::kSize) {
764 // The string is too small to fit an external String in its place. This can
765 // only happen for zero length strings.
766 return false;
767 }
768 ASSERT(size >= ExternalString::kSize);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100769 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 bool is_symbol = this->IsSymbol();
771 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000772 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000773
774 // Morph the object to an external string by adjusting the map and
775 // reinitializing the fields.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100776 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100777 heap->external_string_with_ascii_data_map() :
778 heap->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
780 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000781 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000782 self->set_resource(resource);
783 // Additionally make the object into an external symbol if the original string
784 // was a symbol to start with.
785 if (is_symbol) {
786 self->Hash(); // Force regeneration of the hash value.
787 // Now morph this external string into a external symbol.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100788 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100789 heap->external_symbol_with_ascii_data_map() :
790 heap->external_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000791 }
792
793 // Fill the remainder of the string with dead wood.
794 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100795 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000796 return true;
797}
798
799
800bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
801#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000802 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 // Assert that the resource and the string are equivalent.
804 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100805 ScopedVector<char> smart_chars(this->length());
806 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
807 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100809 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000810 }
811#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100812 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 int size = this->Size(); // Byte size of the original string.
814 if (size < ExternalString::kSize) {
815 // The string is too small to fit an external String in its place. This can
816 // only happen for zero length strings.
817 return false;
818 }
819 ASSERT(size >= ExternalString::kSize);
820 bool is_symbol = this->IsSymbol();
821 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000822 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000823
824 // Morph the object to an external string by adjusting the map and
825 // reinitializing the fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100826 this->set_map(heap->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000827 ExternalAsciiString* self = ExternalAsciiString::cast(this);
828 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000829 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000830 self->set_resource(resource);
831 // Additionally make the object into an external symbol if the original string
832 // was a symbol to start with.
833 if (is_symbol) {
834 self->Hash(); // Force regeneration of the hash value.
835 // Now morph this external string into a external symbol.
Steve Block44f0eee2011-05-26 01:26:41 +0100836 this->set_map(heap->external_ascii_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 }
838
839 // Fill the remainder of the string with dead wood.
840 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100841 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 return true;
843}
844
845
846void String::StringShortPrint(StringStream* accumulator) {
847 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +0000848 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 accumulator->Add("<Very long string[%u]>", len);
850 return;
851 }
852
853 if (!LooksValid()) {
854 accumulator->Add("<Invalid String>");
855 return;
856 }
857
858 StringInputBuffer buf(this);
859
860 bool truncated = false;
861 if (len > kMaxShortPrintLength) {
862 len = kMaxShortPrintLength;
863 truncated = true;
864 }
865 bool ascii = true;
866 for (int i = 0; i < len; i++) {
867 int c = buf.GetNext();
868
869 if (c < 32 || c >= 127) {
870 ascii = false;
871 }
872 }
873 buf.Reset(this);
874 if (ascii) {
875 accumulator->Add("<String[%u]: ", length());
876 for (int i = 0; i < len; i++) {
877 accumulator->Put(buf.GetNext());
878 }
879 accumulator->Put('>');
880 } else {
881 // Backslash indicates that the string contains control
882 // characters and that backslashes are therefore escaped.
883 accumulator->Add("<String[%u]\\: ", length());
884 for (int i = 0; i < len; i++) {
885 int c = buf.GetNext();
886 if (c == '\n') {
887 accumulator->Add("\\n");
888 } else if (c == '\r') {
889 accumulator->Add("\\r");
890 } else if (c == '\\') {
891 accumulator->Add("\\\\");
892 } else if (c < 32 || c > 126) {
893 accumulator->Add("\\x%02x", c);
894 } else {
895 accumulator->Put(c);
896 }
897 }
898 if (truncated) {
899 accumulator->Put('.');
900 accumulator->Put('.');
901 accumulator->Put('.');
902 }
903 accumulator->Put('>');
904 }
905 return;
906}
907
908
909void JSObject::JSObjectShortPrint(StringStream* accumulator) {
910 switch (map()->instance_type()) {
911 case JS_ARRAY_TYPE: {
912 double length = JSArray::cast(this)->length()->Number();
913 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
914 break;
915 }
916 case JS_REGEXP_TYPE: {
917 accumulator->Add("<JS RegExp>");
918 break;
919 }
920 case JS_FUNCTION_TYPE: {
921 Object* fun_name = JSFunction::cast(this)->shared()->name();
922 bool printed = false;
923 if (fun_name->IsString()) {
924 String* str = String::cast(fun_name);
925 if (str->length() > 0) {
926 accumulator->Add("<JS Function ");
927 accumulator->Put(str);
928 accumulator->Put('>');
929 printed = true;
930 }
931 }
932 if (!printed) {
933 accumulator->Add("<JS Function>");
934 }
935 break;
936 }
937 // All other JSObjects are rather similar to each other (JSObject,
938 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
939 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100940 Map* map_of_this = map();
941 Heap* heap = map_of_this->heap();
942 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +0000943 bool printed = false;
944 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100945 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000946 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
947 } else {
948 bool global_object = IsJSGlobalProxy();
949 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100950 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
952 } else {
953 Object* constructor_name =
954 JSFunction::cast(constructor)->shared()->name();
955 if (constructor_name->IsString()) {
956 String* str = String::cast(constructor_name);
957 if (str->length() > 0) {
958 bool vowel = AnWord(str);
959 accumulator->Add("<%sa%s ",
960 global_object ? "Global Object: " : "",
961 vowel ? "n" : "");
962 accumulator->Put(str);
963 accumulator->Put('>');
964 printed = true;
965 }
966 }
967 }
968 }
969 if (!printed) {
970 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
971 }
972 }
973 if (IsJSValue()) {
974 accumulator->Add(" value = ");
975 JSValue::cast(this)->value()->ShortPrint(accumulator);
976 }
977 accumulator->Put('>');
978 break;
979 }
980 }
981}
982
983
984void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +0100985 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
986 Heap* heap = GetHeap();
987 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 accumulator->Add("!!!INVALID POINTER!!!");
989 return;
990 }
Steve Block44f0eee2011-05-26 01:26:41 +0100991 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 accumulator->Add("!!!INVALID MAP!!!");
993 return;
994 }
995
996 accumulator->Add("%p ", this);
997
998 if (IsString()) {
999 String::cast(this)->StringShortPrint(accumulator);
1000 return;
1001 }
1002 if (IsJSObject()) {
1003 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1004 return;
1005 }
1006 switch (map()->instance_type()) {
1007 case MAP_TYPE:
1008 accumulator->Add("<Map>");
1009 break;
1010 case FIXED_ARRAY_TYPE:
1011 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1012 break;
1013 case BYTE_ARRAY_TYPE:
1014 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1015 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001016 case EXTERNAL_PIXEL_ARRAY_TYPE:
1017 accumulator->Add("<ExternalPixelArray[%u]>",
1018 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001019 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001020 case EXTERNAL_BYTE_ARRAY_TYPE:
1021 accumulator->Add("<ExternalByteArray[%u]>",
1022 ExternalByteArray::cast(this)->length());
1023 break;
1024 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1025 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1026 ExternalUnsignedByteArray::cast(this)->length());
1027 break;
1028 case EXTERNAL_SHORT_ARRAY_TYPE:
1029 accumulator->Add("<ExternalShortArray[%u]>",
1030 ExternalShortArray::cast(this)->length());
1031 break;
1032 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1033 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1034 ExternalUnsignedShortArray::cast(this)->length());
1035 break;
1036 case EXTERNAL_INT_ARRAY_TYPE:
1037 accumulator->Add("<ExternalIntArray[%u]>",
1038 ExternalIntArray::cast(this)->length());
1039 break;
1040 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1041 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1042 ExternalUnsignedIntArray::cast(this)->length());
1043 break;
1044 case EXTERNAL_FLOAT_ARRAY_TYPE:
1045 accumulator->Add("<ExternalFloatArray[%u]>",
1046 ExternalFloatArray::cast(this)->length());
1047 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001048 case SHARED_FUNCTION_INFO_TYPE:
1049 accumulator->Add("<SharedFunctionInfo>");
1050 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001051 case JS_MESSAGE_OBJECT_TYPE:
1052 accumulator->Add("<JSMessageObject>");
1053 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001054#define MAKE_STRUCT_CASE(NAME, Name, name) \
1055 case NAME##_TYPE: \
1056 accumulator->Put('<'); \
1057 accumulator->Add(#Name); \
1058 accumulator->Put('>'); \
1059 break;
1060 STRUCT_LIST(MAKE_STRUCT_CASE)
1061#undef MAKE_STRUCT_CASE
1062 case CODE_TYPE:
1063 accumulator->Add("<Code>");
1064 break;
1065 case ODDBALL_TYPE: {
1066 if (IsUndefined())
1067 accumulator->Add("<undefined>");
1068 else if (IsTheHole())
1069 accumulator->Add("<the hole>");
1070 else if (IsNull())
1071 accumulator->Add("<null>");
1072 else if (IsTrue())
1073 accumulator->Add("<true>");
1074 else if (IsFalse())
1075 accumulator->Add("<false>");
1076 else
1077 accumulator->Add("<Odd Oddball>");
1078 break;
1079 }
1080 case HEAP_NUMBER_TYPE:
1081 accumulator->Add("<Number: ");
1082 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1083 accumulator->Put('>');
1084 break;
1085 case PROXY_TYPE:
1086 accumulator->Add("<Proxy>");
1087 break;
1088 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1089 accumulator->Add("Cell for ");
1090 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1091 break;
1092 default:
1093 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1094 break;
1095 }
1096}
1097
1098
Steve Blocka7e24c12009-10-30 11:49:00 +00001099void HeapObject::Iterate(ObjectVisitor* v) {
1100 // Handle header
1101 IteratePointer(v, kMapOffset);
1102 // Handle object body
1103 Map* m = map();
1104 IterateBody(m->instance_type(), SizeFromMap(m), v);
1105}
1106
1107
1108void HeapObject::IterateBody(InstanceType type, int object_size,
1109 ObjectVisitor* v) {
1110 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1111 // During GC, the map pointer field is encoded.
1112 if (type < FIRST_NONSTRING_TYPE) {
1113 switch (type & kStringRepresentationMask) {
1114 case kSeqStringTag:
1115 break;
1116 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001117 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001118 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001119 case kExternalStringTag:
1120 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1121 reinterpret_cast<ExternalAsciiString*>(this)->
1122 ExternalAsciiStringIterateBody(v);
1123 } else {
1124 reinterpret_cast<ExternalTwoByteString*>(this)->
1125 ExternalTwoByteStringIterateBody(v);
1126 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001127 break;
1128 }
1129 return;
1130 }
1131
1132 switch (type) {
1133 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001134 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 break;
1136 case JS_OBJECT_TYPE:
1137 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1138 case JS_VALUE_TYPE:
1139 case JS_ARRAY_TYPE:
1140 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001141 case JS_GLOBAL_PROXY_TYPE:
1142 case JS_GLOBAL_OBJECT_TYPE:
1143 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001144 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001145 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001146 break;
Steve Block791712a2010-08-27 10:21:07 +01001147 case JS_FUNCTION_TYPE:
1148 reinterpret_cast<JSFunction*>(this)
1149 ->JSFunctionIterateBody(object_size, v);
1150 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001151 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001152 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 break;
1154 case PROXY_TYPE:
1155 reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
1156 break;
1157 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001158 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001159 break;
1160 case CODE_TYPE:
1161 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1162 break;
1163 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001164 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001165 break;
1166 case HEAP_NUMBER_TYPE:
1167 case FILLER_TYPE:
1168 case BYTE_ARRAY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001169 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001170 case EXTERNAL_BYTE_ARRAY_TYPE:
1171 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1172 case EXTERNAL_SHORT_ARRAY_TYPE:
1173 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1174 case EXTERNAL_INT_ARRAY_TYPE:
1175 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1176 case EXTERNAL_FLOAT_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001177 break;
Iain Merrick75681382010-08-19 15:07:18 +01001178 case SHARED_FUNCTION_INFO_TYPE:
1179 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 break;
Iain Merrick75681382010-08-19 15:07:18 +01001181
Steve Blocka7e24c12009-10-30 11:49:00 +00001182#define MAKE_STRUCT_CASE(NAME, Name, name) \
1183 case NAME##_TYPE:
1184 STRUCT_LIST(MAKE_STRUCT_CASE)
1185#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001186 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001187 break;
1188 default:
1189 PrintF("Unknown type: %d\n", type);
1190 UNREACHABLE();
1191 }
1192}
1193
1194
Steve Blocka7e24c12009-10-30 11:49:00 +00001195Object* HeapNumber::HeapNumberToBoolean() {
1196 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001197#if __BYTE_ORDER == __LITTLE_ENDIAN
1198 union IeeeDoubleLittleEndianArchType u;
1199#elif __BYTE_ORDER == __BIG_ENDIAN
1200 union IeeeDoubleBigEndianArchType u;
1201#endif
1202 u.d = value();
1203 if (u.bits.exp == 2047) {
1204 // Detect NaN for IEEE double precision floating point.
1205 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001206 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 }
Iain Merrick75681382010-08-19 15:07:18 +01001208 if (u.bits.exp == 0) {
1209 // Detect +0, and -0 for IEEE double precision floating point.
1210 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001211 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001212 }
Steve Block44f0eee2011-05-26 01:26:41 +01001213 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001214}
1215
1216
Ben Murdochb0fe1622011-05-05 13:52:32 +01001217void HeapNumber::HeapNumberPrint(FILE* out) {
1218 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001219}
1220
1221
1222void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1223 // The Windows version of vsnprintf can allocate when printing a %g string
1224 // into a buffer that may not be big enough. We don't want random memory
1225 // allocation when producing post-crash stack traces, so we print into a
1226 // buffer that is plenty big enough for any floating point number, then
1227 // print that using vsnprintf (which may truncate but never allocate if
1228 // there is no more space in the buffer).
1229 EmbeddedVector<char, 100> buffer;
1230 OS::SNPrintF(buffer, "%.16g", Number());
1231 accumulator->Add("%s", buffer.start());
1232}
1233
1234
1235String* JSObject::class_name() {
1236 if (IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001237 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 }
1239 if (map()->constructor()->IsJSFunction()) {
1240 JSFunction* constructor = JSFunction::cast(map()->constructor());
1241 return String::cast(constructor->shared()->instance_class_name());
1242 }
1243 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001244 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001245}
1246
1247
1248String* JSObject::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001249 if (map()->constructor()->IsJSFunction()) {
1250 JSFunction* constructor = JSFunction::cast(map()->constructor());
1251 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001252 if (name->length() > 0) return name;
1253 String* inferred_name = constructor->shared()->inferred_name();
1254 if (inferred_name->length() > 0) return inferred_name;
1255 Object* proto = GetPrototype();
1256 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001257 }
1258 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001259 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001260}
1261
1262
John Reck59135872010-11-02 12:39:01 -07001263MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1264 String* name,
1265 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001266 int index = new_map->PropertyIndexFor(name);
1267 if (map()->unused_property_fields() == 0) {
1268 ASSERT(map()->unused_property_fields() == 0);
1269 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001270 Object* values;
1271 { MaybeObject* maybe_values =
1272 properties()->CopySize(properties()->length() + new_unused + 1);
1273 if (!maybe_values->ToObject(&values)) return maybe_values;
1274 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001275 set_properties(FixedArray::cast(values));
1276 }
1277 set_map(new_map);
1278 return FastPropertyAtPut(index, value);
1279}
1280
1281
Ben Murdoch8b112d22011-06-08 16:22:53 +01001282static bool IsIdentifier(UnicodeCache* cache,
1283 unibrow::CharacterStream* buffer) {
1284 // Checks whether the buffer contains an identifier (no escape).
1285 if (!buffer->has_more()) return false;
1286 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1287 return false;
1288 }
1289 while (buffer->has_more()) {
1290 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1291 return false;
1292 }
1293 }
1294 return true;
1295}
1296
1297
John Reck59135872010-11-02 12:39:01 -07001298MaybeObject* JSObject::AddFastProperty(String* name,
1299 Object* value,
1300 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001301 ASSERT(!IsJSGlobalProxy());
1302
Steve Blocka7e24c12009-10-30 11:49:00 +00001303 // Normalize the object if the name is an actual string (not the
1304 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001305 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001306 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001307 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001308 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001309 Object* obj;
1310 { MaybeObject* maybe_obj =
1311 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1312 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1313 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 return AddSlowProperty(name, value, attributes);
1315 }
1316
1317 DescriptorArray* old_descriptors = map()->instance_descriptors();
1318 // Compute the new index for new field.
1319 int index = map()->NextFreePropertyIndex();
1320
1321 // Allocate new instance descriptors with (name, index) added
1322 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001323 Object* new_descriptors;
1324 { MaybeObject* maybe_new_descriptors =
1325 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1326 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1327 return maybe_new_descriptors;
1328 }
1329 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001330
Steve Block44f0eee2011-05-26 01:26:41 +01001331 // Only allow map transition if the object isn't the global object and there
1332 // is not a transition for the name, or there's a transition for the name but
1333 // it's unrelated to properties.
1334 int descriptor_index = old_descriptors->Search(name);
1335
1336 // External array transitions are stored in the descriptor for property "",
1337 // which is not a identifier and should have forced a switch to slow
1338 // properties above.
1339 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1340 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1341 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1342 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001343 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001344 can_insert_transition &&
1345 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001346
1347 ASSERT(index < map()->inobject_properties() ||
1348 (index - map()->inobject_properties()) < properties()->length() ||
1349 map()->unused_property_fields() == 0);
1350 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001351 Object* r;
1352 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1353 if (!maybe_r->ToObject(&r)) return maybe_r;
1354 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001355 Map* new_map = Map::cast(r);
1356 if (allow_map_transition) {
1357 // Allocate new instance descriptors for the old map with map transition.
1358 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001359 Object* r;
1360 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1361 if (!maybe_r->ToObject(&r)) return maybe_r;
1362 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 old_descriptors = DescriptorArray::cast(r);
1364 }
1365
1366 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001367 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001368 Object* obj;
1369 { MaybeObject* maybe_obj =
1370 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1371 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1372 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001373 return AddSlowProperty(name, value, attributes);
1374 }
1375 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001376 Object* values;
1377 { MaybeObject* maybe_values =
1378 properties()->CopySize(properties()->length() + kFieldsAdded);
1379 if (!maybe_values->ToObject(&values)) return maybe_values;
1380 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 set_properties(FixedArray::cast(values));
1382 new_map->set_unused_property_fields(kFieldsAdded - 1);
1383 } else {
1384 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1385 }
1386 // We have now allocated all the necessary objects.
1387 // All the changes can be applied at once, so they are atomic.
1388 map()->set_instance_descriptors(old_descriptors);
1389 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1390 set_map(new_map);
1391 return FastPropertyAtPut(index, value);
1392}
1393
1394
John Reck59135872010-11-02 12:39:01 -07001395MaybeObject* JSObject::AddConstantFunctionProperty(
1396 String* name,
1397 JSFunction* function,
1398 PropertyAttributes attributes) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001399 ASSERT(!GetHeap()->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001400
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 // Allocate new instance descriptors with (name, function) added
1402 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001403 Object* new_descriptors;
1404 { MaybeObject* maybe_new_descriptors =
1405 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1406 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1407 return maybe_new_descriptors;
1408 }
1409 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001410
1411 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001412 Object* new_map;
1413 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1414 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1415 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001416
1417 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1418 Map::cast(new_map)->set_instance_descriptors(descriptors);
1419 Map* old_map = map();
1420 set_map(Map::cast(new_map));
1421
1422 // If the old map is the global object map (from new Object()),
1423 // then transitions are not added to it, so we are done.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001424 Heap* heap = old_map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001425 if (old_map == heap->isolate()->context()->global_context()->
1426 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001427 return function;
1428 }
1429
1430 // Do not add CONSTANT_TRANSITIONS to global objects
1431 if (IsGlobalObject()) {
1432 return function;
1433 }
1434
1435 // Add a CONSTANT_TRANSITION descriptor to the old map,
1436 // so future assignments to this property on other objects
1437 // of the same type will create a normal field, not a constant function.
1438 // Don't do this for special properties, with non-trival attributes.
1439 if (attributes != NONE) {
1440 return function;
1441 }
Iain Merrick75681382010-08-19 15:07:18 +01001442 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001443 { MaybeObject* maybe_new_descriptors =
1444 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1445 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1446 // We have accomplished the main goal, so return success.
1447 return function;
1448 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001449 }
1450 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1451
1452 return function;
1453}
1454
1455
1456// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001457MaybeObject* JSObject::AddSlowProperty(String* name,
1458 Object* value,
1459 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001460 ASSERT(!HasFastProperties());
1461 StringDictionary* dict = property_dictionary();
1462 Object* store_value = value;
1463 if (IsGlobalObject()) {
1464 // In case name is an orphaned property reuse the cell.
1465 int entry = dict->FindEntry(name);
1466 if (entry != StringDictionary::kNotFound) {
1467 store_value = dict->ValueAt(entry);
1468 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1469 // Assign an enumeration index to the property and update
1470 // SetNextEnumerationIndex.
1471 int index = dict->NextEnumerationIndex();
1472 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1473 dict->SetNextEnumerationIndex(index + 1);
1474 dict->SetEntry(entry, name, store_value, details);
1475 return value;
1476 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001477 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001478 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001479 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001480 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1481 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001482 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1483 }
1484 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001485 Object* result;
1486 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1487 if (!maybe_result->ToObject(&result)) return maybe_result;
1488 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001489 if (dict != result) set_properties(StringDictionary::cast(result));
1490 return value;
1491}
1492
1493
John Reck59135872010-11-02 12:39:01 -07001494MaybeObject* JSObject::AddProperty(String* name,
1495 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001496 PropertyAttributes attributes,
1497 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001499 Map* map_of_this = map();
1500 Heap* heap = map_of_this->heap();
1501 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001502 if (strict_mode == kNonStrictMode) {
1503 return heap->undefined_value();
1504 } else {
1505 Handle<Object> args[1] = {Handle<String>(name)};
1506 return heap->isolate()->Throw(
1507 *FACTORY->NewTypeError("object_not_extensible",
1508 HandleVector(args, 1)));
1509 }
Steve Block8defd9f2010-07-08 12:39:36 +01001510 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001511 if (HasFastProperties()) {
1512 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001513 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001514 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001515 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001516 return AddConstantFunctionProperty(name,
1517 JSFunction::cast(value),
1518 attributes);
1519 } else {
1520 return AddFastProperty(name, value, attributes);
1521 }
1522 } else {
1523 // Normalize the object to prevent very large instance descriptors.
1524 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001525 Object* obj;
1526 { MaybeObject* maybe_obj =
1527 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1528 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1529 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001530 }
1531 }
1532 return AddSlowProperty(name, value, attributes);
1533}
1534
1535
John Reck59135872010-11-02 12:39:01 -07001536MaybeObject* JSObject::SetPropertyPostInterceptor(
1537 String* name,
1538 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001539 PropertyAttributes attributes,
1540 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001541 // Check local property, ignore interceptor.
1542 LookupResult result;
1543 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001544 if (result.IsFound()) {
1545 // An existing property, a map transition or a null descriptor was
1546 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001547 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001548 }
1549 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001550 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001551}
1552
1553
John Reck59135872010-11-02 12:39:01 -07001554MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1555 Object* value,
1556 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001557 StringDictionary* dictionary = property_dictionary();
1558 int old_index = dictionary->FindEntry(name);
1559 int new_enumeration_index = 0; // 0 means "Use the next available index."
1560 if (old_index != -1) {
1561 // All calls to ReplaceSlowProperty have had all transitions removed.
1562 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1563 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1564 }
1565
1566 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1567 return SetNormalizedProperty(name, value, new_details);
1568}
1569
Steve Blockd0582a62009-12-15 09:54:21 +00001570
John Reck59135872010-11-02 12:39:01 -07001571MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 String* name,
1573 Object* new_value,
1574 PropertyAttributes attributes) {
1575 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001576 Object* result;
1577 { MaybeObject* maybe_result =
1578 ConvertDescriptorToField(name, new_value, attributes);
1579 if (!maybe_result->ToObject(&result)) return maybe_result;
1580 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001581 // If we get to this point we have succeeded - do not return failure
1582 // after this point. Later stuff is optional.
1583 if (!HasFastProperties()) {
1584 return result;
1585 }
1586 // Do not add transitions to the map of "new Object()".
Ben Murdoch8b112d22011-06-08 16:22:53 +01001587 if (map() == old_map->heap()->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001588 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001589 return result;
1590 }
1591
1592 MapTransitionDescriptor transition(name,
1593 map(),
1594 attributes);
John Reck59135872010-11-02 12:39:01 -07001595 Object* new_descriptors;
1596 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1597 CopyInsert(&transition, KEEP_TRANSITIONS);
1598 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1599 return result; // Yes, return _result_.
1600 }
1601 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001602 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1603 return result;
1604}
1605
1606
John Reck59135872010-11-02 12:39:01 -07001607MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1608 Object* new_value,
1609 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001610 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001611 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001612 Object* obj;
1613 { MaybeObject* maybe_obj =
1614 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1615 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1616 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001617 return ReplaceSlowProperty(name, new_value, attributes);
1618 }
1619
1620 int index = map()->NextFreePropertyIndex();
1621 FieldDescriptor new_field(name, index, attributes);
1622 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001623 Object* descriptors_unchecked;
1624 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1625 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1626 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1627 return maybe_descriptors_unchecked;
1628 }
1629 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 DescriptorArray* new_descriptors =
1631 DescriptorArray::cast(descriptors_unchecked);
1632
1633 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001634 Object* new_map_unchecked;
1635 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1636 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1637 return maybe_new_map_unchecked;
1638 }
1639 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001640 Map* new_map = Map::cast(new_map_unchecked);
1641 new_map->set_instance_descriptors(new_descriptors);
1642
1643 // Make new properties array if necessary.
1644 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1645 int new_unused_property_fields = map()->unused_property_fields() - 1;
1646 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001647 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001648 Object* new_properties_object;
1649 { MaybeObject* maybe_new_properties_object =
1650 properties()->CopySize(properties()->length() + kFieldsAdded);
1651 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1652 return maybe_new_properties_object;
1653 }
1654 }
1655 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001656 }
1657
1658 // Update pointers to commit changes.
1659 // Object points to the new map.
1660 new_map->set_unused_property_fields(new_unused_property_fields);
1661 set_map(new_map);
1662 if (new_properties) {
1663 set_properties(FixedArray::cast(new_properties));
1664 }
1665 return FastPropertyAtPut(index, new_value);
1666}
1667
1668
1669
John Reck59135872010-11-02 12:39:01 -07001670MaybeObject* JSObject::SetPropertyWithInterceptor(
1671 String* name,
1672 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001673 PropertyAttributes attributes,
1674 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001675 Isolate* isolate = GetIsolate();
1676 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001677 Handle<JSObject> this_handle(this);
1678 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001679 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001680 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1681 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001682 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1683 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001684 v8::AccessorInfo info(args.end());
1685 v8::NamedPropertySetter setter =
1686 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1687 v8::Handle<v8::Value> result;
1688 {
1689 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001690 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001691 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001692 isolate->heap()->undefined_value() :
1693 value,
1694 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 result = setter(v8::Utils::ToLocal(name_handle),
1696 v8::Utils::ToLocal(value_unhole),
1697 info);
1698 }
Steve Block44f0eee2011-05-26 01:26:41 +01001699 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001700 if (!result.IsEmpty()) return *value_handle;
1701 }
John Reck59135872010-11-02 12:39:01 -07001702 MaybeObject* raw_result =
1703 this_handle->SetPropertyPostInterceptor(*name_handle,
1704 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001705 attributes,
1706 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001707 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001708 return raw_result;
1709}
1710
1711
John Reck59135872010-11-02 12:39:01 -07001712MaybeObject* JSObject::SetProperty(String* name,
1713 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001714 PropertyAttributes attributes,
1715 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001716 LookupResult result;
1717 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001718 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001719}
1720
1721
John Reck59135872010-11-02 12:39:01 -07001722MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1723 String* name,
1724 Object* value,
1725 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01001726 Isolate* isolate = GetIsolate();
1727 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001728
1729 // We should never get here to initialize a const with the hole
1730 // value since a const declaration would conflict with the setter.
1731 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001732 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001733
1734 // To accommodate both the old and the new api we switch on the
1735 // data structure used to store the callbacks. Eventually proxy
1736 // callbacks should be phased out.
1737 if (structure->IsProxy()) {
1738 AccessorDescriptor* callback =
1739 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
John Reck59135872010-11-02 12:39:01 -07001740 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001741 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 if (obj->IsFailure()) return obj;
1743 return *value_handle;
1744 }
1745
1746 if (structure->IsAccessorInfo()) {
1747 // api style callbacks
1748 AccessorInfo* data = AccessorInfo::cast(structure);
1749 Object* call_obj = data->setter();
1750 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1751 if (call_fun == NULL) return value;
1752 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001753 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1754 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001755 v8::AccessorInfo info(args.end());
1756 {
1757 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001758 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001759 call_fun(v8::Utils::ToLocal(key),
1760 v8::Utils::ToLocal(value_handle),
1761 info);
1762 }
Steve Block44f0eee2011-05-26 01:26:41 +01001763 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 return *value_handle;
1765 }
1766
1767 if (structure->IsFixedArray()) {
1768 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1769 if (setter->IsJSFunction()) {
1770 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1771 } else {
1772 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001773 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001774 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01001775 return isolate->Throw(
1776 *isolate->factory()->NewTypeError("no_setter_in_callback",
1777 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001778 }
1779 }
1780
1781 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01001782 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001783}
1784
1785
John Reck59135872010-11-02 12:39:01 -07001786MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1787 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01001788 Isolate* isolate = GetIsolate();
1789 Handle<Object> value_handle(value, isolate);
1790 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1791 Handle<JSObject> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001792#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01001793 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00001794 // Handle stepping into a setter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01001795 if (debug->StepInActive()) {
1796 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 }
1798#endif
1799 bool has_pending_exception;
1800 Object** argv[] = { value_handle.location() };
1801 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1802 // Check for pending exception and return the result.
1803 if (has_pending_exception) return Failure::Exception();
1804 return *value_handle;
1805}
1806
1807
1808void JSObject::LookupCallbackSetterInPrototypes(String* name,
1809 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001810 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001811 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001812 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001813 pt = pt->GetPrototype()) {
1814 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001815 if (result->IsProperty()) {
1816 if (result->IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001817 result->NotFound();
1818 return;
1819 }
1820 if (result->type() == CALLBACKS) {
1821 return;
1822 }
1823 }
1824 }
1825 result->NotFound();
1826}
1827
1828
Steve Block1e0659c2011-05-24 12:43:12 +01001829MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
1830 Object* value,
1831 bool* found) {
Steve Block44f0eee2011-05-26 01:26:41 +01001832 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001833 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001834 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001835 pt = pt->GetPrototype()) {
1836 if (!JSObject::cast(pt)->HasDictionaryElements()) {
1837 continue;
1838 }
1839 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1840 int entry = dictionary->FindEntry(index);
1841 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001842 PropertyDetails details = dictionary->DetailsAt(entry);
1843 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001844 *found = true;
1845 return SetElementWithCallback(
1846 dictionary->ValueAt(entry), index, value, JSObject::cast(pt));
Steve Blocka7e24c12009-10-30 11:49:00 +00001847 }
1848 }
1849 }
Steve Block1e0659c2011-05-24 12:43:12 +01001850 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001851 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001852}
1853
1854
1855void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1856 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001857 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 if (number != DescriptorArray::kNotFound) {
1859 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1860 } else {
1861 result->NotFound();
1862 }
1863}
1864
1865
Ben Murdochb0fe1622011-05-05 13:52:32 +01001866void Map::LookupInDescriptors(JSObject* holder,
1867 String* name,
1868 LookupResult* result) {
1869 DescriptorArray* descriptors = instance_descriptors();
Steve Block44f0eee2011-05-26 01:26:41 +01001870 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1871 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001872 if (number == DescriptorLookupCache::kAbsent) {
1873 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001874 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001875 }
1876 if (number != DescriptorArray::kNotFound) {
1877 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1878 } else {
1879 result->NotFound();
1880 }
1881}
1882
1883
Steve Block44f0eee2011-05-26 01:26:41 +01001884MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
1885 bool safe_to_add_transition) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001886 Heap* current_heap = heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001887 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001888 String* external_array_sentinel_name = current_heap->empty_symbol();
Steve Block44f0eee2011-05-26 01:26:41 +01001889
1890 if (safe_to_add_transition) {
1891 // It's only safe to manipulate the descriptor array if it would be
1892 // safe to add a transition.
1893
1894 ASSERT(!is_shared()); // no transitions can be added to shared maps.
1895 // Check if the external array transition already exists.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001896 DescriptorLookupCache* cache =
1897 current_heap->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01001898 int index = cache->Lookup(descriptors, external_array_sentinel_name);
1899 if (index == DescriptorLookupCache::kAbsent) {
1900 index = descriptors->Search(external_array_sentinel_name);
1901 cache->Update(descriptors,
1902 external_array_sentinel_name,
1903 index);
1904 }
1905
1906 // If the transition already exists, check the type. If there is a match,
1907 // return it.
1908 if (index != DescriptorArray::kNotFound) {
1909 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
1910 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
1911 details.array_type() == array_type) {
1912 return descriptors->GetValue(index);
1913 } else {
1914 safe_to_add_transition = false;
1915 }
1916 }
1917 }
1918
1919 // No transition to an existing external array map. Make a new one.
1920 Object* obj;
1921 { MaybeObject* maybe_map = CopyDropTransitions();
1922 if (!maybe_map->ToObject(&obj)) return maybe_map;
1923 }
1924 Map* new_map = Map::cast(obj);
1925
1926 new_map->set_has_fast_elements(false);
1927 new_map->set_has_external_array_elements(true);
1928 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
1929
1930 // Only remember the map transition if the object's map is NOT equal to the
1931 // global object_function's map and there is not an already existing
1932 // non-matching external array transition.
1933 bool allow_map_transition =
1934 safe_to_add_transition &&
1935 (GetIsolate()->context()->global_context()->object_function()->map() !=
1936 map());
1937 if (allow_map_transition) {
1938 // Allocate new instance descriptors for the old map with map transition.
1939 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
1940 Map::cast(new_map),
1941 array_type);
1942 Object* new_descriptors;
1943 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
1944 &desc,
1945 KEEP_TRANSITIONS);
1946 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1947 return maybe_new_descriptors;
1948 }
1949 descriptors = DescriptorArray::cast(new_descriptors);
1950 set_instance_descriptors(descriptors);
1951 }
1952
1953 return new_map;
1954}
1955
1956
Steve Blocka7e24c12009-10-30 11:49:00 +00001957void JSObject::LocalLookupRealNamedProperty(String* name,
1958 LookupResult* result) {
1959 if (IsJSGlobalProxy()) {
1960 Object* proto = GetPrototype();
1961 if (proto->IsNull()) return result->NotFound();
1962 ASSERT(proto->IsJSGlobalObject());
1963 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
1964 }
1965
1966 if (HasFastProperties()) {
1967 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001968 if (result->IsFound()) {
1969 // A property, a map transition or a null descriptor was found.
1970 // We return all of these result types because
1971 // LocalLookupRealNamedProperty is used when setting properties
1972 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00001973 ASSERT(result->holder() == this && result->type() != NORMAL);
1974 // Disallow caching for uninitialized constants. These can only
1975 // occur as fields.
1976 if (result->IsReadOnly() && result->type() == FIELD &&
1977 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
1978 result->DisallowCaching();
1979 }
1980 return;
1981 }
1982 } else {
1983 int entry = property_dictionary()->FindEntry(name);
1984 if (entry != StringDictionary::kNotFound) {
1985 Object* value = property_dictionary()->ValueAt(entry);
1986 if (IsGlobalObject()) {
1987 PropertyDetails d = property_dictionary()->DetailsAt(entry);
1988 if (d.IsDeleted()) {
1989 result->NotFound();
1990 return;
1991 }
1992 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001993 }
1994 // Make sure to disallow caching for uninitialized constants
1995 // found in the dictionary-mode objects.
1996 if (value->IsTheHole()) result->DisallowCaching();
1997 result->DictionaryResult(this, entry);
1998 return;
1999 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002000 }
2001 result->NotFound();
2002}
2003
2004
2005void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2006 LocalLookupRealNamedProperty(name, result);
2007 if (result->IsProperty()) return;
2008
2009 LookupRealNamedPropertyInPrototypes(name, result);
2010}
2011
2012
2013void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2014 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002015 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002016 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002017 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002018 pt = JSObject::cast(pt)->GetPrototype()) {
2019 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002020 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002021 }
2022 result->NotFound();
2023}
2024
2025
2026// We only need to deal with CALLBACKS and INTERCEPTORS
John Reck59135872010-11-02 12:39:01 -07002027MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
2028 String* name,
Ben Murdoch086aeea2011-05-13 15:57:08 +01002029 Object* value,
2030 bool check_prototype) {
2031 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002032 LookupCallbackSetterInPrototypes(name, result);
2033 }
2034
2035 if (result->IsProperty()) {
2036 if (!result->IsReadOnly()) {
2037 switch (result->type()) {
2038 case CALLBACKS: {
2039 Object* obj = result->GetCallbackObject();
2040 if (obj->IsAccessorInfo()) {
2041 AccessorInfo* info = AccessorInfo::cast(obj);
2042 if (info->all_can_write()) {
2043 return SetPropertyWithCallback(result->GetCallbackObject(),
2044 name,
2045 value,
2046 result->holder());
2047 }
2048 }
2049 break;
2050 }
2051 case INTERCEPTOR: {
2052 // Try lookup real named properties. Note that only property can be
2053 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2054 LookupResult r;
2055 LookupRealNamedProperty(name, &r);
2056 if (r.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002057 return SetPropertyWithFailedAccessCheck(&r, name, value,
2058 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00002059 }
2060 break;
2061 }
2062 default: {
2063 break;
2064 }
2065 }
2066 }
2067 }
2068
Iain Merrick75681382010-08-19 15:07:18 +01002069 HandleScope scope;
2070 Handle<Object> value_handle(value);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002071 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01002072 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002073 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002074}
2075
2076
John Reck59135872010-11-02 12:39:01 -07002077MaybeObject* JSObject::SetProperty(LookupResult* result,
2078 String* name,
2079 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002080 PropertyAttributes attributes,
2081 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002082 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002083 // Make sure that the top context does not change when doing callbacks or
2084 // interceptor calls.
2085 AssertNoContextChange ncc;
2086
Steve Blockd0582a62009-12-15 09:54:21 +00002087 // Optimization for 2-byte strings often used as keys in a decompression
2088 // dictionary. We make these short keys into symbols to avoid constantly
2089 // reallocating them.
2090 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002091 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002092 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002093 if (maybe_symbol_version->ToObject(&symbol_version)) {
2094 name = String::cast(symbol_version);
2095 }
2096 }
Steve Blockd0582a62009-12-15 09:54:21 +00002097 }
2098
Steve Blocka7e24c12009-10-30 11:49:00 +00002099 // Check access rights if needed.
2100 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002101 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002102 return SetPropertyWithFailedAccessCheck(result, name, value, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00002103 }
2104
2105 if (IsJSGlobalProxy()) {
2106 Object* proto = GetPrototype();
2107 if (proto->IsNull()) return value;
2108 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002109 return JSObject::cast(proto)->SetProperty(
2110 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002111 }
2112
2113 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2114 // We could not find a local property so let's check whether there is an
2115 // accessor that wants to handle the property.
2116 LookupResult accessor_result;
2117 LookupCallbackSetterInPrototypes(name, &accessor_result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002118 if (accessor_result.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002119 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2120 name,
2121 value,
2122 accessor_result.holder());
2123 }
2124 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002125 if (!result->IsFound()) {
2126 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002127 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002128 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002129 if (result->IsReadOnly() && result->IsProperty()) {
2130 if (strict_mode == kStrictMode) {
2131 HandleScope scope;
2132 Handle<String> key(name);
2133 Handle<Object> holder(this);
2134 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002135 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2136 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002137 } else {
2138 return value;
2139 }
2140 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002141 // This is a real property that is not read-only, or it is a
2142 // transition or null descriptor and there are no setters in the prototypes.
2143 switch (result->type()) {
2144 case NORMAL:
2145 return SetNormalizedProperty(result, value);
2146 case FIELD:
2147 return FastPropertyAtPut(result->GetFieldIndex(), value);
2148 case MAP_TRANSITION:
2149 if (attributes == result->GetAttributes()) {
2150 // Only use map transition if the attributes match.
2151 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2152 name,
2153 value);
2154 }
2155 return ConvertDescriptorToField(name, value, attributes);
2156 case CONSTANT_FUNCTION:
2157 // Only replace the function if necessary.
2158 if (value == result->GetConstantFunction()) return value;
2159 // Preserve the attributes of this existing property.
2160 attributes = result->GetAttributes();
2161 return ConvertDescriptorToField(name, value, attributes);
2162 case CALLBACKS:
2163 return SetPropertyWithCallback(result->GetCallbackObject(),
2164 name,
2165 value,
2166 result->holder());
2167 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002168 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002169 case CONSTANT_TRANSITION: {
2170 // If the same constant function is being added we can simply
2171 // transition to the target map.
2172 Map* target_map = result->GetTransitionMap();
2173 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2174 int number = target_descriptors->SearchWithCache(name);
2175 ASSERT(number != DescriptorArray::kNotFound);
2176 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2177 JSFunction* function =
2178 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002179 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002180 if (value == function) {
2181 set_map(target_map);
2182 return value;
2183 }
2184 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2185 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002186 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002187 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002188 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002189 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002190 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2191 default:
2192 UNREACHABLE();
2193 }
2194 UNREACHABLE();
2195 return value;
2196}
2197
2198
2199// Set a real local property, even if it is READ_ONLY. If the property is not
2200// present, add it with attributes NONE. This code is an exact clone of
2201// SetProperty, with the check for IsReadOnly and the check for a
2202// callback setter removed. The two lines looking up the LookupResult
2203// result are also added. If one of the functions is changed, the other
2204// should be.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002205MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002206 String* name,
2207 Object* value,
2208 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002209
Steve Blocka7e24c12009-10-30 11:49:00 +00002210 // Make sure that the top context does not change when doing callbacks or
2211 // interceptor calls.
2212 AssertNoContextChange ncc;
Andrei Popescu402d9372010-02-26 13:31:12 +00002213 LookupResult result;
2214 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002215 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002216 if (IsAccessCheckNeeded()) {
2217 Heap* heap = GetHeap();
2218 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2219 return SetPropertyWithFailedAccessCheck(&result, name, value, false);
2220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002221 }
2222
2223 if (IsJSGlobalProxy()) {
2224 Object* proto = GetPrototype();
2225 if (proto->IsNull()) return value;
2226 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002227 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002228 name,
2229 value,
2230 attributes);
2231 }
2232
2233 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002234 if (!result.IsFound()) {
2235 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002236 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002237 }
Steve Block6ded16b2010-05-10 14:33:55 +01002238
Andrei Popescu402d9372010-02-26 13:31:12 +00002239 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2240
Steve Blocka7e24c12009-10-30 11:49:00 +00002241 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002242 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002243 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002244 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002245 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002246 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002247 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002248 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002249 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002250 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002251 name,
2252 value);
2253 }
2254 return ConvertDescriptorToField(name, value, attributes);
2255 case CONSTANT_FUNCTION:
2256 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002257 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002258 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002259 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002260 return ConvertDescriptorToField(name, value, attributes);
2261 case CALLBACKS:
2262 case INTERCEPTOR:
2263 // Override callback in clone
2264 return ConvertDescriptorToField(name, value, attributes);
2265 case CONSTANT_TRANSITION:
2266 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2267 // if the value is a function.
2268 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2269 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002270 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002271 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2272 default:
2273 UNREACHABLE();
2274 }
2275 UNREACHABLE();
2276 return value;
2277}
2278
2279
2280PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2281 JSObject* receiver,
2282 String* name,
2283 bool continue_search) {
2284 // Check local property, ignore interceptor.
2285 LookupResult result;
2286 LocalLookupRealNamedProperty(name, &result);
2287 if (result.IsProperty()) return result.GetAttributes();
2288
2289 if (continue_search) {
2290 // Continue searching via the prototype chain.
2291 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002292 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002293 return JSObject::cast(pt)->
2294 GetPropertyAttributeWithReceiver(receiver, name);
2295 }
2296 }
2297 return ABSENT;
2298}
2299
2300
2301PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2302 JSObject* receiver,
2303 String* name,
2304 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002305 Isolate* isolate = GetIsolate();
2306
Steve Blocka7e24c12009-10-30 11:49:00 +00002307 // Make sure that the top context does not change when doing
2308 // callbacks or interceptor calls.
2309 AssertNoContextChange ncc;
2310
Steve Block44f0eee2011-05-26 01:26:41 +01002311 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002312 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2313 Handle<JSObject> receiver_handle(receiver);
2314 Handle<JSObject> holder_handle(this);
2315 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002316 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002317 v8::AccessorInfo info(args.end());
2318 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002319 v8::NamedPropertyQuery query =
2320 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002321 LOG(isolate,
2322 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002323 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002324 {
2325 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002326 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002327 result = query(v8::Utils::ToLocal(name_handle), info);
2328 }
2329 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002330 ASSERT(result->IsInt32());
2331 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002332 }
2333 } else if (!interceptor->getter()->IsUndefined()) {
2334 v8::NamedPropertyGetter getter =
2335 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002336 LOG(isolate,
2337 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002338 v8::Handle<v8::Value> result;
2339 {
2340 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002341 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002342 result = getter(v8::Utils::ToLocal(name_handle), info);
2343 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002344 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002345 }
2346 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2347 *name_handle,
2348 continue_search);
2349}
2350
2351
2352PropertyAttributes JSObject::GetPropertyAttributeWithReceiver(
2353 JSObject* receiver,
2354 String* key) {
2355 uint32_t index = 0;
2356 if (key->AsArrayIndex(&index)) {
2357 if (HasElementWithReceiver(receiver, index)) return NONE;
2358 return ABSENT;
2359 }
2360 // Named property.
2361 LookupResult result;
2362 Lookup(key, &result);
2363 return GetPropertyAttribute(receiver, &result, key, true);
2364}
2365
2366
2367PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
2368 LookupResult* result,
2369 String* name,
2370 bool continue_search) {
2371 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002372 if (IsAccessCheckNeeded()) {
2373 Heap* heap = GetHeap();
2374 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
2375 return GetPropertyAttributeWithFailedAccessCheck(receiver,
2376 result,
2377 name,
2378 continue_search);
2379 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002380 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002381 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002382 switch (result->type()) {
2383 case NORMAL: // fall through
2384 case FIELD:
2385 case CONSTANT_FUNCTION:
2386 case CALLBACKS:
2387 return result->GetAttributes();
2388 case INTERCEPTOR:
2389 return result->holder()->
2390 GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002391 default:
2392 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002393 }
2394 }
2395 return ABSENT;
2396}
2397
2398
2399PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
2400 // Check whether the name is an array index.
2401 uint32_t index = 0;
2402 if (name->AsArrayIndex(&index)) {
2403 if (HasLocalElement(index)) return NONE;
2404 return ABSENT;
2405 }
2406 // Named property.
2407 LookupResult result;
2408 LocalLookup(name, &result);
2409 return GetPropertyAttribute(this, &result, name, false);
2410}
2411
2412
John Reck59135872010-11-02 12:39:01 -07002413MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2414 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002415 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002416 Map* fast = obj->map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002417 int index = Hash(fast) % kEntries;
2418 Object* result = get(index);
2419 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002420#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002421 if (FLAG_enable_slow_asserts) {
2422 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002423 Object* fresh;
2424 { MaybeObject* maybe_fresh =
2425 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2426 if (maybe_fresh->ToObject(&fresh)) {
2427 ASSERT(memcmp(Map::cast(fresh)->address(),
2428 Map::cast(result)->address(),
2429 Map::kSize) == 0);
2430 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002431 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002432 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002433#endif
2434 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002435 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002436
John Reck59135872010-11-02 12:39:01 -07002437 { MaybeObject* maybe_result =
2438 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2439 if (!maybe_result->ToObject(&result)) return maybe_result;
2440 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002441 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002442 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002443
2444 return result;
2445}
2446
2447
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002448void NormalizedMapCache::Clear() {
2449 int entries = length();
2450 for (int i = 0; i != entries; i++) {
2451 set_undefined(i);
2452 }
2453}
2454
2455
2456int NormalizedMapCache::Hash(Map* fast) {
2457 // For performance reasons we only hash the 3 most variable fields of a map:
2458 // constructor, prototype and bit_field2.
2459
2460 // Shift away the tag.
2461 int hash = (static_cast<uint32_t>(
2462 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2);
2463
2464 // XOR-ing the prototype and constructor directly yields too many zero bits
2465 // when the two pointers are close (which is fairly common).
2466 // To avoid this we shift the prototype 4 bits relatively to the constructor.
2467 hash ^= (static_cast<uint32_t>(
2468 reinterpret_cast<uintptr_t>(fast->prototype())) << 2);
2469
2470 return hash ^ (hash >> 16) ^ fast->bit_field2();
2471}
2472
2473
2474bool NormalizedMapCache::CheckHit(Map* slow,
2475 Map* fast,
2476 PropertyNormalizationMode mode) {
2477#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002478 slow->SharedMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002479#endif
2480 return
2481 slow->constructor() == fast->constructor() &&
2482 slow->prototype() == fast->prototype() &&
2483 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
2484 0 :
2485 fast->inobject_properties()) &&
2486 slow->instance_type() == fast->instance_type() &&
2487 slow->bit_field() == fast->bit_field() &&
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002488 (slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002489}
2490
2491
John Reck59135872010-11-02 12:39:01 -07002492MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002493 if (map()->is_shared()) {
2494 // Fast case maps are never marked as shared.
2495 ASSERT(!HasFastProperties());
2496 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002497 Object* obj;
2498 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2499 UNIQUE_NORMALIZED_MAP);
2500 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2501 }
Steve Block44f0eee2011-05-26 01:26:41 +01002502 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002503
2504 set_map(Map::cast(obj));
2505 }
2506 return map()->UpdateCodeCache(name, code);
2507}
2508
2509
John Reck59135872010-11-02 12:39:01 -07002510MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2511 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002512 if (!HasFastProperties()) return this;
2513
2514 // The global object is always normalized.
2515 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002516 // JSGlobalProxy must never be normalized
2517 ASSERT(!IsJSGlobalProxy());
2518
Ben Murdoch8b112d22011-06-08 16:22:53 +01002519 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01002520
Steve Blocka7e24c12009-10-30 11:49:00 +00002521 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002522 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00002523 if (expected_additional_properties > 0) {
2524 property_count += expected_additional_properties;
2525 } else {
2526 property_count += 2; // Make space for two more properties.
2527 }
John Reck59135872010-11-02 12:39:01 -07002528 Object* obj;
2529 { MaybeObject* maybe_obj =
2530 StringDictionary::Allocate(property_count);
2531 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2532 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002533 StringDictionary* dictionary = StringDictionary::cast(obj);
2534
Ben Murdoch8b112d22011-06-08 16:22:53 +01002535 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002536 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002537 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00002538 switch (details.type()) {
2539 case CONSTANT_FUNCTION: {
2540 PropertyDetails d =
2541 PropertyDetails(details.attributes(), NORMAL, details.index());
2542 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07002543 Object* result;
2544 { MaybeObject* maybe_result =
2545 dictionary->Add(descs->GetKey(i), value, d);
2546 if (!maybe_result->ToObject(&result)) return maybe_result;
2547 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002548 dictionary = StringDictionary::cast(result);
2549 break;
2550 }
2551 case FIELD: {
2552 PropertyDetails d =
2553 PropertyDetails(details.attributes(), NORMAL, details.index());
2554 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07002555 Object* result;
2556 { MaybeObject* maybe_result =
2557 dictionary->Add(descs->GetKey(i), value, d);
2558 if (!maybe_result->ToObject(&result)) return maybe_result;
2559 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002560 dictionary = StringDictionary::cast(result);
2561 break;
2562 }
2563 case CALLBACKS: {
2564 PropertyDetails d =
2565 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2566 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07002567 Object* result;
2568 { MaybeObject* maybe_result =
2569 dictionary->Add(descs->GetKey(i), value, d);
2570 if (!maybe_result->ToObject(&result)) return maybe_result;
2571 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002572 dictionary = StringDictionary::cast(result);
2573 break;
2574 }
2575 case MAP_TRANSITION:
2576 case CONSTANT_TRANSITION:
2577 case NULL_DESCRIPTOR:
2578 case INTERCEPTOR:
2579 break;
2580 default:
2581 UNREACHABLE();
2582 }
2583 }
2584
Ben Murdoch8b112d22011-06-08 16:22:53 +01002585 Heap* current_heap = map_of_this->heap();
2586
Steve Blocka7e24c12009-10-30 11:49:00 +00002587 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002588 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002589 dictionary->SetNextEnumerationIndex(index);
2590
Ben Murdoch8b112d22011-06-08 16:22:53 +01002591 { MaybeObject* maybe_obj =
2592 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01002593 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07002594 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2595 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002596 Map* new_map = Map::cast(obj);
2597
Steve Blocka7e24c12009-10-30 11:49:00 +00002598 // We have now successfully allocated all the necessary objects.
2599 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002600
2601 // Resize the object in the heap if necessary.
2602 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002603 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002604 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002605 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2606 instance_size_delta);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002607
Steve Blocka7e24c12009-10-30 11:49:00 +00002608 set_map(new_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002609 new_map->set_instance_descriptors(current_heap->empty_descriptor_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00002610
2611 set_properties(dictionary);
2612
Ben Murdoch8b112d22011-06-08 16:22:53 +01002613 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002614
2615#ifdef DEBUG
2616 if (FLAG_trace_normalization) {
2617 PrintF("Object properties have been normalized:\n");
2618 Print();
2619 }
2620#endif
2621 return this;
2622}
2623
2624
John Reck59135872010-11-02 12:39:01 -07002625MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002626 if (HasFastProperties()) return this;
2627 ASSERT(!IsGlobalObject());
2628 return property_dictionary()->
2629 TransformPropertiesToFastFor(this, unused_property_fields);
2630}
2631
2632
John Reck59135872010-11-02 12:39:01 -07002633MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002634 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00002635 if (HasDictionaryElements()) return this;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002636 Map* old_map = map();
2637 ASSERT(old_map->has_fast_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01002638
John Reck59135872010-11-02 12:39:01 -07002639 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002640 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap();
John Reck59135872010-11-02 12:39:01 -07002641 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2642 }
Steve Block8defd9f2010-07-08 12:39:36 +01002643 Map* new_map = Map::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00002644
2645 // Get number of entries.
2646 FixedArray* array = FixedArray::cast(elements());
2647
2648 // Compute the effective length.
2649 int length = IsJSArray() ?
2650 Smi::cast(JSArray::cast(this)->length())->value() :
2651 array->length();
John Reck59135872010-11-02 12:39:01 -07002652 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length);
2653 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2654 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002655 NumberDictionary* dictionary = NumberDictionary::cast(obj);
2656 // Copy entries.
2657 for (int i = 0; i < length; i++) {
2658 Object* value = array->get(i);
2659 if (!value->IsTheHole()) {
2660 PropertyDetails details = PropertyDetails(NONE, NORMAL);
John Reck59135872010-11-02 12:39:01 -07002661 Object* result;
2662 { MaybeObject* maybe_result =
2663 dictionary->AddNumberEntry(i, array->get(i), details);
2664 if (!maybe_result->ToObject(&result)) return maybe_result;
2665 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002666 dictionary = NumberDictionary::cast(result);
2667 }
2668 }
Steve Block8defd9f2010-07-08 12:39:36 +01002669 // Switch to using the dictionary as the backing storage for
2670 // elements. Set the new map first to satify the elements type
2671 // assert in set_elements().
2672 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00002673 set_elements(dictionary);
2674
Ben Murdoch8b112d22011-06-08 16:22:53 +01002675 new_map->heap()->isolate()->counters()->elements_to_dictionary()->
Steve Block44f0eee2011-05-26 01:26:41 +01002676 Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002677
2678#ifdef DEBUG
2679 if (FLAG_trace_normalization) {
2680 PrintF("Object elements have been normalized:\n");
2681 Print();
2682 }
2683#endif
2684
2685 return this;
2686}
2687
2688
John Reck59135872010-11-02 12:39:01 -07002689MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
2690 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002691 // Check local property, ignore interceptor.
2692 LookupResult result;
2693 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002694 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002695
2696 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002697 Object* obj;
2698 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2699 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2700 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002701
2702 return DeleteNormalizedProperty(name, mode);
2703}
2704
2705
John Reck59135872010-11-02 12:39:01 -07002706MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01002707 Isolate* isolate = GetIsolate();
2708 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002709 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2710 Handle<String> name_handle(name);
2711 Handle<JSObject> this_handle(this);
2712 if (!interceptor->deleter()->IsUndefined()) {
2713 v8::NamedPropertyDeleter deleter =
2714 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01002715 LOG(isolate,
2716 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2717 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002718 v8::AccessorInfo info(args.end());
2719 v8::Handle<v8::Boolean> result;
2720 {
2721 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002722 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002723 result = deleter(v8::Utils::ToLocal(name_handle), info);
2724 }
Steve Block44f0eee2011-05-26 01:26:41 +01002725 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002726 if (!result.IsEmpty()) {
2727 ASSERT(result->IsBoolean());
2728 return *v8::Utils::OpenHandle(*result);
2729 }
2730 }
John Reck59135872010-11-02 12:39:01 -07002731 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00002732 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01002733 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002734 return raw_result;
2735}
2736
2737
John Reck59135872010-11-02 12:39:01 -07002738MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
2739 DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002740 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00002741 switch (GetElementsKind()) {
2742 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07002743 Object* obj;
2744 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2745 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2746 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002747 uint32_t length = IsJSArray() ?
2748 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2749 static_cast<uint32_t>(FixedArray::cast(elements())->length());
2750 if (index < length) {
2751 FixedArray::cast(elements())->set_the_hole(index);
2752 }
2753 break;
2754 }
2755 case DICTIONARY_ELEMENTS: {
2756 NumberDictionary* dictionary = element_dictionary();
2757 int entry = dictionary->FindEntry(index);
2758 if (entry != NumberDictionary::kNotFound) {
2759 return dictionary->DeleteProperty(entry, mode);
2760 }
2761 break;
2762 }
2763 default:
2764 UNREACHABLE();
2765 break;
2766 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01002767 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002768}
2769
2770
John Reck59135872010-11-02 12:39:01 -07002771MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01002772 Isolate* isolate = GetIsolate();
2773 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002774 // Make sure that the top context does not change when doing
2775 // callbacks or interceptor calls.
2776 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01002777 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002778 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01002779 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002780 v8::IndexedPropertyDeleter deleter =
2781 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
2782 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01002783 LOG(isolate,
2784 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
2785 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002786 v8::AccessorInfo info(args.end());
2787 v8::Handle<v8::Boolean> result;
2788 {
2789 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002790 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002791 result = deleter(index, info);
2792 }
Steve Block44f0eee2011-05-26 01:26:41 +01002793 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002794 if (!result.IsEmpty()) {
2795 ASSERT(result->IsBoolean());
2796 return *v8::Utils::OpenHandle(*result);
2797 }
John Reck59135872010-11-02 12:39:01 -07002798 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00002799 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01002800 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002801 return raw_result;
2802}
2803
2804
John Reck59135872010-11-02 12:39:01 -07002805MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002806 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002807 // Check access rights if needed.
2808 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002809 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
2810 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2811 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002812 }
2813
2814 if (IsJSGlobalProxy()) {
2815 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002816 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002817 ASSERT(proto->IsJSGlobalObject());
2818 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
2819 }
2820
2821 if (HasIndexedInterceptor()) {
2822 // Skip interceptor if forcing deletion.
2823 if (mode == FORCE_DELETION) {
2824 return DeleteElementPostInterceptor(index, mode);
2825 }
2826 return DeleteElementWithInterceptor(index);
2827 }
2828
2829 switch (GetElementsKind()) {
2830 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07002831 Object* obj;
2832 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2833 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2834 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002835 uint32_t length = IsJSArray() ?
2836 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2837 static_cast<uint32_t>(FixedArray::cast(elements())->length());
2838 if (index < length) {
2839 FixedArray::cast(elements())->set_the_hole(index);
2840 }
2841 break;
2842 }
Steve Block44f0eee2011-05-26 01:26:41 +01002843 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00002844 case EXTERNAL_BYTE_ELEMENTS:
2845 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2846 case EXTERNAL_SHORT_ELEMENTS:
2847 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2848 case EXTERNAL_INT_ELEMENTS:
2849 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2850 case EXTERNAL_FLOAT_ELEMENTS:
2851 // Pixel and external array elements cannot be deleted. Just
2852 // silently ignore here.
Steve Blocka7e24c12009-10-30 11:49:00 +00002853 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002854 case DICTIONARY_ELEMENTS: {
2855 NumberDictionary* dictionary = element_dictionary();
2856 int entry = dictionary->FindEntry(index);
2857 if (entry != NumberDictionary::kNotFound) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002858 Object* result = dictionary->DeleteProperty(entry, mode);
Steve Block44f0eee2011-05-26 01:26:41 +01002859 if (mode == STRICT_DELETION && result ==
2860 isolate->heap()->false_value()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002861 // In strict mode, deleting a non-configurable property throws
2862 // exception. dictionary->DeleteProperty will return false_value()
2863 // if a non-configurable property is being deleted.
2864 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01002865 Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002866 Handle<Object> args[2] = { i, Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01002867 return isolate->Throw(*isolate->factory()->NewTypeError(
2868 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002869 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002870 }
2871 break;
2872 }
2873 default:
2874 UNREACHABLE();
2875 break;
2876 }
Steve Block44f0eee2011-05-26 01:26:41 +01002877 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002878}
2879
2880
John Reck59135872010-11-02 12:39:01 -07002881MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002882 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002883 // ECMA-262, 3rd, 8.6.2.5
2884 ASSERT(name->IsString());
2885
2886 // Check access rights if needed.
2887 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002888 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
2889 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2890 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002891 }
2892
2893 if (IsJSGlobalProxy()) {
2894 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002895 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002896 ASSERT(proto->IsJSGlobalObject());
2897 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
2898 }
2899
2900 uint32_t index = 0;
2901 if (name->AsArrayIndex(&index)) {
2902 return DeleteElement(index, mode);
2903 } else {
2904 LookupResult result;
2905 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01002906 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002907 // Ignore attributes if forcing a deletion.
2908 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002909 if (mode == STRICT_DELETION) {
2910 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01002911 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002912 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01002913 return isolate->Throw(*isolate->factory()->NewTypeError(
2914 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002915 }
Steve Block44f0eee2011-05-26 01:26:41 +01002916 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002917 }
2918 // Check for interceptor.
2919 if (result.type() == INTERCEPTOR) {
2920 // Skip interceptor if forcing a deletion.
2921 if (mode == FORCE_DELETION) {
2922 return DeletePropertyPostInterceptor(name, mode);
2923 }
2924 return DeletePropertyWithInterceptor(name);
2925 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002926 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002927 Object* obj;
2928 { MaybeObject* maybe_obj =
2929 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2930 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2931 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002932 // Make sure the properties are normalized before removing the entry.
2933 return DeleteNormalizedProperty(name, mode);
2934 }
2935}
2936
2937
2938// Check whether this object references another object.
2939bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002940 Map* map_of_this = map();
2941 Heap* heap = map_of_this->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002942 AssertNoAllocation no_alloc;
2943
2944 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01002945 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002946 return true;
2947 }
2948
2949 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01002950 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002951 return true;
2952 }
2953
2954 // Check if the object is among the named properties.
2955 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01002956 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002957 return true;
2958 }
2959
2960 // Check if the object is among the indexed properties.
2961 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002962 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00002963 case EXTERNAL_BYTE_ELEMENTS:
2964 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2965 case EXTERNAL_SHORT_ELEMENTS:
2966 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2967 case EXTERNAL_INT_ELEMENTS:
2968 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2969 case EXTERNAL_FLOAT_ELEMENTS:
2970 // Raw pixels and external arrays do not reference other
2971 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00002972 break;
2973 case FAST_ELEMENTS: {
2974 int length = IsJSArray() ?
2975 Smi::cast(JSArray::cast(this)->length())->value() :
2976 FixedArray::cast(elements())->length();
2977 for (int i = 0; i < length; i++) {
2978 Object* element = FixedArray::cast(elements())->get(i);
2979 if (!element->IsTheHole() && element == obj) {
2980 return true;
2981 }
2982 }
2983 break;
2984 }
2985 case DICTIONARY_ELEMENTS: {
2986 key = element_dictionary()->SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01002987 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002988 return true;
2989 }
2990 break;
2991 }
2992 default:
2993 UNREACHABLE();
2994 break;
2995 }
2996
Steve Block6ded16b2010-05-10 14:33:55 +01002997 // For functions check the context.
2998 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002999 // Get the constructor function for arguments array.
3000 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01003001 heap->isolate()->context()->global_context()->
3002 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003003 JSFunction* arguments_function =
3004 JSFunction::cast(arguments_boilerplate->map()->constructor());
3005
3006 // Get the context and don't check if it is the global context.
3007 JSFunction* f = JSFunction::cast(this);
3008 Context* context = f->context();
3009 if (context->IsGlobalContext()) {
3010 return false;
3011 }
3012
3013 // Check the non-special context slots.
3014 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3015 // Only check JS objects.
3016 if (context->get(i)->IsJSObject()) {
3017 JSObject* ctxobj = JSObject::cast(context->get(i));
3018 // If it is an arguments array check the content.
3019 if (ctxobj->map()->constructor() == arguments_function) {
3020 if (ctxobj->ReferencesObject(obj)) {
3021 return true;
3022 }
3023 } else if (ctxobj == obj) {
3024 return true;
3025 }
3026 }
3027 }
3028
3029 // Check the context extension if any.
3030 if (context->has_extension()) {
3031 return context->extension()->ReferencesObject(obj);
3032 }
3033 }
3034
3035 // No references to object.
3036 return false;
3037}
3038
3039
John Reck59135872010-11-02 12:39:01 -07003040MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01003041 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003042 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003043 !isolate->MayNamedAccess(this,
3044 isolate->heap()->undefined_value(),
3045 v8::ACCESS_KEYS)) {
3046 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3047 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003048 }
3049
Steve Block1e0659c2011-05-24 12:43:12 +01003050 if (IsJSGlobalProxy()) {
3051 Object* proto = GetPrototype();
3052 if (proto->IsNull()) return this;
3053 ASSERT(proto->IsJSGlobalObject());
3054 return JSObject::cast(proto)->PreventExtensions();
3055 }
3056
Steve Block8defd9f2010-07-08 12:39:36 +01003057 // If there are fast elements we normalize.
3058 if (HasFastElements()) {
John Reck59135872010-11-02 12:39:01 -07003059 Object* ok;
3060 { MaybeObject* maybe_ok = NormalizeElements();
3061 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3062 }
Steve Block8defd9f2010-07-08 12:39:36 +01003063 }
3064 // Make sure that we never go back to fast case.
3065 element_dictionary()->set_requires_slow_elements();
3066
3067 // Do a map transition, other objects with this map may still
3068 // be extensible.
John Reck59135872010-11-02 12:39:01 -07003069 Object* new_map;
3070 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
3071 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3072 }
Steve Block8defd9f2010-07-08 12:39:36 +01003073 Map::cast(new_map)->set_is_extensible(false);
3074 set_map(Map::cast(new_map));
3075 ASSERT(!map()->is_extensible());
3076 return new_map;
3077}
3078
3079
Steve Blocka7e24c12009-10-30 11:49:00 +00003080// Tests for the fast common case for property enumeration:
Steve Blockd0582a62009-12-15 09:54:21 +00003081// - This object and all prototypes has an enum cache (which means that it has
3082// no interceptors and needs no access checks).
3083// - This object has no elements.
3084// - No prototype has enumerable properties/elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00003085bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003086 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003087 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003088 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003089 o = JSObject::cast(o)->GetPrototype()) {
3090 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003091 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003092 ASSERT(!curr->HasNamedInterceptor());
3093 ASSERT(!curr->HasIndexedInterceptor());
3094 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003095 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003096 if (curr != this) {
3097 FixedArray* curr_fixed_array =
3098 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003099 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003100 }
3101 }
3102 return true;
3103}
3104
3105
3106int Map::NumberOfDescribedProperties() {
3107 int result = 0;
3108 DescriptorArray* descs = instance_descriptors();
3109 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3110 if (descs->IsProperty(i)) result++;
3111 }
3112 return result;
3113}
3114
3115
3116int Map::PropertyIndexFor(String* name) {
3117 DescriptorArray* descs = instance_descriptors();
3118 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3119 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3120 return descs->GetFieldIndex(i);
3121 }
3122 }
3123 return -1;
3124}
3125
3126
3127int Map::NextFreePropertyIndex() {
3128 int max_index = -1;
3129 DescriptorArray* descs = instance_descriptors();
3130 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3131 if (descs->GetType(i) == FIELD) {
3132 int current_index = descs->GetFieldIndex(i);
3133 if (current_index > max_index) max_index = current_index;
3134 }
3135 }
3136 return max_index + 1;
3137}
3138
3139
3140AccessorDescriptor* Map::FindAccessor(String* name) {
3141 DescriptorArray* descs = instance_descriptors();
3142 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3143 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3144 return descs->GetCallbacks(i);
3145 }
3146 }
3147 return NULL;
3148}
3149
3150
3151void JSObject::LocalLookup(String* name, LookupResult* result) {
3152 ASSERT(name->IsString());
3153
Steve Block44f0eee2011-05-26 01:26:41 +01003154 Heap* heap = GetHeap();
3155
Steve Blocka7e24c12009-10-30 11:49:00 +00003156 if (IsJSGlobalProxy()) {
3157 Object* proto = GetPrototype();
3158 if (proto->IsNull()) return result->NotFound();
3159 ASSERT(proto->IsJSGlobalObject());
3160 return JSObject::cast(proto)->LocalLookup(name, result);
3161 }
3162
3163 // Do not use inline caching if the object is a non-global object
3164 // that requires access checks.
3165 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
3166 result->DisallowCaching();
3167 }
3168
3169 // Check __proto__ before interceptor.
Steve Block44f0eee2011-05-26 01:26:41 +01003170 if (name->Equals(heap->Proto_symbol()) &&
3171 !IsJSContextExtensionObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003172 result->ConstantResult(this);
3173 return;
3174 }
3175
3176 // Check for lookup interceptor except when bootstrapping.
Steve Block44f0eee2011-05-26 01:26:41 +01003177 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003178 result->InterceptorResult(this);
3179 return;
3180 }
3181
3182 LocalLookupRealNamedProperty(name, result);
3183}
3184
3185
3186void JSObject::Lookup(String* name, LookupResult* result) {
3187 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003188 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003189 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003190 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003191 current = JSObject::cast(current)->GetPrototype()) {
3192 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003193 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003194 }
3195 result->NotFound();
3196}
3197
3198
3199// Search object and it's prototype chain for callback properties.
3200void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003201 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003202 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003203 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003204 current = JSObject::cast(current)->GetPrototype()) {
3205 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003206 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003207 }
3208 result->NotFound();
3209}
3210
3211
John Reck59135872010-11-02 12:39:01 -07003212MaybeObject* JSObject::DefineGetterSetter(String* name,
3213 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003214 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003215 // Make sure that the top context does not change when doing callbacks or
3216 // interceptor calls.
3217 AssertNoContextChange ncc;
3218
Steve Blocka7e24c12009-10-30 11:49:00 +00003219 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01003220 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003221
Leon Clarkef7060e22010-06-03 12:02:55 +01003222 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003223 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003224 }
3225
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003226 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003227 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003228
3229 if (is_element) {
3230 switch (GetElementsKind()) {
3231 case FAST_ELEMENTS:
3232 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003233 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003234 case EXTERNAL_BYTE_ELEMENTS:
3235 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3236 case EXTERNAL_SHORT_ELEMENTS:
3237 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3238 case EXTERNAL_INT_ELEMENTS:
3239 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3240 case EXTERNAL_FLOAT_ELEMENTS:
3241 // Ignore getters and setters on pixel and external array
3242 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003243 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003244 case DICTIONARY_ELEMENTS: {
3245 // Lookup the index.
3246 NumberDictionary* dictionary = element_dictionary();
3247 int entry = dictionary->FindEntry(index);
3248 if (entry != NumberDictionary::kNotFound) {
3249 Object* result = dictionary->ValueAt(entry);
3250 PropertyDetails details = dictionary->DetailsAt(entry);
Steve Block44f0eee2011-05-26 01:26:41 +01003251 if (details.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003252 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003253 if (result->IsFixedArray()) {
3254 return result;
3255 }
3256 // Otherwise allow to override it.
Steve Blocka7e24c12009-10-30 11:49:00 +00003257 }
3258 }
3259 break;
3260 }
3261 default:
3262 UNREACHABLE();
3263 break;
3264 }
3265 } else {
3266 // Lookup the name.
3267 LookupResult result;
3268 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003269 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003270 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003271 if (result.type() == CALLBACKS) {
3272 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01003273 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00003274 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003275 // Use set to update attributes.
3276 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003277 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003278 }
3279 }
3280 }
3281
3282 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07003283 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01003284 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07003285 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3286 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003287
3288 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003289 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003290 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003291 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003292 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003293}
3294
3295
3296bool JSObject::CanSetCallback(String* name) {
3297 ASSERT(!IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01003298 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003299
3300 // Check if there is an API defined callback object which prohibits
3301 // callback overwriting in this object or it's prototype chain.
3302 // This mechanism is needed for instance in a browser setting, where
3303 // certain accessors such as window.location should not be allowed
3304 // to be overwritten because allowing overwriting could potentially
3305 // cause security problems.
3306 LookupResult callback_result;
3307 LookupCallback(name, &callback_result);
3308 if (callback_result.IsProperty()) {
3309 Object* obj = callback_result.GetCallbackObject();
3310 if (obj->IsAccessorInfo() &&
3311 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3312 return false;
3313 }
3314 }
3315
3316 return true;
3317}
3318
3319
John Reck59135872010-11-02 12:39:01 -07003320MaybeObject* JSObject::SetElementCallback(uint32_t index,
3321 Object* structure,
3322 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003323 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3324
3325 // Normalize elements to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003326 Object* ok;
3327 { MaybeObject* maybe_ok = NormalizeElements();
3328 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3329 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003330
3331 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003332 Object* dict;
3333 { MaybeObject* maybe_dict =
3334 element_dictionary()->Set(index, structure, details);
3335 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
3336 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003337
3338 NumberDictionary* elements = NumberDictionary::cast(dict);
3339 elements->set_requires_slow_elements();
3340 // Set the potential new dictionary on the object.
3341 set_elements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00003342
3343 return structure;
3344}
3345
3346
John Reck59135872010-11-02 12:39:01 -07003347MaybeObject* JSObject::SetPropertyCallback(String* name,
3348 Object* structure,
3349 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003350 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3351
3352 bool convert_back_to_fast = HasFastProperties() &&
3353 (map()->instance_descriptors()->number_of_descriptors()
3354 < DescriptorArray::kMaxNumberOfDescriptors);
3355
3356 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003357 Object* ok;
3358 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3359 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3360 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003361
3362 // For the global object allocate a new map to invalidate the global inline
3363 // caches which have a global property cell reference directly in the code.
3364 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07003365 Object* new_map;
3366 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3367 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3368 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003369 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003370 // When running crankshaft, changing the map is not enough. We
3371 // need to deoptimize all functions that rely on this global
3372 // object.
3373 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003374 }
3375
3376 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003377 Object* result;
3378 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3379 if (!maybe_result->ToObject(&result)) return maybe_result;
3380 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003381
3382 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07003383 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3384 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3385 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003386 }
3387 return result;
3388}
3389
John Reck59135872010-11-02 12:39:01 -07003390MaybeObject* JSObject::DefineAccessor(String* name,
3391 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01003392 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003393 PropertyAttributes attributes) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003394 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003395 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003396 // Check access rights if needed.
3397 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003398 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3399 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3400 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003401 }
3402
3403 if (IsJSGlobalProxy()) {
3404 Object* proto = GetPrototype();
3405 if (proto->IsNull()) return this;
3406 ASSERT(proto->IsJSGlobalObject());
3407 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3408 fun, attributes);
3409 }
3410
John Reck59135872010-11-02 12:39:01 -07003411 Object* array;
3412 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3413 if (!maybe_array->ToObject(&array)) return maybe_array;
3414 }
3415 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003416 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3417 return this;
3418}
3419
3420
John Reck59135872010-11-02 12:39:01 -07003421MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003422 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003423 String* name = String::cast(info->name());
3424 // Check access rights if needed.
3425 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003426 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3427 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3428 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003429 }
3430
3431 if (IsJSGlobalProxy()) {
3432 Object* proto = GetPrototype();
3433 if (proto->IsNull()) return this;
3434 ASSERT(proto->IsJSGlobalObject());
3435 return JSObject::cast(proto)->DefineAccessor(info);
3436 }
3437
3438 // Make sure that the top context does not change when doing callbacks or
3439 // interceptor calls.
3440 AssertNoContextChange ncc;
3441
3442 // Try to flatten before operating on the string.
3443 name->TryFlatten();
3444
3445 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003446 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003447 }
3448
3449 uint32_t index = 0;
3450 bool is_element = name->AsArrayIndex(&index);
3451
3452 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003453 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003454
3455 // Accessors overwrite previous callbacks (cf. with getters/setters).
3456 switch (GetElementsKind()) {
3457 case FAST_ELEMENTS:
3458 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003459 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003460 case EXTERNAL_BYTE_ELEMENTS:
3461 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3462 case EXTERNAL_SHORT_ELEMENTS:
3463 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3464 case EXTERNAL_INT_ELEMENTS:
3465 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3466 case EXTERNAL_FLOAT_ELEMENTS:
3467 // Ignore getters and setters on pixel and external array
3468 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003469 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003470 case DICTIONARY_ELEMENTS:
3471 break;
3472 default:
3473 UNREACHABLE();
3474 break;
3475 }
3476
John Reck59135872010-11-02 12:39:01 -07003477 Object* ok;
3478 { MaybeObject* maybe_ok =
3479 SetElementCallback(index, info, info->property_attributes());
3480 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3481 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003482 } else {
3483 // Lookup the name.
3484 LookupResult result;
3485 LocalLookup(name, &result);
3486 // ES5 forbids turning a property into an accessor if it's not
3487 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3488 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003489 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003490 }
John Reck59135872010-11-02 12:39:01 -07003491 Object* ok;
3492 { MaybeObject* maybe_ok =
3493 SetPropertyCallback(name, info, info->property_attributes());
3494 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3495 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003496 }
3497
3498 return this;
3499}
3500
3501
Steve Blocka7e24c12009-10-30 11:49:00 +00003502Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003503 Heap* heap = GetHeap();
3504
Steve Blocka7e24c12009-10-30 11:49:00 +00003505 // Make sure that the top context does not change when doing callbacks or
3506 // interceptor calls.
3507 AssertNoContextChange ncc;
3508
3509 // Check access rights if needed.
3510 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003511 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3512 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3513 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003514 }
3515
3516 // Make the lookup and include prototypes.
3517 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003518 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003519 if (name->AsArrayIndex(&index)) {
3520 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003521 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003522 obj = JSObject::cast(obj)->GetPrototype()) {
3523 JSObject* js_object = JSObject::cast(obj);
3524 if (js_object->HasDictionaryElements()) {
3525 NumberDictionary* dictionary = js_object->element_dictionary();
3526 int entry = dictionary->FindEntry(index);
3527 if (entry != NumberDictionary::kNotFound) {
3528 Object* element = dictionary->ValueAt(entry);
3529 PropertyDetails details = dictionary->DetailsAt(entry);
3530 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003531 if (element->IsFixedArray()) {
3532 return FixedArray::cast(element)->get(accessor_index);
3533 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003534 }
3535 }
3536 }
3537 }
3538 } else {
3539 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003540 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003541 obj = JSObject::cast(obj)->GetPrototype()) {
3542 LookupResult result;
3543 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003544 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003545 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003546 if (result.type() == CALLBACKS) {
3547 Object* obj = result.GetCallbackObject();
3548 if (obj->IsFixedArray()) {
3549 return FixedArray::cast(obj)->get(accessor_index);
3550 }
3551 }
3552 }
3553 }
3554 }
Steve Block44f0eee2011-05-26 01:26:41 +01003555 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003556}
3557
3558
3559Object* JSObject::SlowReverseLookup(Object* value) {
3560 if (HasFastProperties()) {
3561 DescriptorArray* descs = map()->instance_descriptors();
3562 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3563 if (descs->GetType(i) == FIELD) {
3564 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3565 return descs->GetKey(i);
3566 }
3567 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3568 if (descs->GetConstantFunction(i) == value) {
3569 return descs->GetKey(i);
3570 }
3571 }
3572 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003573 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003574 } else {
3575 return property_dictionary()->SlowReverseLookup(value);
3576 }
3577}
3578
3579
John Reck59135872010-11-02 12:39:01 -07003580MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01003581 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07003582 Object* result;
3583 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003584 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07003585 if (!maybe_result->ToObject(&result)) return maybe_result;
3586 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003587 Map::cast(result)->set_prototype(prototype());
3588 Map::cast(result)->set_constructor(constructor());
3589 // Don't copy descriptors, so map transitions always remain a forest.
3590 // If we retained the same descriptors we would have two maps
3591 // pointing to the same transition which is bad because the garbage
3592 // collector relies on being able to reverse pointers from transitions
3593 // to maps. If properties need to be retained use CopyDropTransitions.
Steve Block44f0eee2011-05-26 01:26:41 +01003594 Map::cast(result)->set_instance_descriptors(
3595 heap->empty_descriptor_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00003596 // Please note instance_type and instance_size are set when allocated.
3597 Map::cast(result)->set_inobject_properties(inobject_properties());
3598 Map::cast(result)->set_unused_property_fields(unused_property_fields());
3599
3600 // If the map has pre-allocated properties always start out with a descriptor
3601 // array describing these properties.
3602 if (pre_allocated_property_fields() > 0) {
3603 ASSERT(constructor()->IsJSFunction());
3604 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07003605 Object* descriptors;
3606 { MaybeObject* maybe_descriptors =
3607 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
3608 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3609 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003610 Map::cast(result)->set_instance_descriptors(
3611 DescriptorArray::cast(descriptors));
3612 Map::cast(result)->set_pre_allocated_property_fields(
3613 pre_allocated_property_fields());
3614 }
3615 Map::cast(result)->set_bit_field(bit_field());
3616 Map::cast(result)->set_bit_field2(bit_field2());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003617 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01003618 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00003619 return result;
3620}
3621
3622
John Reck59135872010-11-02 12:39:01 -07003623MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
3624 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003625 int new_instance_size = instance_size();
3626 if (mode == CLEAR_INOBJECT_PROPERTIES) {
3627 new_instance_size -= inobject_properties() * kPointerSize;
3628 }
3629
John Reck59135872010-11-02 12:39:01 -07003630 Object* result;
3631 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003632 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07003633 if (!maybe_result->ToObject(&result)) return maybe_result;
3634 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003635
3636 if (mode != CLEAR_INOBJECT_PROPERTIES) {
3637 Map::cast(result)->set_inobject_properties(inobject_properties());
3638 }
3639
3640 Map::cast(result)->set_prototype(prototype());
3641 Map::cast(result)->set_constructor(constructor());
3642
3643 Map::cast(result)->set_bit_field(bit_field());
3644 Map::cast(result)->set_bit_field2(bit_field2());
3645
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003646 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
3647
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003648#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003649 if (Map::cast(result)->is_shared()) {
3650 Map::cast(result)->SharedMapVerify();
3651 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003652#endif
3653
3654 return result;
3655}
3656
3657
John Reck59135872010-11-02 12:39:01 -07003658MaybeObject* Map::CopyDropTransitions() {
3659 Object* new_map;
3660 { MaybeObject* maybe_new_map = CopyDropDescriptors();
3661 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3662 }
3663 Object* descriptors;
3664 { MaybeObject* maybe_descriptors =
3665 instance_descriptors()->RemoveTransitions();
3666 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3667 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003668 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01003669 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003670}
3671
3672
John Reck59135872010-11-02 12:39:01 -07003673MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003674 // Allocate the code cache if not present.
3675 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07003676 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +01003677 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07003678 if (!maybe_result->ToObject(&result)) return maybe_result;
3679 }
Steve Block6ded16b2010-05-10 14:33:55 +01003680 set_code_cache(result);
3681 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003682
Steve Block6ded16b2010-05-10 14:33:55 +01003683 // Update the code cache.
3684 return CodeCache::cast(code_cache())->Update(name, code);
3685}
3686
3687
3688Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3689 // Do a lookup if a code cache exists.
3690 if (!code_cache()->IsFixedArray()) {
3691 return CodeCache::cast(code_cache())->Lookup(name, flags);
3692 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003693 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003694 }
3695}
3696
3697
3698int Map::IndexInCodeCache(Object* name, Code* code) {
3699 // Get the internal index if a code cache exists.
3700 if (!code_cache()->IsFixedArray()) {
3701 return CodeCache::cast(code_cache())->GetIndex(name, code);
3702 }
3703 return -1;
3704}
3705
3706
3707void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3708 // No GC is supposed to happen between a call to IndexInCodeCache and
3709 // RemoveFromCodeCache so the code cache must be there.
3710 ASSERT(!code_cache()->IsFixedArray());
3711 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3712}
3713
3714
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003715void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Steve Block053d10c2011-06-13 19:13:29 +01003716 // Traverse the transition tree without using a stack. We do this by
3717 // reversing the pointers in the maps and descriptor arrays.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003718 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003719 Map* meta_map = heap()->meta_map();
Steve Block053d10c2011-06-13 19:13:29 +01003720 Object** map_or_index_field = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01003721 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003722 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
3723 *RawField(current, Map::kInstanceDescriptorsOffset));
Steve Block053d10c2011-06-13 19:13:29 +01003724 if (!d->IsEmpty()) {
3725 FixedArray* contents = reinterpret_cast<FixedArray*>(
3726 d->get(DescriptorArray::kContentArrayIndex));
3727 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3728 Object* map_or_index = *map_or_index_field;
3729 bool map_done = true; // Controls a nested continue statement.
3730 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3731 i < contents->length();
3732 i += 2) {
3733 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3734 if (details.IsTransition()) {
3735 // Found a map in the transition array. We record our progress in
3736 // the transition array by recording the current map in the map field
3737 // of the next map and recording the index in the transition array in
3738 // the map field of the array.
3739 Map* next = Map::cast(contents->get(i));
3740 next->set_map(current);
3741 *map_or_index_field = Smi::FromInt(i + 2);
3742 current = next;
3743 map_done = false;
3744 break;
3745 }
3746 }
3747 if (!map_done) continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003748 }
Steve Block053d10c2011-06-13 19:13:29 +01003749 // That was the regular transitions, now for the prototype transitions.
3750 FixedArray* prototype_transitions =
3751 current->unchecked_prototype_transitions();
3752 Object** proto_map_or_index_field =
3753 RawField(prototype_transitions, HeapObject::kMapOffset);
3754 Object* map_or_index = *proto_map_or_index_field;
3755 const int start = 2;
3756 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
3757 if (i < prototype_transitions->length()) {
3758 // Found a map in the prototype transition array. Record progress in
3759 // an analogous way to the regular transitions array above.
3760 Object* perhaps_map = prototype_transitions->get(i);
3761 if (perhaps_map->IsMap()) {
3762 Map* next = Map::cast(perhaps_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003763 next->set_map(current);
Steve Block053d10c2011-06-13 19:13:29 +01003764 *proto_map_or_index_field =
3765 Smi::FromInt(i + 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003766 current = next;
Steve Block053d10c2011-06-13 19:13:29 +01003767 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003768 }
3769 }
Steve Block053d10c2011-06-13 19:13:29 +01003770 *proto_map_or_index_field = heap()->fixed_array_map();
3771 if (map_or_index_field != NULL) {
3772 *map_or_index_field = heap()->fixed_array_map();
3773 }
3774
3775 // The callback expects a map to have a real map as its map, so we save
3776 // the map field, which is being used to track the traversal and put the
3777 // correct map (the meta_map) in place while we do the callback.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003778 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003779 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003780 callback(current, data);
3781 current = prev;
3782 }
3783}
3784
3785
John Reck59135872010-11-02 12:39:01 -07003786MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003787 ASSERT(code->ic_state() == MONOMORPHIC);
3788
3789 // The number of monomorphic stubs for normal load/store/call IC's can grow to
3790 // a large number and therefore they need to go into a hash table. They are
3791 // used to load global properties from cells.
3792 if (code->type() == NORMAL) {
3793 // Make sure that a hash table is allocated for the normal load code cache.
3794 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07003795 Object* result;
3796 { MaybeObject* maybe_result =
3797 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
3798 if (!maybe_result->ToObject(&result)) return maybe_result;
3799 }
Steve Block6ded16b2010-05-10 14:33:55 +01003800 set_normal_type_cache(result);
3801 }
3802 return UpdateNormalTypeCache(name, code);
3803 } else {
3804 ASSERT(default_cache()->IsFixedArray());
3805 return UpdateDefaultCache(name, code);
3806 }
3807}
3808
3809
John Reck59135872010-11-02 12:39:01 -07003810MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003811 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00003812 // flags. This allows call constant stubs to overwrite call field
3813 // stubs, etc.
3814 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
3815
3816 // First check whether we can update existing code cache without
3817 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01003818 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003819 int length = cache->length();
3820 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01003821 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003822 Object* key = cache->get(i);
3823 if (key->IsNull()) {
3824 if (deleted_index < 0) deleted_index = i;
3825 continue;
3826 }
3827 if (key->IsUndefined()) {
3828 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01003829 cache->set(i + kCodeCacheEntryNameOffset, name);
3830 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003831 return this;
3832 }
3833 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003834 Code::Flags found =
3835 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00003836 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01003837 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003838 return this;
3839 }
3840 }
3841 }
3842
3843 // Reached the end of the code cache. If there were deleted
3844 // elements, reuse the space for the first of them.
3845 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01003846 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
3847 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003848 return this;
3849 }
3850
Steve Block6ded16b2010-05-10 14:33:55 +01003851 // Extend the code cache with some new entries (at least one). Must be a
3852 // multiple of the entry size.
3853 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
3854 new_length = new_length - new_length % kCodeCacheEntrySize;
3855 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07003856 Object* result;
3857 { MaybeObject* maybe_result = cache->CopySize(new_length);
3858 if (!maybe_result->ToObject(&result)) return maybe_result;
3859 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003860
3861 // Add the (name, code) pair to the new cache.
3862 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01003863 cache->set(length + kCodeCacheEntryNameOffset, name);
3864 cache->set(length + kCodeCacheEntryCodeOffset, code);
3865 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00003866 return this;
3867}
3868
3869
John Reck59135872010-11-02 12:39:01 -07003870MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003871 // Adding a new entry can cause a new cache to be allocated.
3872 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07003873 Object* new_cache;
3874 { MaybeObject* maybe_new_cache = cache->Put(name, code);
3875 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
3876 }
Steve Block6ded16b2010-05-10 14:33:55 +01003877 set_normal_type_cache(new_cache);
3878 return this;
3879}
3880
3881
3882Object* CodeCache::Lookup(String* name, Code::Flags flags) {
3883 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
3884 return LookupNormalTypeCache(name, flags);
3885 } else {
3886 return LookupDefaultCache(name, flags);
3887 }
3888}
3889
3890
3891Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
3892 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003893 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003894 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
3895 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00003896 // Skip deleted elements.
3897 if (key->IsNull()) continue;
3898 if (key->IsUndefined()) return key;
3899 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003900 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
3901 if (code->flags() == flags) {
3902 return code;
3903 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003904 }
3905 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003906 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003907}
3908
3909
Steve Block6ded16b2010-05-10 14:33:55 +01003910Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
3911 if (!normal_type_cache()->IsUndefined()) {
3912 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3913 return cache->Lookup(name, flags);
3914 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003915 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003916 }
3917}
3918
3919
3920int CodeCache::GetIndex(Object* name, Code* code) {
3921 if (code->type() == NORMAL) {
3922 if (normal_type_cache()->IsUndefined()) return -1;
3923 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3924 return cache->GetIndex(String::cast(name), code->flags());
3925 }
3926
3927 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003928 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003929 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
3930 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00003931 }
3932 return -1;
3933}
3934
3935
Steve Block6ded16b2010-05-10 14:33:55 +01003936void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
3937 if (code->type() == NORMAL) {
3938 ASSERT(!normal_type_cache()->IsUndefined());
3939 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3940 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
3941 cache->RemoveByIndex(index);
3942 } else {
3943 FixedArray* array = default_cache();
3944 ASSERT(array->length() >= index && array->get(index)->IsCode());
3945 // Use null instead of undefined for deleted elements to distinguish
3946 // deleted elements from unused elements. This distinction is used
3947 // when looking up in the cache and when updating the cache.
3948 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
3949 array->set_null(index - 1); // Name.
3950 array->set_null(index); // Code.
3951 }
3952}
3953
3954
3955// The key in the code cache hash table consists of the property name and the
3956// code object. The actual match is on the name and the code flags. If a key
3957// is created using the flags and not a code object it can only be used for
3958// lookup not to create a new entry.
3959class CodeCacheHashTableKey : public HashTableKey {
3960 public:
3961 CodeCacheHashTableKey(String* name, Code::Flags flags)
3962 : name_(name), flags_(flags), code_(NULL) { }
3963
3964 CodeCacheHashTableKey(String* name, Code* code)
3965 : name_(name),
3966 flags_(code->flags()),
3967 code_(code) { }
3968
3969
3970 bool IsMatch(Object* other) {
3971 if (!other->IsFixedArray()) return false;
3972 FixedArray* pair = FixedArray::cast(other);
3973 String* name = String::cast(pair->get(0));
3974 Code::Flags flags = Code::cast(pair->get(1))->flags();
3975 if (flags != flags_) {
3976 return false;
3977 }
3978 return name_->Equals(name);
3979 }
3980
3981 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
3982 return name->Hash() ^ flags;
3983 }
3984
3985 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
3986
3987 uint32_t HashForObject(Object* obj) {
3988 FixedArray* pair = FixedArray::cast(obj);
3989 String* name = String::cast(pair->get(0));
3990 Code* code = Code::cast(pair->get(1));
3991 return NameFlagsHashHelper(name, code->flags());
3992 }
3993
John Reck59135872010-11-02 12:39:01 -07003994 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01003995 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07003996 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01003997 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07003998 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3999 }
Steve Block6ded16b2010-05-10 14:33:55 +01004000 FixedArray* pair = FixedArray::cast(obj);
4001 pair->set(0, name_);
4002 pair->set(1, code_);
4003 return pair;
4004 }
4005
4006 private:
4007 String* name_;
4008 Code::Flags flags_;
4009 Code* code_;
4010};
4011
4012
4013Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4014 CodeCacheHashTableKey key(name, flags);
4015 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01004016 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004017 return get(EntryToIndex(entry) + 1);
4018}
4019
4020
John Reck59135872010-11-02 12:39:01 -07004021MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004022 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07004023 Object* obj;
4024 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4025 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4026 }
Steve Block6ded16b2010-05-10 14:33:55 +01004027
4028 // Don't use this, as the table might have grown.
4029 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4030
4031 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004032 Object* k;
4033 { MaybeObject* maybe_k = key.AsObject();
4034 if (!maybe_k->ToObject(&k)) return maybe_k;
4035 }
Steve Block6ded16b2010-05-10 14:33:55 +01004036
4037 cache->set(EntryToIndex(entry), k);
4038 cache->set(EntryToIndex(entry) + 1, code);
4039 cache->ElementAdded();
4040 return cache;
4041}
4042
4043
4044int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4045 CodeCacheHashTableKey key(name, flags);
4046 int entry = FindEntry(&key);
4047 return (entry == kNotFound) ? -1 : entry;
4048}
4049
4050
4051void CodeCacheHashTable::RemoveByIndex(int index) {
4052 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004053 Heap* heap = GetHeap();
4054 set(EntryToIndex(index), heap->null_value());
4055 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004056 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004057}
4058
4059
Steve Blocka7e24c12009-10-30 11:49:00 +00004060static bool HasKey(FixedArray* array, Object* key) {
4061 int len0 = array->length();
4062 for (int i = 0; i < len0; i++) {
4063 Object* element = array->get(i);
4064 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4065 if (element->IsString() &&
4066 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4067 return true;
4068 }
4069 }
4070 return false;
4071}
4072
4073
John Reck59135872010-11-02 12:39:01 -07004074MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Steve Block44f0eee2011-05-26 01:26:41 +01004075 ASSERT(!array->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00004076 switch (array->GetElementsKind()) {
4077 case JSObject::FAST_ELEMENTS:
4078 return UnionOfKeys(FixedArray::cast(array->elements()));
4079 case JSObject::DICTIONARY_ELEMENTS: {
4080 NumberDictionary* dict = array->element_dictionary();
4081 int size = dict->NumberOfElements();
4082
4083 // Allocate a temporary fixed array.
John Reck59135872010-11-02 12:39:01 -07004084 Object* object;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004085 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
John Reck59135872010-11-02 12:39:01 -07004086 if (!maybe_object->ToObject(&object)) return maybe_object;
4087 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004088 FixedArray* key_array = FixedArray::cast(object);
4089
4090 int capacity = dict->Capacity();
4091 int pos = 0;
4092 // Copy the elements from the JSArray to the temporary fixed array.
4093 for (int i = 0; i < capacity; i++) {
4094 if (dict->IsKey(dict->KeyAt(i))) {
4095 key_array->set(pos++, dict->ValueAt(i));
4096 }
4097 }
4098 // Compute the union of this and the temporary fixed array.
4099 return UnionOfKeys(key_array);
4100 }
4101 default:
4102 UNREACHABLE();
4103 }
4104 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01004105 return GetHeap()->null_value(); // Failure case needs to "return" a value.
Steve Blocka7e24c12009-10-30 11:49:00 +00004106}
4107
4108
John Reck59135872010-11-02 12:39:01 -07004109MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004110 int len0 = length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004111#ifdef DEBUG
4112 if (FLAG_enable_slow_asserts) {
4113 for (int i = 0; i < len0; i++) {
4114 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4115 }
4116 }
4117#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004118 int len1 = other->length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004119 // Optimize if 'other' is empty.
4120 // We cannot optimize if 'this' is empty, as other may have holes
4121 // or non keys.
Steve Blocka7e24c12009-10-30 11:49:00 +00004122 if (len1 == 0) return this;
4123
4124 // Compute how many elements are not in this.
4125 int extra = 0;
4126 for (int y = 0; y < len1; y++) {
4127 Object* value = other->get(y);
4128 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
4129 }
4130
4131 if (extra == 0) return this;
4132
4133 // Allocate the result
John Reck59135872010-11-02 12:39:01 -07004134 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004135 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
John Reck59135872010-11-02 12:39:01 -07004136 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4137 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004138 // Fill in the content
Leon Clarke4515c472010-02-03 11:58:03 +00004139 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004140 FixedArray* result = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00004141 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004142 for (int i = 0; i < len0; i++) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004143 Object* e = get(i);
4144 ASSERT(e->IsString() || e->IsNumber());
4145 result->set(i, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004146 }
4147 // Fill in the extra keys.
4148 int index = 0;
4149 for (int y = 0; y < len1; y++) {
4150 Object* value = other->get(y);
4151 if (!value->IsTheHole() && !HasKey(this, value)) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004152 Object* e = other->get(y);
4153 ASSERT(e->IsString() || e->IsNumber());
4154 result->set(len0 + index, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004155 index++;
4156 }
4157 }
4158 ASSERT(extra == index);
4159 return result;
4160}
4161
4162
John Reck59135872010-11-02 12:39:01 -07004163MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004164 Heap* heap = GetHeap();
4165 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004166 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004167 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004168 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4169 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004170 FixedArray* result = FixedArray::cast(obj);
4171 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004172 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004173 int len = length();
4174 if (new_length < len) len = new_length;
4175 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004176 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004177 for (int i = 0; i < len; i++) {
4178 result->set(i, get(i), mode);
4179 }
4180 return result;
4181}
4182
4183
4184void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004185 AssertNoAllocation no_gc;
4186 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004187 for (int index = 0; index < len; index++) {
4188 dest->set(dest_pos+index, get(pos+index), mode);
4189 }
4190}
4191
4192
4193#ifdef DEBUG
4194bool FixedArray::IsEqualTo(FixedArray* other) {
4195 if (length() != other->length()) return false;
4196 for (int i = 0 ; i < length(); ++i) {
4197 if (get(i) != other->get(i)) return false;
4198 }
4199 return true;
4200}
4201#endif
4202
4203
John Reck59135872010-11-02 12:39:01 -07004204MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004205 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004206 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004207 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004208 }
4209 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004210 Object* array;
4211 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004212 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004213 if (!maybe_array->ToObject(&array)) return maybe_array;
4214 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004215 // Do not use DescriptorArray::cast on incomplete object.
4216 FixedArray* result = FixedArray::cast(array);
4217
4218 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004219 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004220 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004221 if (!maybe_array->ToObject(&array)) return maybe_array;
4222 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004223 result->set(kContentArrayIndex, array);
4224 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004225 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004226 return result;
4227}
4228
4229
4230void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4231 FixedArray* new_cache) {
4232 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4233 if (HasEnumCache()) {
4234 FixedArray::cast(get(kEnumerationIndexIndex))->
4235 set(kEnumCacheBridgeCacheIndex, new_cache);
4236 } else {
4237 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4238 FixedArray::cast(bridge_storage)->
4239 set(kEnumCacheBridgeCacheIndex, new_cache);
4240 fast_set(FixedArray::cast(bridge_storage),
4241 kEnumCacheBridgeEnumIndex,
4242 get(kEnumerationIndexIndex));
4243 set(kEnumerationIndexIndex, bridge_storage);
4244 }
4245}
4246
4247
John Reck59135872010-11-02 12:39:01 -07004248MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4249 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004250 // Transitions are only kept when inserting another transition.
4251 // This precondition is not required by this function's implementation, but
4252 // is currently required by the semantics of maps, so we check it.
4253 // Conversely, we filter after replacing, so replacing a transition and
4254 // removing all other transitions is not supported.
4255 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4256 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4257 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4258
4259 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004260 Object* result;
4261 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4262 if (!maybe_result->ToObject(&result)) return maybe_result;
4263 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004264
4265 int transitions = 0;
4266 int null_descriptors = 0;
4267 if (remove_transitions) {
4268 for (int i = 0; i < number_of_descriptors(); i++) {
4269 if (IsTransition(i)) transitions++;
4270 if (IsNullDescriptor(i)) null_descriptors++;
4271 }
4272 } else {
4273 for (int i = 0; i < number_of_descriptors(); i++) {
4274 if (IsNullDescriptor(i)) null_descriptors++;
4275 }
4276 }
4277 int new_size = number_of_descriptors() - transitions - null_descriptors;
4278
4279 // If key is in descriptor, we replace it in-place when filtering.
4280 // Count a null descriptor for key as inserted, not replaced.
4281 int index = Search(descriptor->GetKey());
4282 const bool inserting = (index == kNotFound);
4283 const bool replacing = !inserting;
4284 bool keep_enumeration_index = false;
4285 if (inserting) {
4286 ++new_size;
4287 }
4288 if (replacing) {
4289 // We are replacing an existing descriptor. We keep the enumeration
4290 // index of a visible property.
4291 PropertyType t = PropertyDetails(GetDetails(index)).type();
4292 if (t == CONSTANT_FUNCTION ||
4293 t == FIELD ||
4294 t == CALLBACKS ||
4295 t == INTERCEPTOR) {
4296 keep_enumeration_index = true;
4297 } else if (remove_transitions) {
4298 // Replaced descriptor has been counted as removed if it is
4299 // a transition that will be replaced. Adjust count in this case.
4300 ++new_size;
4301 }
4302 }
John Reck59135872010-11-02 12:39:01 -07004303 { MaybeObject* maybe_result = Allocate(new_size);
4304 if (!maybe_result->ToObject(&result)) return maybe_result;
4305 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004306 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4307 // Set the enumeration index in the descriptors and set the enumeration index
4308 // in the result.
4309 int enumeration_index = NextEnumerationIndex();
4310 if (!descriptor->GetDetails().IsTransition()) {
4311 if (keep_enumeration_index) {
4312 descriptor->SetEnumerationIndex(
4313 PropertyDetails(GetDetails(index)).index());
4314 } else {
4315 descriptor->SetEnumerationIndex(enumeration_index);
4316 ++enumeration_index;
4317 }
4318 }
4319 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4320
4321 // Copy the descriptors, filtering out transitions and null descriptors,
4322 // and inserting or replacing a descriptor.
4323 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4324 int from_index = 0;
4325 int to_index = 0;
4326
4327 for (; from_index < number_of_descriptors(); from_index++) {
4328 String* key = GetKey(from_index);
4329 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4330 break;
4331 }
4332 if (IsNullDescriptor(from_index)) continue;
4333 if (remove_transitions && IsTransition(from_index)) continue;
4334 new_descriptors->CopyFrom(to_index++, this, from_index);
4335 }
4336
4337 new_descriptors->Set(to_index++, descriptor);
4338 if (replacing) from_index++;
4339
4340 for (; from_index < number_of_descriptors(); from_index++) {
4341 if (IsNullDescriptor(from_index)) continue;
4342 if (remove_transitions && IsTransition(from_index)) continue;
4343 new_descriptors->CopyFrom(to_index++, this, from_index);
4344 }
4345
4346 ASSERT(to_index == new_descriptors->number_of_descriptors());
4347 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4348
4349 return new_descriptors;
4350}
4351
4352
John Reck59135872010-11-02 12:39:01 -07004353MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004354 // Remove all transitions and null descriptors. Return a copy of the array
4355 // with all transitions removed, or a Failure object if the new array could
4356 // not be allocated.
4357
4358 // Compute the size of the map transition entries to be removed.
4359 int num_removed = 0;
4360 for (int i = 0; i < number_of_descriptors(); i++) {
4361 if (!IsProperty(i)) num_removed++;
4362 }
4363
4364 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07004365 Object* result;
4366 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4367 if (!maybe_result->ToObject(&result)) return maybe_result;
4368 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004369 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4370
4371 // Copy the content.
4372 int next_descriptor = 0;
4373 for (int i = 0; i < number_of_descriptors(); i++) {
4374 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
4375 }
4376 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4377
4378 return new_descriptors;
4379}
4380
4381
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004382void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004383 // In-place heap sort.
4384 int len = number_of_descriptors();
4385
4386 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004387 // Index of the last node with children
4388 const int max_parent_index = (len / 2) - 1;
4389 for (int i = max_parent_index; i >= 0; --i) {
4390 int parent_index = i;
4391 const uint32_t parent_hash = GetKey(i)->Hash();
4392 while (parent_index <= max_parent_index) {
4393 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004394 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004395 if (child_index + 1 < len) {
4396 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4397 if (right_child_hash > child_hash) {
4398 child_index++;
4399 child_hash = right_child_hash;
4400 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004401 }
Steve Block6ded16b2010-05-10 14:33:55 +01004402 if (child_hash <= parent_hash) break;
4403 Swap(parent_index, child_index);
4404 // Now element at child_index could be < its children.
4405 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004406 }
4407 }
4408
4409 // Extract elements and create sorted array.
4410 for (int i = len - 1; i > 0; --i) {
4411 // Put max element at the back of the array.
4412 Swap(0, i);
4413 // Sift down the new top element.
4414 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004415 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4416 const int max_parent_index = (i / 2) - 1;
4417 while (parent_index <= max_parent_index) {
4418 int child_index = parent_index * 2 + 1;
4419 uint32_t child_hash = GetKey(child_index)->Hash();
4420 if (child_index + 1 < i) {
4421 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4422 if (right_child_hash > child_hash) {
4423 child_index++;
4424 child_hash = right_child_hash;
4425 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004426 }
Steve Block6ded16b2010-05-10 14:33:55 +01004427 if (child_hash <= parent_hash) break;
4428 Swap(parent_index, child_index);
4429 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004430 }
4431 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004432}
Steve Blocka7e24c12009-10-30 11:49:00 +00004433
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004434
4435void DescriptorArray::Sort() {
4436 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004437 SLOW_ASSERT(IsSortedNoDuplicates());
4438}
4439
4440
4441int DescriptorArray::BinarySearch(String* name, int low, int high) {
4442 uint32_t hash = name->Hash();
4443
4444 while (low <= high) {
4445 int mid = (low + high) / 2;
4446 String* mid_name = GetKey(mid);
4447 uint32_t mid_hash = mid_name->Hash();
4448
4449 if (mid_hash > hash) {
4450 high = mid - 1;
4451 continue;
4452 }
4453 if (mid_hash < hash) {
4454 low = mid + 1;
4455 continue;
4456 }
4457 // Found an element with the same hash-code.
4458 ASSERT(hash == mid_hash);
4459 // There might be more, so we find the first one and
4460 // check them all to see if we have a match.
4461 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4462 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4463 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4464 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4465 }
4466 break;
4467 }
4468 return kNotFound;
4469}
4470
4471
4472int DescriptorArray::LinearSearch(String* name, int len) {
4473 uint32_t hash = name->Hash();
4474 for (int number = 0; number < len; number++) {
4475 String* entry = GetKey(number);
4476 if ((entry->Hash() == hash) &&
4477 name->Equals(entry) &&
4478 !is_null_descriptor(number)) {
4479 return number;
4480 }
4481 }
4482 return kNotFound;
4483}
4484
4485
Ben Murdochb0fe1622011-05-05 13:52:32 +01004486MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4487 PretenureFlag pretenure) {
4488 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004489 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004490 pretenure);
4491}
4492
4493
4494MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
4495 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01004496 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
4497 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004498 pretenure);
4499}
4500
4501
Steve Blocka7e24c12009-10-30 11:49:00 +00004502#ifdef DEBUG
4503bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
4504 if (IsEmpty()) return other->IsEmpty();
4505 if (other->IsEmpty()) return false;
4506 if (length() != other->length()) return false;
4507 for (int i = 0; i < length(); ++i) {
4508 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
4509 }
4510 return GetContentArray()->IsEqualTo(other->GetContentArray());
4511}
4512#endif
4513
4514
Steve Blocka7e24c12009-10-30 11:49:00 +00004515bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01004516 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004517 return true;
4518}
4519
4520
4521int String::Utf8Length() {
4522 if (IsAsciiRepresentation()) return length();
4523 // Attempt to flatten before accessing the string. It probably
4524 // doesn't make Utf8Length faster, but it is very likely that
4525 // the string will be accessed later (for example by WriteUtf8)
4526 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01004527 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01004528 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01004529 Access<StringInputBuffer> buffer(
4530 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004531 buffer->Reset(0, this);
4532 int result = 0;
4533 while (buffer->has_more())
4534 result += unibrow::Utf8::Length(buffer->GetNext());
4535 return result;
4536}
4537
4538
4539Vector<const char> String::ToAsciiVector() {
4540 ASSERT(IsAsciiRepresentation());
4541 ASSERT(IsFlat());
4542
4543 int offset = 0;
4544 int length = this->length();
4545 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4546 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004547 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004548 ConsString* cons = ConsString::cast(string);
4549 ASSERT(cons->second()->length() == 0);
4550 string = cons->first();
4551 string_tag = StringShape(string).representation_tag();
4552 }
4553 if (string_tag == kSeqStringTag) {
4554 SeqAsciiString* seq = SeqAsciiString::cast(string);
4555 char* start = seq->GetChars();
4556 return Vector<const char>(start + offset, length);
4557 }
4558 ASSERT(string_tag == kExternalStringTag);
4559 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
4560 const char* start = ext->resource()->data();
4561 return Vector<const char>(start + offset, length);
4562}
4563
4564
4565Vector<const uc16> String::ToUC16Vector() {
4566 ASSERT(IsTwoByteRepresentation());
4567 ASSERT(IsFlat());
4568
4569 int offset = 0;
4570 int length = this->length();
4571 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4572 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004573 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004574 ConsString* cons = ConsString::cast(string);
4575 ASSERT(cons->second()->length() == 0);
4576 string = cons->first();
4577 string_tag = StringShape(string).representation_tag();
4578 }
4579 if (string_tag == kSeqStringTag) {
4580 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
4581 return Vector<const uc16>(seq->GetChars() + offset, length);
4582 }
4583 ASSERT(string_tag == kExternalStringTag);
4584 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
4585 const uc16* start =
4586 reinterpret_cast<const uc16*>(ext->resource()->data());
4587 return Vector<const uc16>(start + offset, length);
4588}
4589
4590
4591SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4592 RobustnessFlag robust_flag,
4593 int offset,
4594 int length,
4595 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004596 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4597 return SmartPointer<char>(NULL);
4598 }
Steve Block44f0eee2011-05-26 01:26:41 +01004599 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004600
4601 // Negative length means the to the end of the string.
4602 if (length < 0) length = kMaxInt - offset;
4603
4604 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01004605 Access<StringInputBuffer> buffer(
4606 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004607 buffer->Reset(offset, this);
4608 int character_position = offset;
4609 int utf8_bytes = 0;
4610 while (buffer->has_more()) {
4611 uint16_t character = buffer->GetNext();
4612 if (character_position < offset + length) {
4613 utf8_bytes += unibrow::Utf8::Length(character);
4614 }
4615 character_position++;
4616 }
4617
4618 if (length_return) {
4619 *length_return = utf8_bytes;
4620 }
4621
4622 char* result = NewArray<char>(utf8_bytes + 1);
4623
4624 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
4625 buffer->Rewind();
4626 buffer->Seek(offset);
4627 character_position = offset;
4628 int utf8_byte_position = 0;
4629 while (buffer->has_more()) {
4630 uint16_t character = buffer->GetNext();
4631 if (character_position < offset + length) {
4632 if (allow_nulls == DISALLOW_NULLS && character == 0) {
4633 character = ' ';
4634 }
4635 utf8_byte_position +=
4636 unibrow::Utf8::Encode(result + utf8_byte_position, character);
4637 }
4638 character_position++;
4639 }
4640 result[utf8_byte_position] = 0;
4641 return SmartPointer<char>(result);
4642}
4643
4644
4645SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4646 RobustnessFlag robust_flag,
4647 int* length_return) {
4648 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
4649}
4650
4651
4652const uc16* String::GetTwoByteData() {
4653 return GetTwoByteData(0);
4654}
4655
4656
4657const uc16* String::GetTwoByteData(unsigned start) {
4658 ASSERT(!IsAsciiRepresentation());
4659 switch (StringShape(this).representation_tag()) {
4660 case kSeqStringTag:
4661 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
4662 case kExternalStringTag:
4663 return ExternalTwoByteString::cast(this)->
4664 ExternalTwoByteStringGetData(start);
Steve Blocka7e24c12009-10-30 11:49:00 +00004665 case kConsStringTag:
4666 UNREACHABLE();
4667 return NULL;
4668 }
4669 UNREACHABLE();
4670 return NULL;
4671}
4672
4673
4674SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004675 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4676 return SmartPointer<uc16>();
4677 }
Steve Block44f0eee2011-05-26 01:26:41 +01004678 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004679
Steve Block44f0eee2011-05-26 01:26:41 +01004680 Access<StringInputBuffer> buffer(
4681 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004682 buffer->Reset(this);
4683
4684 uc16* result = NewArray<uc16>(length() + 1);
4685
4686 int i = 0;
4687 while (buffer->has_more()) {
4688 uint16_t character = buffer->GetNext();
4689 result[i++] = character;
4690 }
4691 result[i] = 0;
4692 return SmartPointer<uc16>(result);
4693}
4694
4695
4696const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
4697 return reinterpret_cast<uc16*>(
4698 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
4699}
4700
4701
4702void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4703 unsigned* offset_ptr,
4704 unsigned max_chars) {
4705 unsigned chars_read = 0;
4706 unsigned offset = *offset_ptr;
4707 while (chars_read < max_chars) {
4708 uint16_t c = *reinterpret_cast<uint16_t*>(
4709 reinterpret_cast<char*>(this) -
4710 kHeapObjectTag + kHeaderSize + offset * kShortSize);
4711 if (c <= kMaxAsciiCharCode) {
4712 // Fast case for ASCII characters. Cursor is an input output argument.
4713 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4714 rbb->util_buffer,
4715 rbb->capacity,
4716 rbb->cursor)) {
4717 break;
4718 }
4719 } else {
4720 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4721 rbb->util_buffer,
4722 rbb->capacity,
4723 rbb->cursor)) {
4724 break;
4725 }
4726 }
4727 offset++;
4728 chars_read++;
4729 }
4730 *offset_ptr = offset;
4731 rbb->remaining += chars_read;
4732}
4733
4734
4735const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
4736 unsigned* remaining,
4737 unsigned* offset_ptr,
4738 unsigned max_chars) {
4739 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
4740 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
4741 *remaining = max_chars;
4742 *offset_ptr += max_chars;
4743 return b;
4744}
4745
4746
4747// This will iterate unless the block of string data spans two 'halves' of
4748// a ConsString, in which case it will recurse. Since the block of string
4749// data to be read has a maximum size this limits the maximum recursion
4750// depth to something sane. Since C++ does not have tail call recursion
4751// elimination, the iteration must be explicit. Since this is not an
4752// -IntoBuffer method it can delegate to one of the efficient
4753// *AsciiStringReadBlock routines.
4754const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
4755 unsigned* offset_ptr,
4756 unsigned max_chars) {
4757 ConsString* current = this;
4758 unsigned offset = *offset_ptr;
4759 int offset_correction = 0;
4760
4761 while (true) {
4762 String* left = current->first();
4763 unsigned left_length = (unsigned)left->length();
4764 if (left_length > offset &&
4765 (max_chars <= left_length - offset ||
4766 (rbb->capacity <= left_length - offset &&
4767 (max_chars = left_length - offset, true)))) { // comma operator!
4768 // Left hand side only - iterate unless we have reached the bottom of
4769 // the cons tree. The assignment on the left of the comma operator is
4770 // in order to make use of the fact that the -IntoBuffer routines can
4771 // produce at most 'capacity' characters. This enables us to postpone
4772 // the point where we switch to the -IntoBuffer routines (below) in order
4773 // to maximize the chances of delegating a big chunk of work to the
4774 // efficient *AsciiStringReadBlock routines.
4775 if (StringShape(left).IsCons()) {
4776 current = ConsString::cast(left);
4777 continue;
4778 } else {
4779 const unibrow::byte* answer =
4780 String::ReadBlock(left, rbb, &offset, max_chars);
4781 *offset_ptr = offset + offset_correction;
4782 return answer;
4783 }
4784 } else if (left_length <= offset) {
4785 // Right hand side only - iterate unless we have reached the bottom of
4786 // the cons tree.
4787 String* right = current->second();
4788 offset -= left_length;
4789 offset_correction += left_length;
4790 if (StringShape(right).IsCons()) {
4791 current = ConsString::cast(right);
4792 continue;
4793 } else {
4794 const unibrow::byte* answer =
4795 String::ReadBlock(right, rbb, &offset, max_chars);
4796 *offset_ptr = offset + offset_correction;
4797 return answer;
4798 }
4799 } else {
4800 // The block to be read spans two sides of the ConsString, so we call the
4801 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
4802 // are able to assemble data from several part strings because they use
4803 // the util_buffer to store their data and never return direct pointers
4804 // to their storage. We don't try to read more than the buffer capacity
4805 // here or we can get too much recursion.
4806 ASSERT(rbb->remaining == 0);
4807 ASSERT(rbb->cursor == 0);
4808 current->ConsStringReadBlockIntoBuffer(
4809 rbb,
4810 &offset,
4811 max_chars > rbb->capacity ? rbb->capacity : max_chars);
4812 *offset_ptr = offset + offset_correction;
4813 return rbb->util_buffer;
4814 }
4815 }
4816}
4817
4818
Steve Blocka7e24c12009-10-30 11:49:00 +00004819uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
4820 ASSERT(index >= 0 && index < length());
4821 return resource()->data()[index];
4822}
4823
4824
4825const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
4826 unsigned* remaining,
4827 unsigned* offset_ptr,
4828 unsigned max_chars) {
4829 // Cast const char* to unibrow::byte* (signedness difference).
4830 const unibrow::byte* b =
4831 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
4832 *remaining = max_chars;
4833 *offset_ptr += max_chars;
4834 return b;
4835}
4836
4837
4838const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
4839 unsigned start) {
4840 return resource()->data() + start;
4841}
4842
4843
4844uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
4845 ASSERT(index >= 0 && index < length());
4846 return resource()->data()[index];
4847}
4848
4849
4850void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
4851 ReadBlockBuffer* rbb,
4852 unsigned* offset_ptr,
4853 unsigned max_chars) {
4854 unsigned chars_read = 0;
4855 unsigned offset = *offset_ptr;
4856 const uint16_t* data = resource()->data();
4857 while (chars_read < max_chars) {
4858 uint16_t c = data[offset];
4859 if (c <= kMaxAsciiCharCode) {
4860 // Fast case for ASCII characters. Cursor is an input output argument.
4861 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4862 rbb->util_buffer,
4863 rbb->capacity,
4864 rbb->cursor))
4865 break;
4866 } else {
4867 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4868 rbb->util_buffer,
4869 rbb->capacity,
4870 rbb->cursor))
4871 break;
4872 }
4873 offset++;
4874 chars_read++;
4875 }
4876 *offset_ptr = offset;
4877 rbb->remaining += chars_read;
4878}
4879
4880
4881void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4882 unsigned* offset_ptr,
4883 unsigned max_chars) {
4884 unsigned capacity = rbb->capacity - rbb->cursor;
4885 if (max_chars > capacity) max_chars = capacity;
4886 memcpy(rbb->util_buffer + rbb->cursor,
4887 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
4888 *offset_ptr * kCharSize,
4889 max_chars);
4890 rbb->remaining += max_chars;
4891 *offset_ptr += max_chars;
4892 rbb->cursor += max_chars;
4893}
4894
4895
4896void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
4897 ReadBlockBuffer* rbb,
4898 unsigned* offset_ptr,
4899 unsigned max_chars) {
4900 unsigned capacity = rbb->capacity - rbb->cursor;
4901 if (max_chars > capacity) max_chars = capacity;
4902 memcpy(rbb->util_buffer + rbb->cursor,
4903 resource()->data() + *offset_ptr,
4904 max_chars);
4905 rbb->remaining += max_chars;
4906 *offset_ptr += max_chars;
4907 rbb->cursor += max_chars;
4908}
4909
4910
4911// This method determines the type of string involved and then copies
4912// a whole chunk of characters into a buffer, or returns a pointer to a buffer
4913// where they can be found. The pointer is not necessarily valid across a GC
4914// (see AsciiStringReadBlock).
4915const unibrow::byte* String::ReadBlock(String* input,
4916 ReadBlockBuffer* rbb,
4917 unsigned* offset_ptr,
4918 unsigned max_chars) {
4919 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
4920 if (max_chars == 0) {
4921 rbb->remaining = 0;
4922 return NULL;
4923 }
4924 switch (StringShape(input).representation_tag()) {
4925 case kSeqStringTag:
4926 if (input->IsAsciiRepresentation()) {
4927 SeqAsciiString* str = SeqAsciiString::cast(input);
4928 return str->SeqAsciiStringReadBlock(&rbb->remaining,
4929 offset_ptr,
4930 max_chars);
4931 } else {
4932 SeqTwoByteString* str = SeqTwoByteString::cast(input);
4933 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
4934 offset_ptr,
4935 max_chars);
4936 return rbb->util_buffer;
4937 }
4938 case kConsStringTag:
4939 return ConsString::cast(input)->ConsStringReadBlock(rbb,
4940 offset_ptr,
4941 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00004942 case kExternalStringTag:
4943 if (input->IsAsciiRepresentation()) {
4944 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
4945 &rbb->remaining,
4946 offset_ptr,
4947 max_chars);
4948 } else {
4949 ExternalTwoByteString::cast(input)->
4950 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
4951 offset_ptr,
4952 max_chars);
4953 return rbb->util_buffer;
4954 }
4955 default:
4956 break;
4957 }
4958
4959 UNREACHABLE();
4960 return 0;
4961}
4962
4963
Steve Blocka7e24c12009-10-30 11:49:00 +00004964void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01004965 Isolate* isolate = Isolate::Current();
4966 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00004967 while (current != NULL) {
4968 current->PostGarbageCollection();
4969 current = current->prev_;
4970 }
4971}
4972
4973
4974// Reserve space for statics needing saving and restoring.
4975int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01004976 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00004977}
4978
4979
4980// Archive statics that are thread local.
4981char* Relocatable::ArchiveState(char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01004982 Isolate* isolate = Isolate::Current();
4983 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
4984 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00004985 return to + ArchiveSpacePerThread();
4986}
4987
4988
4989// Restore statics that are thread local.
4990char* Relocatable::RestoreState(char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01004991 Isolate* isolate = Isolate::Current();
4992 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00004993 return from + ArchiveSpacePerThread();
4994}
4995
4996
4997char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
4998 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
4999 Iterate(v, top);
5000 return thread_storage + ArchiveSpacePerThread();
5001}
5002
5003
5004void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01005005 Isolate* isolate = Isolate::Current();
5006 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005007}
5008
5009
5010void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5011 Relocatable* current = top;
5012 while (current != NULL) {
5013 current->IterateInstance(v);
5014 current = current->prev_;
5015 }
5016}
5017
5018
Steve Block44f0eee2011-05-26 01:26:41 +01005019FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5020 : Relocatable(isolate),
5021 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00005022 length_(str->length()) {
5023 PostGarbageCollection();
5024}
5025
5026
Steve Block44f0eee2011-05-26 01:26:41 +01005027FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5028 : Relocatable(isolate),
5029 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005030 is_ascii_(true),
5031 length_(input.length()),
5032 start_(input.start()) { }
5033
5034
5035void FlatStringReader::PostGarbageCollection() {
5036 if (str_ == NULL) return;
5037 Handle<String> str(str_);
5038 ASSERT(str->IsFlat());
5039 is_ascii_ = str->IsAsciiRepresentation();
5040 if (is_ascii_) {
5041 start_ = str->ToAsciiVector().start();
5042 } else {
5043 start_ = str->ToUC16Vector().start();
5044 }
5045}
5046
5047
5048void StringInputBuffer::Seek(unsigned pos) {
5049 Reset(pos, input_);
5050}
5051
5052
5053void SafeStringInputBuffer::Seek(unsigned pos) {
5054 Reset(pos, input_);
5055}
5056
5057
5058// This method determines the type of string involved and then copies
5059// a whole chunk of characters into a buffer. It can be used with strings
5060// that have been glued together to form a ConsString and which must cooperate
5061// to fill up a buffer.
5062void String::ReadBlockIntoBuffer(String* input,
5063 ReadBlockBuffer* rbb,
5064 unsigned* offset_ptr,
5065 unsigned max_chars) {
5066 ASSERT(*offset_ptr <= (unsigned)input->length());
5067 if (max_chars == 0) return;
5068
5069 switch (StringShape(input).representation_tag()) {
5070 case kSeqStringTag:
5071 if (input->IsAsciiRepresentation()) {
5072 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5073 offset_ptr,
5074 max_chars);
5075 return;
5076 } else {
5077 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5078 offset_ptr,
5079 max_chars);
5080 return;
5081 }
5082 case kConsStringTag:
5083 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5084 offset_ptr,
5085 max_chars);
5086 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005087 case kExternalStringTag:
5088 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005089 ExternalAsciiString::cast(input)->
5090 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5091 } else {
5092 ExternalTwoByteString::cast(input)->
5093 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5094 offset_ptr,
5095 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005096 }
5097 return;
5098 default:
5099 break;
5100 }
5101
5102 UNREACHABLE();
5103 return;
5104}
5105
5106
5107const unibrow::byte* String::ReadBlock(String* input,
5108 unibrow::byte* util_buffer,
5109 unsigned capacity,
5110 unsigned* remaining,
5111 unsigned* offset_ptr) {
5112 ASSERT(*offset_ptr <= (unsigned)input->length());
5113 unsigned chars = input->length() - *offset_ptr;
5114 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5115 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5116 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5117 *remaining = rbb.remaining;
5118 return answer;
5119}
5120
5121
5122const unibrow::byte* String::ReadBlock(String** raw_input,
5123 unibrow::byte* util_buffer,
5124 unsigned capacity,
5125 unsigned* remaining,
5126 unsigned* offset_ptr) {
5127 Handle<String> input(raw_input);
5128 ASSERT(*offset_ptr <= (unsigned)input->length());
5129 unsigned chars = input->length() - *offset_ptr;
5130 if (chars > capacity) chars = capacity;
5131 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5132 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5133 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5134 *remaining = rbb.remaining;
5135 return rbb.util_buffer;
5136}
5137
5138
5139// This will iterate unless the block of string data spans two 'halves' of
5140// a ConsString, in which case it will recurse. Since the block of string
5141// data to be read has a maximum size this limits the maximum recursion
5142// depth to something sane. Since C++ does not have tail call recursion
5143// elimination, the iteration must be explicit.
5144void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5145 unsigned* offset_ptr,
5146 unsigned max_chars) {
5147 ConsString* current = this;
5148 unsigned offset = *offset_ptr;
5149 int offset_correction = 0;
5150
5151 while (true) {
5152 String* left = current->first();
5153 unsigned left_length = (unsigned)left->length();
5154 if (left_length > offset &&
5155 max_chars <= left_length - offset) {
5156 // Left hand side only - iterate unless we have reached the bottom of
5157 // the cons tree.
5158 if (StringShape(left).IsCons()) {
5159 current = ConsString::cast(left);
5160 continue;
5161 } else {
5162 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5163 *offset_ptr = offset + offset_correction;
5164 return;
5165 }
5166 } else if (left_length <= offset) {
5167 // Right hand side only - iterate unless we have reached the bottom of
5168 // the cons tree.
5169 offset -= left_length;
5170 offset_correction += left_length;
5171 String* right = current->second();
5172 if (StringShape(right).IsCons()) {
5173 current = ConsString::cast(right);
5174 continue;
5175 } else {
5176 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5177 *offset_ptr = offset + offset_correction;
5178 return;
5179 }
5180 } else {
5181 // The block to be read spans two sides of the ConsString, so we recurse.
5182 // First recurse on the left.
5183 max_chars -= left_length - offset;
5184 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5185 // We may have reached the max or there may not have been enough space
5186 // in the buffer for the characters in the left hand side.
5187 if (offset == left_length) {
5188 // Recurse on the right.
5189 String* right = String::cast(current->second());
5190 offset -= left_length;
5191 offset_correction += left_length;
5192 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5193 }
5194 *offset_ptr = offset + offset_correction;
5195 return;
5196 }
5197 }
5198}
5199
5200
Steve Blocka7e24c12009-10-30 11:49:00 +00005201uint16_t ConsString::ConsStringGet(int index) {
5202 ASSERT(index >= 0 && index < this->length());
5203
5204 // Check for a flattened cons string
5205 if (second()->length() == 0) {
5206 String* left = first();
5207 return left->Get(index);
5208 }
5209
5210 String* string = String::cast(this);
5211
5212 while (true) {
5213 if (StringShape(string).IsCons()) {
5214 ConsString* cons_string = ConsString::cast(string);
5215 String* left = cons_string->first();
5216 if (left->length() > index) {
5217 string = left;
5218 } else {
5219 index -= left->length();
5220 string = cons_string->second();
5221 }
5222 } else {
5223 return string->Get(index);
5224 }
5225 }
5226
5227 UNREACHABLE();
5228 return 0;
5229}
5230
5231
5232template <typename sinkchar>
5233void String::WriteToFlat(String* src,
5234 sinkchar* sink,
5235 int f,
5236 int t) {
5237 String* source = src;
5238 int from = f;
5239 int to = t;
5240 while (true) {
5241 ASSERT(0 <= from && from <= to && to <= source->length());
5242 switch (StringShape(source).full_representation_tag()) {
5243 case kAsciiStringTag | kExternalStringTag: {
5244 CopyChars(sink,
5245 ExternalAsciiString::cast(source)->resource()->data() + from,
5246 to - from);
5247 return;
5248 }
5249 case kTwoByteStringTag | kExternalStringTag: {
5250 const uc16* data =
5251 ExternalTwoByteString::cast(source)->resource()->data();
5252 CopyChars(sink,
5253 data + from,
5254 to - from);
5255 return;
5256 }
5257 case kAsciiStringTag | kSeqStringTag: {
5258 CopyChars(sink,
5259 SeqAsciiString::cast(source)->GetChars() + from,
5260 to - from);
5261 return;
5262 }
5263 case kTwoByteStringTag | kSeqStringTag: {
5264 CopyChars(sink,
5265 SeqTwoByteString::cast(source)->GetChars() + from,
5266 to - from);
5267 return;
5268 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005269 case kAsciiStringTag | kConsStringTag:
5270 case kTwoByteStringTag | kConsStringTag: {
5271 ConsString* cons_string = ConsString::cast(source);
5272 String* first = cons_string->first();
5273 int boundary = first->length();
5274 if (to - boundary >= boundary - from) {
5275 // Right hand side is longer. Recurse over left.
5276 if (from < boundary) {
5277 WriteToFlat(first, sink, from, boundary);
5278 sink += boundary - from;
5279 from = 0;
5280 } else {
5281 from -= boundary;
5282 }
5283 to -= boundary;
5284 source = cons_string->second();
5285 } else {
5286 // Left hand side is longer. Recurse over right.
5287 if (to > boundary) {
5288 String* second = cons_string->second();
5289 WriteToFlat(second,
5290 sink + boundary - from,
5291 0,
5292 to - boundary);
5293 to = boundary;
5294 }
5295 source = first;
5296 }
5297 break;
5298 }
5299 }
5300 }
5301}
5302
5303
Steve Blocka7e24c12009-10-30 11:49:00 +00005304template <typename IteratorA, typename IteratorB>
5305static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5306 // General slow case check. We know that the ia and ib iterators
5307 // have the same length.
5308 while (ia->has_more()) {
5309 uc32 ca = ia->GetNext();
5310 uc32 cb = ib->GetNext();
5311 if (ca != cb)
5312 return false;
5313 }
5314 return true;
5315}
5316
5317
5318// Compares the contents of two strings by reading and comparing
5319// int-sized blocks of characters.
5320template <typename Char>
5321static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5322 int length = a.length();
5323 ASSERT_EQ(length, b.length());
5324 const Char* pa = a.start();
5325 const Char* pb = b.start();
5326 int i = 0;
5327#ifndef V8_HOST_CAN_READ_UNALIGNED
5328 // If this architecture isn't comfortable reading unaligned ints
5329 // then we have to check that the strings are aligned before
5330 // comparing them blockwise.
5331 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5332 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5333 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5334 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5335#endif
5336 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5337 int endpoint = length - kStepSize;
5338 // Compare blocks until we reach near the end of the string.
5339 for (; i <= endpoint; i += kStepSize) {
5340 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5341 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5342 if (wa != wb) {
5343 return false;
5344 }
5345 }
5346#ifndef V8_HOST_CAN_READ_UNALIGNED
5347 }
5348#endif
5349 // Compare the remaining characters that didn't fit into a block.
5350 for (; i < length; i++) {
5351 if (a[i] != b[i]) {
5352 return false;
5353 }
5354 }
5355 return true;
5356}
5357
5358
Steve Blocka7e24c12009-10-30 11:49:00 +00005359template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005360static inline bool CompareStringContentsPartial(Isolate* isolate,
5361 IteratorA* ia,
5362 String* b) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005363 if (b->IsFlat()) {
5364 if (b->IsAsciiRepresentation()) {
5365 VectorIterator<char> ib(b->ToAsciiVector());
5366 return CompareStringContents(ia, &ib);
5367 } else {
5368 VectorIterator<uc16> ib(b->ToUC16Vector());
5369 return CompareStringContents(ia, &ib);
5370 }
5371 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005372 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5373 return CompareStringContents(ia,
5374 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005375 }
5376}
5377
5378
Steve Blocka7e24c12009-10-30 11:49:00 +00005379bool String::SlowEquals(String* other) {
5380 // Fast check: negative check with lengths.
5381 int len = length();
5382 if (len != other->length()) return false;
5383 if (len == 0) return true;
5384
5385 // Fast check: if hash code is computed for both strings
5386 // a fast negative check can be performed.
5387 if (HasHashCode() && other->HasHashCode()) {
5388 if (Hash() != other->Hash()) return false;
5389 }
5390
Leon Clarkef7060e22010-06-03 12:02:55 +01005391 // We know the strings are both non-empty. Compare the first chars
5392 // before we try to flatten the strings.
5393 if (this->Get(0) != other->Get(0)) return false;
5394
5395 String* lhs = this->TryFlattenGetString();
5396 String* rhs = other->TryFlattenGetString();
5397
5398 if (StringShape(lhs).IsSequentialAscii() &&
5399 StringShape(rhs).IsSequentialAscii()) {
5400 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5401 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005402 return CompareRawStringContents(Vector<const char>(str1, len),
5403 Vector<const char>(str2, len));
5404 }
5405
Steve Block44f0eee2011-05-26 01:26:41 +01005406 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01005407 if (lhs->IsFlat()) {
Ben Murdochbb769b22010-08-11 14:56:33 +01005408 if (lhs->IsAsciiRepresentation()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01005409 Vector<const char> vec1 = lhs->ToAsciiVector();
5410 if (rhs->IsFlat()) {
5411 if (rhs->IsAsciiRepresentation()) {
5412 Vector<const char> vec2 = rhs->ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005413 return CompareRawStringContents(vec1, vec2);
5414 } else {
5415 VectorIterator<char> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005416 VectorIterator<uc16> ib(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005417 return CompareStringContents(&buf1, &ib);
5418 }
5419 } else {
5420 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005421 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5422 return CompareStringContents(&buf1,
5423 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005424 }
5425 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005426 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5427 if (rhs->IsFlat()) {
5428 if (rhs->IsAsciiRepresentation()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005429 VectorIterator<uc16> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005430 VectorIterator<char> ib(rhs->ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005431 return CompareStringContents(&buf1, &ib);
5432 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005433 Vector<const uc16> vec2(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005434 return CompareRawStringContents(vec1, vec2);
5435 }
5436 } else {
5437 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005438 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5439 return CompareStringContents(&buf1,
5440 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005441 }
5442 }
5443 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005444 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5445 return CompareStringContentsPartial(isolate,
5446 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00005447 }
5448}
5449
5450
5451bool String::MarkAsUndetectable() {
5452 if (StringShape(this).IsSymbol()) return false;
5453
5454 Map* map = this->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005455 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01005456 if (map == heap->string_map()) {
5457 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005458 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01005459 } else if (map == heap->ascii_string_map()) {
5460 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005461 return true;
5462 }
5463 // Rest cannot be marked as undetectable
5464 return false;
5465}
5466
5467
5468bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01005469 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00005470 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005471 Access<UnicodeCache::Utf8Decoder>
5472 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00005473 decoder->Reset(str.start(), str.length());
5474 int i;
5475 for (i = 0; i < slen && decoder->has_more(); i++) {
5476 uc32 r = decoder->GetNext();
5477 if (Get(i) != r) return false;
5478 }
5479 return i == slen && !decoder->has_more();
5480}
5481
5482
Steve Block9fac8402011-05-12 15:51:54 +01005483bool String::IsAsciiEqualTo(Vector<const char> str) {
5484 int slen = length();
5485 if (str.length() != slen) return false;
5486 for (int i = 0; i < slen; i++) {
5487 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
5488 }
5489 return true;
5490}
5491
5492
5493bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
5494 int slen = length();
5495 if (str.length() != slen) return false;
5496 for (int i = 0; i < slen; i++) {
5497 if (Get(i) != str[i]) return false;
5498 }
5499 return true;
5500}
5501
5502
Steve Blocka7e24c12009-10-30 11:49:00 +00005503uint32_t String::ComputeAndSetHash() {
5504 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005505 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005506
Steve Block6ded16b2010-05-10 14:33:55 +01005507 const int len = length();
5508
Steve Blocka7e24c12009-10-30 11:49:00 +00005509 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01005510 uint32_t field = 0;
5511 if (StringShape(this).IsSequentialAscii()) {
5512 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
5513 } else if (StringShape(this).IsSequentialTwoByte()) {
5514 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
5515 } else {
5516 StringInputBuffer buffer(this);
5517 field = ComputeHashField(&buffer, len);
5518 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005519
5520 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00005521 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00005522
5523 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005524 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005525 uint32_t result = field >> kHashShift;
5526 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
5527 return result;
5528}
5529
5530
5531bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
5532 uint32_t* index,
5533 int length) {
5534 if (length == 0 || length > kMaxArrayIndexSize) return false;
5535 uc32 ch = buffer->GetNext();
5536
5537 // If the string begins with a '0' character, it must only consist
5538 // of it to be a legal array index.
5539 if (ch == '0') {
5540 *index = 0;
5541 return length == 1;
5542 }
5543
5544 // Convert string to uint32 array index; character by character.
5545 int d = ch - '0';
5546 if (d < 0 || d > 9) return false;
5547 uint32_t result = d;
5548 while (buffer->has_more()) {
5549 d = buffer->GetNext() - '0';
5550 if (d < 0 || d > 9) return false;
5551 // Check that the new result is below the 32 bit limit.
5552 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
5553 result = (result * 10) + d;
5554 }
5555
5556 *index = result;
5557 return true;
5558}
5559
5560
5561bool String::SlowAsArrayIndex(uint32_t* index) {
5562 if (length() <= kMaxCachedArrayIndexLength) {
5563 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00005564 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005565 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00005566 // Isolate the array index form the full hash field.
5567 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00005568 return true;
5569 } else {
5570 StringInputBuffer buffer(this);
5571 return ComputeArrayIndex(&buffer, index, length());
5572 }
5573}
5574
5575
Iain Merrick9ac36c92010-09-13 15:29:50 +01005576uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005577 // For array indexes mix the length into the hash as an array index could
5578 // be zero.
5579 ASSERT(length > 0);
5580 ASSERT(length <= String::kMaxArrayIndexSize);
5581 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5582 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01005583
5584 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005585 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01005586
5587 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
5588 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
5589 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005590 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00005591}
5592
5593
5594uint32_t StringHasher::GetHashField() {
5595 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00005596 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005597 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005598 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00005599 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005600 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005601 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005602 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005603 }
5604}
5605
5606
Steve Blockd0582a62009-12-15 09:54:21 +00005607uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
5608 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005609 StringHasher hasher(length);
5610
5611 // Very long strings have a trivial hash that doesn't inspect the
5612 // string contents.
5613 if (hasher.has_trivial_hash()) {
5614 return hasher.GetHashField();
5615 }
5616
5617 // Do the iterative array index computation as long as there is a
5618 // chance this is an array index.
5619 while (buffer->has_more() && hasher.is_array_index()) {
5620 hasher.AddCharacter(buffer->GetNext());
5621 }
5622
5623 // Process the remaining characters without updating the array
5624 // index.
5625 while (buffer->has_more()) {
5626 hasher.AddCharacterNoIndex(buffer->GetNext());
5627 }
5628
5629 return hasher.GetHashField();
5630}
5631
5632
John Reck59135872010-11-02 12:39:01 -07005633MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005634 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005635 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01005636 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00005637 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005638}
5639
5640
5641void String::PrintOn(FILE* file) {
5642 int length = this->length();
5643 for (int i = 0; i < length; i++) {
5644 fprintf(file, "%c", Get(i));
5645 }
5646}
5647
5648
5649void Map::CreateBackPointers() {
5650 DescriptorArray* descriptors = instance_descriptors();
5651 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01005652 if (descriptors->GetType(i) == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005653 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005654 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005655 // Get target.
5656 Map* target = Map::cast(descriptors->GetValue(i));
5657#ifdef DEBUG
5658 // Verify target.
5659 Object* source_prototype = prototype();
5660 Object* target_prototype = target->prototype();
5661 ASSERT(source_prototype->IsJSObject() ||
5662 source_prototype->IsMap() ||
5663 source_prototype->IsNull());
5664 ASSERT(target_prototype->IsJSObject() ||
5665 target_prototype->IsNull());
5666 ASSERT(source_prototype->IsMap() ||
5667 source_prototype == target_prototype);
5668#endif
5669 // Point target back to source. set_prototype() will not let us set
5670 // the prototype to a map, as we do here.
5671 *RawField(target, kPrototypeOffset) = this;
5672 }
5673 }
5674}
5675
5676
Steve Block44f0eee2011-05-26 01:26:41 +01005677void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005678 // Live DescriptorArray objects will be marked, so we must use
5679 // low-level accessors to get and modify their data.
5680 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
5681 *RawField(this, Map::kInstanceDescriptorsOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01005682 if (d == heap->raw_unchecked_empty_descriptor_array()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005683 Smi* NullDescriptorDetails =
5684 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
5685 FixedArray* contents = reinterpret_cast<FixedArray*>(
5686 d->get(DescriptorArray::kContentArrayIndex));
5687 ASSERT(contents->length() >= 2);
5688 for (int i = 0; i < contents->length(); i += 2) {
5689 // If the pair (value, details) is a map transition,
5690 // check if the target is live. If not, null the descriptor.
5691 // Also drop the back pointer for that map transition, so that this
5692 // map is not reached again by following a back pointer from a
5693 // non-live object.
5694 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01005695 if (details.type() == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005696 details.type() == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005697 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005698 Map* target = reinterpret_cast<Map*>(contents->get(i));
5699 ASSERT(target->IsHeapObject());
5700 if (!target->IsMarked()) {
5701 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01005702 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01005703 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00005704 ASSERT(target->prototype() == this ||
5705 target->prototype() == real_prototype);
5706 // Getter prototype() is read-only, set_prototype() has side effects.
5707 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5708 }
5709 }
5710 }
5711}
5712
5713
Steve Block791712a2010-08-27 10:21:07 +01005714void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5715 // Iterate over all fields in the body but take care in dealing with
5716 // the code entry.
5717 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5718 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5719 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5720}
5721
5722
Ben Murdochb0fe1622011-05-05 13:52:32 +01005723void JSFunction::MarkForLazyRecompilation() {
5724 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005725 ASSERT(shared()->allows_lazy_compilation() ||
5726 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01005727 Builtins* builtins = GetIsolate()->builtins();
5728 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005729}
5730
5731
5732uint32_t JSFunction::SourceHash() {
5733 uint32_t hash = 0;
5734 Object* script = shared()->script();
5735 if (!script->IsUndefined()) {
5736 Object* source = Script::cast(script)->source();
5737 if (source->IsUndefined()) hash = String::cast(source)->Hash();
5738 }
5739 hash ^= ComputeIntegerHash(shared()->start_position_and_type());
5740 hash += ComputeIntegerHash(shared()->end_position());
5741 return hash;
5742}
5743
5744
5745bool JSFunction::IsInlineable() {
5746 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005747 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005748 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005749 if (!shared_info->script()->IsScript()) return false;
5750 if (shared_info->optimization_disabled()) return false;
5751 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005752 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
5753 // If we never ran this (unlikely) then lets try to optimize it.
5754 if (code->kind() != Code::FUNCTION) return true;
5755 return code->optimizable();
5756}
5757
5758
Steve Blocka7e24c12009-10-30 11:49:00 +00005759Object* JSFunction::SetInstancePrototype(Object* value) {
5760 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01005761 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005762 if (has_initial_map()) {
5763 initial_map()->set_prototype(value);
5764 } else {
5765 // Put the value in the initial map field until an initial map is
5766 // needed. At that point, a new initial map is created and the
5767 // prototype is put into the initial map where it belongs.
5768 set_prototype_or_initial_map(value);
5769 }
Steve Block44f0eee2011-05-26 01:26:41 +01005770 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005771 return value;
5772}
5773
5774
John Reck59135872010-11-02 12:39:01 -07005775MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01005776 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00005777 Object* construct_prototype = value;
5778
5779 // If the value is not a JSObject, store the value in the map's
5780 // constructor field so it can be accessed. Also, set the prototype
5781 // used for constructing objects to the original object prototype.
5782 // See ECMA-262 13.2.2.
5783 if (!value->IsJSObject()) {
5784 // Copy the map so this does not affect unrelated functions.
5785 // Remove map transitions because they point to maps with a
5786 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005787 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07005788 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005789 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07005790 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005791 Map* new_map = Map::cast(new_object);
5792 Heap* heap = new_map->heap();
5793 set_map(new_map);
5794 new_map->set_constructor(value);
5795 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005796 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01005797 heap->isolate()->context()->global_context()->
5798 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00005799 } else {
5800 map()->set_non_instance_prototype(false);
5801 }
5802
5803 return SetInstancePrototype(construct_prototype);
5804}
5805
5806
Steve Block6ded16b2010-05-10 14:33:55 +01005807Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01005808 Context* global_context = context()->global_context();
5809 Map* no_prototype_map = shared()->strict_mode()
5810 ? global_context->strict_mode_function_without_prototype_map()
5811 : global_context->function_without_prototype_map();
5812
5813 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005814 // Be idempotent.
5815 return this;
5816 }
Steve Block44f0eee2011-05-26 01:26:41 +01005817
5818 ASSERT(!shared()->strict_mode() ||
5819 map() == global_context->strict_mode_function_map());
5820 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
5821
5822 set_map(no_prototype_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01005823 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005824 return this;
5825}
5826
5827
Steve Blocka7e24c12009-10-30 11:49:00 +00005828Object* JSFunction::SetInstanceClassName(String* name) {
5829 shared()->set_instance_class_name(name);
5830 return this;
5831}
5832
5833
Ben Murdochb0fe1622011-05-05 13:52:32 +01005834void JSFunction::PrintName(FILE* out) {
5835 SmartPointer<char> name = shared()->DebugName()->ToCString();
5836 PrintF(out, "%s", *name);
5837}
5838
5839
Steve Blocka7e24c12009-10-30 11:49:00 +00005840Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
5841 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
5842}
5843
5844
Steve Block44f0eee2011-05-26 01:26:41 +01005845MaybeObject* Oddball::Initialize(const char* to_string,
5846 Object* to_number,
5847 byte kind) {
John Reck59135872010-11-02 12:39:01 -07005848 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01005849 { MaybeObject* maybe_symbol =
5850 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07005851 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
5852 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005853 set_to_string(String::cast(symbol));
5854 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01005855 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00005856 return this;
5857}
5858
5859
Ben Murdochf87a2032010-10-22 12:50:53 +01005860String* SharedFunctionInfo::DebugName() {
5861 Object* n = name();
5862 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
5863 return String::cast(n);
5864}
5865
5866
Steve Blocka7e24c12009-10-30 11:49:00 +00005867bool SharedFunctionInfo::HasSourceCode() {
5868 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01005869 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00005870}
5871
5872
5873Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01005874 Isolate* isolate = GetIsolate();
5875 if (!HasSourceCode()) return isolate->heap()->undefined_value();
5876 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005877 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01005878 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00005879 start_position(), end_position());
5880}
5881
5882
Ben Murdochb0fe1622011-05-05 13:52:32 +01005883int SharedFunctionInfo::SourceSize() {
5884 return end_position() - start_position();
5885}
5886
5887
Steve Blocka7e24c12009-10-30 11:49:00 +00005888int SharedFunctionInfo::CalculateInstanceSize() {
5889 int instance_size =
5890 JSObject::kHeaderSize +
5891 expected_nof_properties() * kPointerSize;
5892 if (instance_size > JSObject::kMaxInstanceSize) {
5893 instance_size = JSObject::kMaxInstanceSize;
5894 }
5895 return instance_size;
5896}
5897
5898
5899int SharedFunctionInfo::CalculateInObjectProperties() {
5900 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
5901}
5902
5903
Andrei Popescu402d9372010-02-26 13:31:12 +00005904bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
5905 // Check the basic conditions for generating inline constructor code.
5906 if (!FLAG_inline_new
5907 || !has_only_simple_this_property_assignments()
5908 || this_property_assignments_count() == 0) {
5909 return false;
5910 }
5911
5912 // If the prototype is null inline constructors cause no problems.
5913 if (!prototype->IsJSObject()) {
5914 ASSERT(prototype->IsNull());
5915 return true;
5916 }
5917
Ben Murdoch8b112d22011-06-08 16:22:53 +01005918 Heap* heap = GetHeap();
5919
Andrei Popescu402d9372010-02-26 13:31:12 +00005920 // Traverse the proposed prototype chain looking for setters for properties of
5921 // the same names as are set by the inline constructor.
5922 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01005923 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00005924 obj = obj->GetPrototype()) {
5925 JSObject* js_object = JSObject::cast(obj);
5926 for (int i = 0; i < this_property_assignments_count(); i++) {
5927 LookupResult result;
5928 String* name = GetThisPropertyAssignmentName(i);
5929 js_object->LocalLookupRealNamedProperty(name, &result);
5930 if (result.IsProperty() && result.type() == CALLBACKS) {
5931 return false;
5932 }
5933 }
5934 }
5935
5936 return true;
5937}
5938
5939
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005940void SharedFunctionInfo::ForbidInlineConstructor() {
5941 set_compiler_hints(BooleanBit::set(compiler_hints(),
5942 kHasOnlySimpleThisPropertyAssignments,
5943 false));
5944}
5945
5946
Steve Blocka7e24c12009-10-30 11:49:00 +00005947void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00005948 bool only_simple_this_property_assignments,
5949 FixedArray* assignments) {
5950 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00005951 kHasOnlySimpleThisPropertyAssignments,
5952 only_simple_this_property_assignments));
5953 set_this_property_assignments(assignments);
5954 set_this_property_assignments_count(assignments->length() / 3);
5955}
5956
5957
5958void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01005959 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005960 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00005961 kHasOnlySimpleThisPropertyAssignments,
5962 false));
Steve Block44f0eee2011-05-26 01:26:41 +01005963 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005964 set_this_property_assignments_count(0);
5965}
5966
5967
5968String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
5969 Object* obj = this_property_assignments();
5970 ASSERT(obj->IsFixedArray());
5971 ASSERT(index < this_property_assignments_count());
5972 obj = FixedArray::cast(obj)->get(index * 3);
5973 ASSERT(obj->IsString());
5974 return String::cast(obj);
5975}
5976
5977
5978bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
5979 Object* obj = this_property_assignments();
5980 ASSERT(obj->IsFixedArray());
5981 ASSERT(index < this_property_assignments_count());
5982 obj = FixedArray::cast(obj)->get(index * 3 + 1);
5983 return Smi::cast(obj)->value() != -1;
5984}
5985
5986
5987int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
5988 ASSERT(IsThisPropertyAssignmentArgument(index));
5989 Object* obj =
5990 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
5991 return Smi::cast(obj)->value();
5992}
5993
5994
5995Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
5996 ASSERT(!IsThisPropertyAssignmentArgument(index));
5997 Object* obj =
5998 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
5999 return obj;
6000}
6001
6002
Steve Blocka7e24c12009-10-30 11:49:00 +00006003// Support function for printing the source code to a StringStream
6004// without any allocation in the heap.
6005void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6006 int max_length) {
6007 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006008 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006009 accumulator->Add("<No Source>");
6010 return;
6011 }
6012
Steve Blockd0582a62009-12-15 09:54:21 +00006013 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00006014 // Don't use String::cast because we don't want more assertion errors while
6015 // we are already creating a stack dump.
6016 String* script_source =
6017 reinterpret_cast<String*>(Script::cast(script())->source());
6018
6019 if (!script_source->LooksValid()) {
6020 accumulator->Add("<Invalid Source>");
6021 return;
6022 }
6023
6024 if (!is_toplevel()) {
6025 accumulator->Add("function ");
6026 Object* name = this->name();
6027 if (name->IsString() && String::cast(name)->length() > 0) {
6028 accumulator->PrintName(name);
6029 }
6030 }
6031
6032 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006033 if (len <= max_length || max_length < 0) {
6034 accumulator->Put(script_source, start_position(), end_position());
6035 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006036 accumulator->Put(script_source,
6037 start_position(),
6038 start_position() + max_length);
6039 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006040 }
6041}
6042
6043
Ben Murdochb0fe1622011-05-05 13:52:32 +01006044static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6045 if (code->instruction_size() != recompiled->instruction_size()) return false;
6046 ByteArray* code_relocation = code->relocation_info();
6047 ByteArray* recompiled_relocation = recompiled->relocation_info();
6048 int length = code_relocation->length();
6049 if (length != recompiled_relocation->length()) return false;
6050 int compare = memcmp(code_relocation->GetDataStartAddress(),
6051 recompiled_relocation->GetDataStartAddress(),
6052 length);
6053 return compare == 0;
6054}
6055
6056
6057void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6058 ASSERT(!has_deoptimization_support());
6059 AssertNoAllocation no_allocation;
6060 Code* code = this->code();
6061 if (IsCodeEquivalent(code, recompiled)) {
6062 // Copy the deoptimization data from the recompiled code.
6063 code->set_deoptimization_data(recompiled->deoptimization_data());
6064 code->set_has_deoptimization_support(true);
6065 } else {
6066 // TODO(3025757): In case the recompiled isn't equivalent to the
6067 // old code, we have to replace it. We should try to avoid this
6068 // altogether because it flushes valuable type feedback by
6069 // effectively resetting all IC state.
6070 set_code(recompiled);
6071 }
6072 ASSERT(has_deoptimization_support());
6073}
6074
6075
6076bool SharedFunctionInfo::VerifyBailoutId(int id) {
6077 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6078 // we are always bailing out on ARM.
6079
6080 ASSERT(id != AstNode::kNoNumber);
6081 Code* unoptimized = code();
6082 DeoptimizationOutputData* data =
6083 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6084 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6085 USE(ignore);
6086 return true; // Return true if there was no ASSERT.
6087}
6088
6089
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006090void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6091 ASSERT(!IsInobjectSlackTrackingInProgress());
6092
6093 // Only initiate the tracking the first time.
6094 if (live_objects_may_exist()) return;
6095 set_live_objects_may_exist(true);
6096
6097 // No tracking during the snapshot construction phase.
6098 if (Serializer::enabled()) return;
6099
6100 if (map->unused_property_fields() == 0) return;
6101
6102 // Nonzero counter is a leftover from the previous attempt interrupted
6103 // by GC, keep it.
6104 if (construction_count() == 0) {
6105 set_construction_count(kGenerousAllocationCount);
6106 }
6107 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006108 Builtins* builtins = map->heap()->isolate()->builtins();
6109 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006110 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006111 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006112}
6113
6114
6115// Called from GC, hence reinterpret_cast and unchecked accessors.
6116void SharedFunctionInfo::DetachInitialMap() {
6117 Map* map = reinterpret_cast<Map*>(initial_map());
6118
6119 // Make the map remember to restore the link if it survives the GC.
6120 map->set_bit_field2(
6121 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6122
6123 // Undo state changes made by StartInobjectTracking (except the
6124 // construction_count). This way if the initial map does not survive the GC
6125 // then StartInobjectTracking will be called again the next time the
6126 // constructor is called. The countdown will continue and (possibly after
6127 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006128 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6129 Builtins* builtins = map->heap()->isolate()->builtins();
6130 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006131 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006132 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006133 // It is safe to clear the flag: it will be set again if the map is live.
6134 set_live_objects_may_exist(false);
6135}
6136
6137
6138// Called from GC, hence reinterpret_cast and unchecked accessors.
6139void SharedFunctionInfo::AttachInitialMap(Map* map) {
6140 map->set_bit_field2(
6141 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6142
6143 // Resume inobject slack tracking.
6144 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006145 Builtins* builtins = map->heap()->isolate()->builtins();
6146 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006147 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006148 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006149 // The map survived the gc, so there may be objects referencing it.
6150 set_live_objects_may_exist(true);
6151}
6152
6153
6154static void GetMinInobjectSlack(Map* map, void* data) {
6155 int slack = map->unused_property_fields();
6156 if (*reinterpret_cast<int*>(data) > slack) {
6157 *reinterpret_cast<int*>(data) = slack;
6158 }
6159}
6160
6161
6162static void ShrinkInstanceSize(Map* map, void* data) {
6163 int slack = *reinterpret_cast<int*>(data);
6164 map->set_inobject_properties(map->inobject_properties() - slack);
6165 map->set_unused_property_fields(map->unused_property_fields() - slack);
6166 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6167
6168 // Visitor id might depend on the instance size, recalculate it.
6169 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6170}
6171
6172
6173void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6174 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6175 Map* map = Map::cast(initial_map());
6176
Steve Block44f0eee2011-05-26 01:26:41 +01006177 Heap* heap = map->heap();
6178 set_initial_map(heap->undefined_value());
6179 Builtins* builtins = heap->isolate()->builtins();
6180 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006181 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006182 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006183
6184 int slack = map->unused_property_fields();
6185 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6186 if (slack != 0) {
6187 // Resize the initial map and all maps in its transition tree.
6188 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
6189 // Give the correct expected_nof_properties to initial maps created later.
6190 ASSERT(expected_nof_properties() >= slack);
6191 set_expected_nof_properties(expected_nof_properties() - slack);
6192 }
6193}
6194
6195
Steve Blocka7e24c12009-10-30 11:49:00 +00006196void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6197 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6198 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6199 Object* old_target = target;
6200 VisitPointer(&target);
6201 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6202}
6203
6204
Steve Block791712a2010-08-27 10:21:07 +01006205void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6206 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6207 Object* old_code = code;
6208 VisitPointer(&code);
6209 if (code != old_code) {
6210 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6211 }
6212}
6213
6214
Ben Murdochb0fe1622011-05-05 13:52:32 +01006215void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6216 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6217 Object* cell = rinfo->target_cell();
6218 Object* old_cell = cell;
6219 VisitPointer(&cell);
6220 if (cell != old_cell) {
6221 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6222 }
6223}
6224
6225
Steve Blocka7e24c12009-10-30 11:49:00 +00006226void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006227 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6228 rinfo->IsPatchedReturnSequence()) ||
6229 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6230 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006231 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6232 Object* old_target = target;
6233 VisitPointer(&target);
6234 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6235}
6236
6237
Ben Murdochb0fe1622011-05-05 13:52:32 +01006238void Code::InvalidateRelocation() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006239 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006240}
6241
6242
Steve Blockd0582a62009-12-15 09:54:21 +00006243void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006244 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6245 it.rinfo()->apply(delta);
6246 }
6247 CPU::FlushICache(instruction_start(), instruction_size());
6248}
6249
6250
6251void Code::CopyFrom(const CodeDesc& desc) {
6252 // copy code
6253 memmove(instruction_start(), desc.buffer, desc.instr_size);
6254
Steve Blocka7e24c12009-10-30 11:49:00 +00006255 // copy reloc info
6256 memmove(relocation_start(),
6257 desc.buffer + desc.buffer_size - desc.reloc_size,
6258 desc.reloc_size);
6259
6260 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006261 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006262 int mode_mask = RelocInfo::kCodeTargetMask |
6263 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006264 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006265 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006266 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006267 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6268 RelocInfo::Mode mode = it.rinfo()->rmode();
6269 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006270 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006271 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006272 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006273 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006274 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006275 } else if (RelocInfo::IsCodeTarget(mode)) {
6276 // rewrite code handles in inline cache targets to direct
6277 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006278 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006279 Code* code = Code::cast(*p);
6280 it.rinfo()->set_target_address(code->instruction_start());
6281 } else {
6282 it.rinfo()->apply(delta);
6283 }
6284 }
6285 CPU::FlushICache(instruction_start(), instruction_size());
6286}
6287
6288
6289// Locate the source position which is closest to the address in the code. This
6290// is using the source position information embedded in the relocation info.
6291// The position returned is relative to the beginning of the script where the
6292// source for this function is found.
6293int Code::SourcePosition(Address pc) {
6294 int distance = kMaxInt;
6295 int position = RelocInfo::kNoPosition; // Initially no position found.
6296 // Run through all the relocation info to find the best matching source
6297 // position. All the code needs to be considered as the sequence of the
6298 // instructions in the code does not necessarily follow the same order as the
6299 // source.
6300 RelocIterator it(this, RelocInfo::kPositionMask);
6301 while (!it.done()) {
6302 // Only look at positions after the current pc.
6303 if (it.rinfo()->pc() < pc) {
6304 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006305
6306 int dist = static_cast<int>(pc - it.rinfo()->pc());
6307 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006308 // If this position is closer than the current candidate or if it has the
6309 // same distance as the current candidate and the position is higher then
6310 // this position is the new candidate.
6311 if ((dist < distance) ||
6312 (dist == distance && pos > position)) {
6313 position = pos;
6314 distance = dist;
6315 }
6316 }
6317 it.next();
6318 }
6319 return position;
6320}
6321
6322
6323// Same as Code::SourcePosition above except it only looks for statement
6324// positions.
6325int Code::SourceStatementPosition(Address pc) {
6326 // First find the position as close as possible using all position
6327 // information.
6328 int position = SourcePosition(pc);
6329 // Now find the closest statement position before the position.
6330 int statement_position = 0;
6331 RelocIterator it(this, RelocInfo::kPositionMask);
6332 while (!it.done()) {
6333 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006334 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006335 if (statement_position < p && p <= position) {
6336 statement_position = p;
6337 }
6338 }
6339 it.next();
6340 }
6341 return statement_position;
6342}
6343
6344
Ben Murdochb8e0da22011-05-16 14:20:40 +01006345SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006346 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006347 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006348}
6349
6350
6351void Code::SetNoStackCheckTable() {
6352 // Indicate the absence of a stack-check table by a table start after the
6353 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006354 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006355}
6356
6357
6358Map* Code::FindFirstMap() {
6359 ASSERT(is_inline_cache_stub());
6360 AssertNoAllocation no_allocation;
6361 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6362 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6363 RelocInfo* info = it.rinfo();
6364 Object* object = info->target_object();
6365 if (object->IsMap()) return Map::cast(object);
6366 }
6367 return NULL;
6368}
6369
6370
Steve Blocka7e24c12009-10-30 11:49:00 +00006371#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006372
6373#ifdef OBJECT_PRINT
6374
6375void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6376 disasm::NameConverter converter;
6377 int deopt_count = DeoptCount();
6378 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6379 if (0 == deopt_count) return;
6380
6381 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
6382 for (int i = 0; i < deopt_count; i++) {
6383 int command_count = 0;
6384 PrintF(out, "%6d %6d %6d",
6385 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
6386 int translation_index = TranslationIndex(i)->value();
6387 TranslationIterator iterator(TranslationByteArray(), translation_index);
6388 Translation::Opcode opcode =
6389 static_cast<Translation::Opcode>(iterator.Next());
6390 ASSERT(Translation::BEGIN == opcode);
6391 int frame_count = iterator.Next();
6392 if (FLAG_print_code_verbose) {
6393 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6394 frame_count);
6395 }
6396
6397 for (int i = 0; i < frame_count; ++i) {
6398 opcode = static_cast<Translation::Opcode>(iterator.Next());
6399 ASSERT(Translation::FRAME == opcode);
6400 int ast_id = iterator.Next();
6401 int function_id = iterator.Next();
6402 JSFunction* function =
6403 JSFunction::cast(LiteralArray()->get(function_id));
6404 unsigned height = iterator.Next();
6405 if (FLAG_print_code_verbose) {
6406 PrintF(out, "%24s %s {ast_id=%d, function=",
6407 "", Translation::StringFor(opcode), ast_id);
6408 function->PrintName(out);
6409 PrintF(out, ", height=%u}\n", height);
6410 }
6411
6412 // Size of translation is height plus all incoming arguments including
6413 // receiver.
6414 int size = height + function->shared()->formal_parameter_count() + 1;
6415 command_count += size;
6416 for (int j = 0; j < size; ++j) {
6417 opcode = static_cast<Translation::Opcode>(iterator.Next());
6418 if (FLAG_print_code_verbose) {
6419 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
6420 }
6421
6422 if (opcode == Translation::DUPLICATE) {
6423 opcode = static_cast<Translation::Opcode>(iterator.Next());
6424 if (FLAG_print_code_verbose) {
6425 PrintF(out, "%s ", Translation::StringFor(opcode));
6426 }
6427 --j; // Two commands share the same frame index.
6428 }
6429
6430 switch (opcode) {
6431 case Translation::BEGIN:
6432 case Translation::FRAME:
6433 case Translation::DUPLICATE:
6434 UNREACHABLE();
6435 break;
6436
6437 case Translation::REGISTER: {
6438 int reg_code = iterator.Next();
6439 if (FLAG_print_code_verbose) {
6440 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6441 }
6442 break;
6443 }
6444
6445 case Translation::INT32_REGISTER: {
6446 int reg_code = iterator.Next();
6447 if (FLAG_print_code_verbose) {
6448 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6449 }
6450 break;
6451 }
6452
6453 case Translation::DOUBLE_REGISTER: {
6454 int reg_code = iterator.Next();
6455 if (FLAG_print_code_verbose) {
6456 PrintF(out, "{input=%s}",
6457 DoubleRegister::AllocationIndexToString(reg_code));
6458 }
6459 break;
6460 }
6461
6462 case Translation::STACK_SLOT: {
6463 int input_slot_index = iterator.Next();
6464 if (FLAG_print_code_verbose) {
6465 PrintF(out, "{input=%d}", input_slot_index);
6466 }
6467 break;
6468 }
6469
6470 case Translation::INT32_STACK_SLOT: {
6471 int input_slot_index = iterator.Next();
6472 if (FLAG_print_code_verbose) {
6473 PrintF(out, "{input=%d}", input_slot_index);
6474 }
6475 break;
6476 }
6477
6478 case Translation::DOUBLE_STACK_SLOT: {
6479 int input_slot_index = iterator.Next();
6480 if (FLAG_print_code_verbose) {
6481 PrintF(out, "{input=%d}", input_slot_index);
6482 }
6483 break;
6484 }
6485
6486 case Translation::LITERAL: {
6487 unsigned literal_index = iterator.Next();
6488 if (FLAG_print_code_verbose) {
6489 PrintF(out, "{literal_id=%u}", literal_index);
6490 }
6491 break;
6492 }
6493
6494 case Translation::ARGUMENTS_OBJECT:
6495 break;
6496 }
6497 if (FLAG_print_code_verbose) PrintF(out, "\n");
6498 }
6499 }
6500 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
6501 }
6502}
6503
6504
6505void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
6506 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
6507 this->DeoptPoints());
6508 if (this->DeoptPoints() == 0) return;
6509
6510 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
6511 for (int i = 0; i < this->DeoptPoints(); i++) {
6512 int pc_and_state = this->PcAndState(i)->value();
6513 PrintF("%6d %8d %s\n",
6514 this->AstId(i)->value(),
6515 FullCodeGenerator::PcField::decode(pc_and_state),
6516 FullCodeGenerator::State2String(
6517 FullCodeGenerator::StateField::decode(pc_and_state)));
6518 }
6519}
6520
6521#endif
6522
6523
Steve Blocka7e24c12009-10-30 11:49:00 +00006524// Identify kind of code.
6525const char* Code::Kind2String(Kind kind) {
6526 switch (kind) {
6527 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006528 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006529 case STUB: return "STUB";
6530 case BUILTIN: return "BUILTIN";
6531 case LOAD_IC: return "LOAD_IC";
6532 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
Steve Block44f0eee2011-05-26 01:26:41 +01006533 case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006534 case STORE_IC: return "STORE_IC";
6535 case KEYED_STORE_IC: return "KEYED_STORE_IC";
Steve Block44f0eee2011-05-26 01:26:41 +01006536 case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006537 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006538 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006539 case TYPE_RECORDING_BINARY_OP_IC: return "TYPE_RECORDING_BINARY_OP_IC";
6540 case COMPARE_IC: return "COMPARE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006541 }
6542 UNREACHABLE();
6543 return NULL;
6544}
6545
6546
6547const char* Code::ICState2String(InlineCacheState state) {
6548 switch (state) {
6549 case UNINITIALIZED: return "UNINITIALIZED";
6550 case PREMONOMORPHIC: return "PREMONOMORPHIC";
6551 case MONOMORPHIC: return "MONOMORPHIC";
6552 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
6553 case MEGAMORPHIC: return "MEGAMORPHIC";
6554 case DEBUG_BREAK: return "DEBUG_BREAK";
6555 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
6556 }
6557 UNREACHABLE();
6558 return NULL;
6559}
6560
6561
6562const char* Code::PropertyType2String(PropertyType type) {
6563 switch (type) {
6564 case NORMAL: return "NORMAL";
6565 case FIELD: return "FIELD";
6566 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
6567 case CALLBACKS: return "CALLBACKS";
6568 case INTERCEPTOR: return "INTERCEPTOR";
6569 case MAP_TRANSITION: return "MAP_TRANSITION";
Steve Block44f0eee2011-05-26 01:26:41 +01006570 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006571 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
6572 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
6573 }
6574 UNREACHABLE();
6575 return NULL;
6576}
6577
Ben Murdochb0fe1622011-05-05 13:52:32 +01006578
Steve Block1e0659c2011-05-24 12:43:12 +01006579void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
6580 const char* name = NULL;
6581 switch (kind) {
6582 case CALL_IC:
6583 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
6584 name = "STRING_INDEX_OUT_OF_BOUNDS";
6585 }
6586 break;
6587 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006588 case KEYED_STORE_IC:
6589 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01006590 name = "STRICT";
6591 }
6592 break;
6593 default:
6594 break;
6595 }
6596 if (name != NULL) {
6597 PrintF(out, "extra_ic_state = %s\n", name);
6598 } else {
6599 PrintF(out, "etra_ic_state = %d\n", extra);
6600 }
6601}
6602
6603
Ben Murdochb0fe1622011-05-05 13:52:32 +01006604void Code::Disassemble(const char* name, FILE* out) {
6605 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006606 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006607 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01006608 PrintExtraICState(out, kind(), extra_ic_state());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006609 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
Steve Blocka7e24c12009-10-30 11:49:00 +00006610 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006611 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006612 }
6613 }
6614 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006615 PrintF(out, "name = %s\n", name);
6616 }
6617 if (kind() == OPTIMIZED_FUNCTION) {
6618 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00006619 }
6620
Ben Murdochb0fe1622011-05-05 13:52:32 +01006621 PrintF(out, "Instructions (size = %d)\n", instruction_size());
6622 Disassembler::Decode(out, this);
6623 PrintF(out, "\n");
6624
6625#ifdef DEBUG
6626 if (kind() == FUNCTION) {
6627 DeoptimizationOutputData* data =
6628 DeoptimizationOutputData::cast(this->deoptimization_data());
6629 data->DeoptimizationOutputDataPrint(out);
6630 } else if (kind() == OPTIMIZED_FUNCTION) {
6631 DeoptimizationInputData* data =
6632 DeoptimizationInputData::cast(this->deoptimization_data());
6633 data->DeoptimizationInputDataPrint(out);
6634 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006635 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006636#endif
6637
6638 if (kind() == OPTIMIZED_FUNCTION) {
6639 SafepointTable table(this);
6640 PrintF(out, "Safepoints (size = %u)\n", table.size());
6641 for (unsigned i = 0; i < table.length(); i++) {
6642 unsigned pc_offset = table.GetPcOffset(i);
6643 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
6644 table.PrintEntry(i);
6645 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01006646 SafepointEntry entry = table.GetEntry(i);
6647 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
6648 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006649 } else {
6650 PrintF(out, " <none>");
6651 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01006652 if (entry.argument_count() > 0) {
6653 PrintF(out, " argc: %d", entry.argument_count());
6654 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006655 PrintF(out, "\n");
6656 }
6657 PrintF(out, "\n");
6658 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01006659 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006660 // If there is no stack check table, the "table start" will at or after
6661 // (due to alignment) the end of the instruction stream.
6662 if (static_cast<int>(offset) < instruction_size()) {
6663 unsigned* address =
6664 reinterpret_cast<unsigned*>(instruction_start() + offset);
6665 unsigned length = address[0];
6666 PrintF(out, "Stack checks (size = %u)\n", length);
6667 PrintF(out, "ast_id pc_offset\n");
6668 for (unsigned i = 0; i < length; ++i) {
6669 unsigned index = (2 * i) + 1;
6670 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
6671 }
6672 PrintF(out, "\n");
6673 }
6674 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006675
6676 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006677 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
6678 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006679}
6680#endif // ENABLE_DISASSEMBLER
6681
6682
John Reck59135872010-11-02 12:39:01 -07006683MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
6684 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006685 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00006686 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006687 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01006688
John Reck59135872010-11-02 12:39:01 -07006689 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006690 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006691 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6692 }
Steve Block8defd9f2010-07-08 12:39:36 +01006693 FixedArray* elems = FixedArray::cast(obj);
6694
John Reck59135872010-11-02 12:39:01 -07006695 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
6696 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6697 }
Steve Block8defd9f2010-07-08 12:39:36 +01006698 Map* new_map = Map::cast(obj);
6699
Leon Clarke4515c472010-02-03 11:58:03 +00006700 AssertNoAllocation no_gc;
6701 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00006702 switch (GetElementsKind()) {
6703 case FAST_ELEMENTS: {
6704 FixedArray* old_elements = FixedArray::cast(elements());
6705 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
6706 // Fill out the new array with this content and array holes.
6707 for (uint32_t i = 0; i < old_length; i++) {
6708 elems->set(i, old_elements->get(i), mode);
6709 }
6710 break;
6711 }
6712 case DICTIONARY_ELEMENTS: {
6713 NumberDictionary* dictionary = NumberDictionary::cast(elements());
6714 for (int i = 0; i < dictionary->Capacity(); i++) {
6715 Object* key = dictionary->KeyAt(i);
6716 if (key->IsNumber()) {
6717 uint32_t entry = static_cast<uint32_t>(key->Number());
6718 elems->set(entry, dictionary->ValueAt(i), mode);
6719 }
6720 }
6721 break;
6722 }
6723 default:
6724 UNREACHABLE();
6725 break;
6726 }
Steve Block8defd9f2010-07-08 12:39:36 +01006727
6728 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00006729 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01006730
6731 if (IsJSArray()) {
6732 JSArray::cast(this)->set_length(Smi::FromInt(length));
6733 }
6734
6735 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00006736}
6737
6738
John Reck59135872010-11-02 12:39:01 -07006739MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006740 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006741 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00006742
6743 uint32_t new_length = static_cast<uint32_t>(len->Number());
6744
6745 switch (GetElementsKind()) {
6746 case FAST_ELEMENTS: {
6747 // Make sure we never try to shrink dense arrays into sparse arrays.
6748 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
6749 new_length);
John Reck59135872010-11-02 12:39:01 -07006750 Object* obj;
6751 { MaybeObject* maybe_obj = NormalizeElements();
6752 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6753 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006754
6755 // Update length for JSArrays.
6756 if (IsJSArray()) JSArray::cast(this)->set_length(len);
6757 break;
6758 }
6759 case DICTIONARY_ELEMENTS: {
6760 if (IsJSArray()) {
6761 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01006762 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00006763 element_dictionary()->RemoveNumberEntries(new_length, old_length),
6764 JSArray::cast(this)->set_length(len);
6765 }
6766 break;
6767 }
6768 default:
6769 UNREACHABLE();
6770 break;
6771 }
6772 return this;
6773}
6774
6775
John Reck59135872010-11-02 12:39:01 -07006776MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01006777 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006778 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00006779 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00006780 FixedArray* new_elements;
6781 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006782 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00006783 } else {
John Reck59135872010-11-02 12:39:01 -07006784 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006785 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006786 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6787 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006788 new_elements = FixedArray::cast(obj);
6789 }
6790 set_elements(new_elements);
6791 return this;
6792}
6793
6794
6795void JSArray::Expand(int required_size) {
6796 Handle<JSArray> self(this);
6797 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
6798 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00006799 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01006800 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00006801 // Can't use this any more now because we may have had a GC!
6802 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
6803 self->SetContent(*new_backing);
6804}
6805
6806
Steve Block44f0eee2011-05-26 01:26:41 +01006807static Failure* ArrayLengthRangeError(Heap* heap) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006808 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006809 return heap->isolate()->Throw(
6810 *FACTORY->NewRangeError("invalid_array_length",
6811 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00006812}
6813
6814
John Reck59135872010-11-02 12:39:01 -07006815MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006816 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01006817 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00006818
John Reck59135872010-11-02 12:39:01 -07006819 MaybeObject* maybe_smi_length = len->ToSmi();
6820 Object* smi_length = Smi::FromInt(0);
6821 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01006822 const int value = Smi::cast(smi_length)->value();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006823 if (value < 0) return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00006824 switch (GetElementsKind()) {
6825 case FAST_ELEMENTS: {
6826 int old_capacity = FixedArray::cast(elements())->length();
6827 if (value <= old_capacity) {
6828 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07006829 Object* obj;
6830 { MaybeObject* maybe_obj = EnsureWritableFastElements();
6831 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6832 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006833 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
6834 // NOTE: We may be able to optimize this by removing the
6835 // last part of the elements backing storage array and
6836 // setting the capacity to the new size.
6837 for (int i = value; i < old_length; i++) {
6838 FixedArray::cast(elements())->set_the_hole(i);
6839 }
Leon Clarke4515c472010-02-03 11:58:03 +00006840 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006841 }
6842 return this;
6843 }
6844 int min = NewElementsCapacity(old_capacity);
6845 int new_capacity = value > min ? value : min;
6846 if (new_capacity <= kMaxFastElementsLength ||
6847 !ShouldConvertToSlowElements(new_capacity)) {
John Reck59135872010-11-02 12:39:01 -07006848 Object* obj;
6849 { MaybeObject* maybe_obj =
6850 SetFastElementsCapacityAndLength(new_capacity, value);
6851 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6852 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006853 return this;
6854 }
6855 break;
6856 }
6857 case DICTIONARY_ELEMENTS: {
6858 if (IsJSArray()) {
6859 if (value == 0) {
6860 // If the length of a slow array is reset to zero, we clear
6861 // the array and flush backing storage. This has the added
6862 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07006863 Object* obj;
6864 { MaybeObject* maybe_obj = ResetElements();
6865 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6866 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006867 } else {
6868 // Remove deleted elements.
6869 uint32_t old_length =
6870 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
6871 element_dictionary()->RemoveNumberEntries(value, old_length);
6872 }
Leon Clarke4515c472010-02-03 11:58:03 +00006873 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006874 }
6875 return this;
6876 }
6877 default:
6878 UNREACHABLE();
6879 break;
6880 }
6881 }
6882
6883 // General slow case.
6884 if (len->IsNumber()) {
6885 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006886 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006887 return SetSlowElements(len);
6888 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006889 return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00006890 }
6891 }
6892
6893 // len is not a number so make the array size one and
6894 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07006895 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01006896 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07006897 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6898 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006899 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00006900 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006901 set_elements(FixedArray::cast(obj));
6902 return this;
6903}
6904
6905
Steve Block053d10c2011-06-13 19:13:29 +01006906Object* Map::GetPrototypeTransition(Object* prototype) {
6907 FixedArray* cache = prototype_transitions();
6908 int capacity = cache->length();
6909 if (capacity == 0) return NULL;
6910 int finger = Smi::cast(cache->get(0))->value();
6911 for (int i = 1; i < finger; i += 2) {
6912 if (cache->get(i) == prototype) return cache->get(i + 1);
6913 }
6914 return NULL;
6915}
6916
6917
6918MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
6919 // Don't cache prototype transition if this map is shared.
6920 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
6921
6922 FixedArray* cache = prototype_transitions();
6923
6924 int capacity = cache->length();
6925
6926 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value();
6927
6928 if (finger >= capacity) {
6929 if (capacity > kMaxCachedPrototypeTransitions) return this;
6930
6931 FixedArray* new_cache;
6932 { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1);
6933 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
6934 }
6935
6936 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i));
6937 cache = new_cache;
6938 set_prototype_transitions(cache);
6939 }
6940
6941 cache->set(finger, prototype);
6942 cache->set(finger + 1, map);
6943 cache->set(0, Smi::FromInt(finger + 2));
6944
6945 return cache;
6946}
6947
6948
John Reck59135872010-11-02 12:39:01 -07006949MaybeObject* JSObject::SetPrototype(Object* value,
6950 bool skip_hidden_prototypes) {
Steve Block44f0eee2011-05-26 01:26:41 +01006951 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00006952 // Silently ignore the change if value is not a JSObject or null.
6953 // SpiderMonkey behaves this way.
6954 if (!value->IsJSObject() && !value->IsNull()) return value;
6955
Ben Murdoch8b112d22011-06-08 16:22:53 +01006956 // From 8.6.2 Object Internal Methods
6957 // ...
6958 // In addition, if [[Extensible]] is false the value of the [[Class]] and
6959 // [[Prototype]] internal properties of the object may not be modified.
6960 // ...
6961 // Implementation specific extensions that modify [[Class]], [[Prototype]]
6962 // or [[Extensible]] must not violate the invariants defined in the preceding
6963 // paragraph.
6964 if (!this->map()->is_extensible()) {
6965 HandleScope scope;
6966 Handle<Object> handle(this, heap->isolate());
6967 return heap->isolate()->Throw(
6968 *FACTORY->NewTypeError("non_extensible_proto",
6969 HandleVector<Object>(&handle, 1)));
6970 }
6971
Andrei Popescu402d9372010-02-26 13:31:12 +00006972 // Before we can set the prototype we need to be sure
6973 // prototype cycles are prevented.
6974 // It is sufficient to validate that the receiver is not in the new prototype
6975 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01006976 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006977 if (JSObject::cast(pt) == this) {
6978 // Cycle detected.
6979 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006980 return heap->isolate()->Throw(
6981 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00006982 }
6983 }
6984
6985 JSObject* real_receiver = this;
6986
6987 if (skip_hidden_prototypes) {
6988 // Find the first object in the chain whose prototype object is not
6989 // hidden and set the new prototype on that object.
6990 Object* current_proto = real_receiver->GetPrototype();
6991 while (current_proto->IsJSObject() &&
6992 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
6993 real_receiver = JSObject::cast(current_proto);
6994 current_proto = current_proto->GetPrototype();
6995 }
6996 }
6997
6998 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01006999 Map* map = real_receiver->map();
7000
7001 // Nothing to do if prototype is already set.
7002 if (map->prototype() == value) return value;
7003
7004 Object* new_map = map->GetPrototypeTransition(value);
7005 if (new_map == NULL) {
7006 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7007 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7008 }
7009
7010 { MaybeObject* maybe_new_cache =
7011 map->PutPrototypeTransition(value, Map::cast(new_map));
7012 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7013 }
7014
7015 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07007016 }
Steve Block053d10c2011-06-13 19:13:29 +01007017 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00007018 real_receiver->set_map(Map::cast(new_map));
7019
Steve Block44f0eee2011-05-26 01:26:41 +01007020 heap->ClearInstanceofCache();
Kristian Monsen25f61362010-05-21 11:50:48 +01007021
Andrei Popescu402d9372010-02-26 13:31:12 +00007022 return value;
7023}
7024
7025
Steve Blocka7e24c12009-10-30 11:49:00 +00007026bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
7027 switch (GetElementsKind()) {
7028 case FAST_ELEMENTS: {
7029 uint32_t length = IsJSArray() ?
7030 static_cast<uint32_t>
7031 (Smi::cast(JSArray::cast(this)->length())->value()) :
7032 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7033 if ((index < length) &&
7034 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7035 return true;
7036 }
7037 break;
7038 }
Steve Block44f0eee2011-05-26 01:26:41 +01007039 case EXTERNAL_PIXEL_ELEMENTS: {
7040 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007041 if (index < static_cast<uint32_t>(pixels->length())) {
7042 return true;
7043 }
7044 break;
7045 }
Steve Block3ce2e202009-11-05 08:53:23 +00007046 case EXTERNAL_BYTE_ELEMENTS:
7047 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7048 case EXTERNAL_SHORT_ELEMENTS:
7049 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7050 case EXTERNAL_INT_ELEMENTS:
7051 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7052 case EXTERNAL_FLOAT_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007053 ExternalArray* array = ExternalArray::cast(elements());
7054 if (index < static_cast<uint32_t>(array->length())) {
7055 return true;
7056 }
7057 break;
7058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007059 case DICTIONARY_ELEMENTS: {
7060 if (element_dictionary()->FindEntry(index)
7061 != NumberDictionary::kNotFound) {
7062 return true;
7063 }
7064 break;
7065 }
7066 default:
7067 UNREACHABLE();
7068 break;
7069 }
7070
7071 // Handle [] on String objects.
7072 if (this->IsStringObjectWithCharacterAt(index)) return true;
7073
7074 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007075 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007076 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7077}
7078
7079
7080bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007081 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007082 // Make sure that the top context does not change when doing
7083 // callbacks or interceptor calls.
7084 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007085 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007086 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7087 Handle<JSObject> receiver_handle(receiver);
7088 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007089 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007090 v8::AccessorInfo info(args.end());
7091 if (!interceptor->query()->IsUndefined()) {
7092 v8::IndexedPropertyQuery query =
7093 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007094 LOG(isolate,
7095 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007096 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007097 {
7098 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007099 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007100 result = query(index, info);
7101 }
Iain Merrick75681382010-08-19 15:07:18 +01007102 if (!result.IsEmpty()) {
7103 ASSERT(result->IsInt32());
7104 return true; // absence of property is signaled by empty handle.
7105 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007106 } else if (!interceptor->getter()->IsUndefined()) {
7107 v8::IndexedPropertyGetter getter =
7108 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007109 LOG(isolate,
7110 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007111 v8::Handle<v8::Value> result;
7112 {
7113 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007114 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007115 result = getter(index, info);
7116 }
7117 if (!result.IsEmpty()) return true;
7118 }
7119 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7120}
7121
7122
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007123JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007124 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007125 if (IsAccessCheckNeeded()) {
7126 Heap* heap = GetHeap();
7127 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7128 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7129 return UNDEFINED_ELEMENT;
7130 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007131 }
7132
Steve Block1e0659c2011-05-24 12:43:12 +01007133 if (IsJSGlobalProxy()) {
7134 Object* proto = GetPrototype();
7135 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7136 ASSERT(proto->IsJSGlobalObject());
7137 return JSObject::cast(proto)->HasLocalElement(index);
7138 }
7139
Steve Blocka7e24c12009-10-30 11:49:00 +00007140 // Check for lookup interceptor
7141 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007142 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7143 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007144 }
7145
7146 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007147 if (this->IsStringObjectWithCharacterAt(index)) {
7148 return STRING_CHARACTER_ELEMENT;
7149 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007150
7151 switch (GetElementsKind()) {
7152 case FAST_ELEMENTS: {
7153 uint32_t length = IsJSArray() ?
7154 static_cast<uint32_t>
7155 (Smi::cast(JSArray::cast(this)->length())->value()) :
7156 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007157 if ((index < length) &&
7158 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7159 return FAST_ELEMENT;
7160 }
7161 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007162 }
Steve Block44f0eee2011-05-26 01:26:41 +01007163 case EXTERNAL_PIXEL_ELEMENTS: {
7164 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007165 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7166 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007167 }
Steve Block3ce2e202009-11-05 08:53:23 +00007168 case EXTERNAL_BYTE_ELEMENTS:
7169 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7170 case EXTERNAL_SHORT_ELEMENTS:
7171 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7172 case EXTERNAL_INT_ELEMENTS:
7173 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7174 case EXTERNAL_FLOAT_ELEMENTS: {
7175 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007176 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7177 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007178 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007179 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007180 if (element_dictionary()->FindEntry(index) !=
7181 NumberDictionary::kNotFound) {
7182 return DICTIONARY_ELEMENT;
7183 }
7184 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007185 }
7186 default:
7187 UNREACHABLE();
7188 break;
7189 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007190
7191 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007192}
7193
7194
7195bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
7196 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007197 if (IsAccessCheckNeeded()) {
7198 Heap* heap = GetHeap();
7199 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7200 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7201 return false;
7202 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007203 }
7204
7205 // Check for lookup interceptor
7206 if (HasIndexedInterceptor()) {
7207 return HasElementWithInterceptor(receiver, index);
7208 }
7209
7210 switch (GetElementsKind()) {
7211 case FAST_ELEMENTS: {
7212 uint32_t length = IsJSArray() ?
7213 static_cast<uint32_t>
7214 (Smi::cast(JSArray::cast(this)->length())->value()) :
7215 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7216 if ((index < length) &&
7217 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
7218 break;
7219 }
Steve Block44f0eee2011-05-26 01:26:41 +01007220 case EXTERNAL_PIXEL_ELEMENTS: {
7221 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007222 if (index < static_cast<uint32_t>(pixels->length())) {
7223 return true;
7224 }
7225 break;
7226 }
Steve Block3ce2e202009-11-05 08:53:23 +00007227 case EXTERNAL_BYTE_ELEMENTS:
7228 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7229 case EXTERNAL_SHORT_ELEMENTS:
7230 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7231 case EXTERNAL_INT_ELEMENTS:
7232 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7233 case EXTERNAL_FLOAT_ELEMENTS: {
7234 ExternalArray* array = ExternalArray::cast(elements());
7235 if (index < static_cast<uint32_t>(array->length())) {
7236 return true;
7237 }
7238 break;
7239 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007240 case DICTIONARY_ELEMENTS: {
7241 if (element_dictionary()->FindEntry(index)
7242 != NumberDictionary::kNotFound) {
7243 return true;
7244 }
7245 break;
7246 }
7247 default:
7248 UNREACHABLE();
7249 break;
7250 }
7251
7252 // Handle [] on String objects.
7253 if (this->IsStringObjectWithCharacterAt(index)) return true;
7254
7255 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007256 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007257 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7258}
7259
7260
John Reck59135872010-11-02 12:39:01 -07007261MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007262 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007263 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007264 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007265 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007266 // Make sure that the top context does not change when doing
7267 // callbacks or interceptor calls.
7268 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007269 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007270 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7271 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007272 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007273 if (!interceptor->setter()->IsUndefined()) {
7274 v8::IndexedPropertySetter setter =
7275 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01007276 LOG(isolate,
7277 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
7278 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007279 v8::AccessorInfo info(args.end());
7280 v8::Handle<v8::Value> result;
7281 {
7282 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007283 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007284 result = setter(index, v8::Utils::ToLocal(value_handle), info);
7285 }
Steve Block44f0eee2011-05-26 01:26:41 +01007286 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007287 if (!result.IsEmpty()) return *value_handle;
7288 }
John Reck59135872010-11-02 12:39:01 -07007289 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01007290 this_handle->SetElementWithoutInterceptor(index,
7291 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007292 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007293 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007294 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007295 return raw_result;
7296}
7297
7298
John Reck59135872010-11-02 12:39:01 -07007299MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
7300 Object* structure,
7301 uint32_t index,
7302 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007303 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01007304 ASSERT(!structure->IsProxy());
7305
7306 // api style callbacks.
7307 if (structure->IsAccessorInfo()) {
7308 AccessorInfo* data = AccessorInfo::cast(structure);
7309 Object* fun_obj = data->getter();
7310 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007311 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007312 Handle<JSObject> self(JSObject::cast(receiver));
7313 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01007314 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7315 Handle<String> key(isolate->factory()->NumberToString(number));
7316 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
7317 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01007318 v8::AccessorInfo info(args.end());
7319 v8::Handle<v8::Value> result;
7320 {
7321 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007322 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007323 result = call_fun(v8::Utils::ToLocal(key), info);
7324 }
Steve Block44f0eee2011-05-26 01:26:41 +01007325 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
7326 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007327 return *v8::Utils::OpenHandle(*result);
7328 }
7329
7330 // __defineGetter__ callback
7331 if (structure->IsFixedArray()) {
7332 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
7333 if (getter->IsJSFunction()) {
7334 return Object::GetPropertyWithDefinedGetter(receiver,
7335 JSFunction::cast(getter));
7336 }
7337 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01007338 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007339 }
7340
7341 UNREACHABLE();
7342 return NULL;
7343}
7344
7345
John Reck59135872010-11-02 12:39:01 -07007346MaybeObject* JSObject::SetElementWithCallback(Object* structure,
7347 uint32_t index,
7348 Object* value,
7349 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007350 Isolate* isolate = GetIsolate();
7351 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007352
7353 // We should never get here to initialize a const with the hole
7354 // value since a const declaration would conflict with the setter.
7355 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01007356 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007357
7358 // To accommodate both the old and the new api we switch on the
7359 // data structure used to store the callbacks. Eventually proxy
7360 // callbacks should be phased out.
7361 ASSERT(!structure->IsProxy());
7362
7363 if (structure->IsAccessorInfo()) {
7364 // api style callbacks
7365 AccessorInfo* data = AccessorInfo::cast(structure);
7366 Object* call_obj = data->setter();
7367 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
7368 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01007369 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7370 Handle<String> key(isolate->factory()->NumberToString(number));
7371 LOG(isolate, ApiNamedPropertyAccess("store", this, *key));
7372 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Leon Clarkef7060e22010-06-03 12:02:55 +01007373 v8::AccessorInfo info(args.end());
7374 {
7375 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007376 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007377 call_fun(v8::Utils::ToLocal(key),
7378 v8::Utils::ToLocal(value_handle),
7379 info);
7380 }
Steve Block44f0eee2011-05-26 01:26:41 +01007381 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007382 return *value_handle;
7383 }
7384
7385 if (structure->IsFixedArray()) {
7386 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
7387 if (setter->IsJSFunction()) {
7388 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
7389 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007390 Handle<Object> holder_handle(holder, isolate);
7391 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01007392 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01007393 return isolate->Throw(
7394 *isolate->factory()->NewTypeError("no_setter_in_callback",
7395 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01007396 }
7397 }
7398
7399 UNREACHABLE();
7400 return NULL;
7401}
7402
7403
Steve Blocka7e24c12009-10-30 11:49:00 +00007404// Adding n elements in fast case is O(n*n).
7405// Note: revisit design to have dual undefined values to capture absent
7406// elements.
Steve Block9fac8402011-05-12 15:51:54 +01007407MaybeObject* JSObject::SetFastElement(uint32_t index,
7408 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007409 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007410 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007411 ASSERT(HasFastElements());
7412
John Reck59135872010-11-02 12:39:01 -07007413 Object* elms_obj;
7414 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements();
7415 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
7416 }
Iain Merrick75681382010-08-19 15:07:18 +01007417 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007418 uint32_t elms_length = static_cast<uint32_t>(elms->length());
7419
Steve Block9fac8402011-05-12 15:51:54 +01007420 if (check_prototype &&
Steve Block1e0659c2011-05-24 12:43:12 +01007421 (index >= elms_length || elms->get(index)->IsTheHole())) {
7422 bool found;
7423 MaybeObject* result =
7424 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7425 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007426 }
7427
Steve Block9fac8402011-05-12 15:51:54 +01007428
Steve Blocka7e24c12009-10-30 11:49:00 +00007429 // Check whether there is extra space in fixed array..
7430 if (index < elms_length) {
7431 elms->set(index, value);
7432 if (IsJSArray()) {
7433 // Update the length of the array if needed.
7434 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007435 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007436 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00007437 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007438 }
7439 }
7440 return value;
7441 }
7442
7443 // Allow gap in fast case.
7444 if ((index - elms_length) < kMaxGap) {
7445 // Try allocating extra space.
7446 int new_capacity = NewElementsCapacity(index+1);
7447 if (new_capacity <= kMaxFastElementsLength ||
7448 !ShouldConvertToSlowElements(new_capacity)) {
7449 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07007450 Object* obj;
7451 { MaybeObject* maybe_obj =
7452 SetFastElementsCapacityAndLength(new_capacity, index + 1);
7453 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7454 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007455 FixedArray::cast(elements())->set(index, value);
7456 return value;
7457 }
7458 }
7459
7460 // Otherwise default to slow case.
John Reck59135872010-11-02 12:39:01 -07007461 Object* obj;
7462 { MaybeObject* maybe_obj = NormalizeElements();
7463 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7464 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007465 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007466 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007467}
7468
Iain Merrick75681382010-08-19 15:07:18 +01007469
Steve Block9fac8402011-05-12 15:51:54 +01007470MaybeObject* JSObject::SetElement(uint32_t index,
7471 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007472 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007473 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007474 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007475 if (IsAccessCheckNeeded()) {
7476 Heap* heap = GetHeap();
7477 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
7478 HandleScope scope;
7479 Handle<Object> value_handle(value);
7480 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
7481 return *value_handle;
7482 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007483 }
7484
7485 if (IsJSGlobalProxy()) {
7486 Object* proto = GetPrototype();
7487 if (proto->IsNull()) return value;
7488 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007489 return JSObject::cast(proto)->SetElement(index,
7490 value,
7491 strict_mode,
7492 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007493 }
7494
7495 // Check for lookup interceptor
7496 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007497 return SetElementWithInterceptor(index,
7498 value,
7499 strict_mode,
7500 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007501 }
7502
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007503 return SetElementWithoutInterceptor(index,
7504 value,
7505 strict_mode,
7506 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007507}
7508
7509
John Reck59135872010-11-02 12:39:01 -07007510MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007511 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007512 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007513 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007514 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007515 switch (GetElementsKind()) {
7516 case FAST_ELEMENTS:
7517 // Fast case.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007518 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007519 case EXTERNAL_PIXEL_ELEMENTS: {
7520 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007521 return pixels->SetValue(index, value);
7522 }
Steve Block3ce2e202009-11-05 08:53:23 +00007523 case EXTERNAL_BYTE_ELEMENTS: {
7524 ExternalByteArray* array = ExternalByteArray::cast(elements());
7525 return array->SetValue(index, value);
7526 }
7527 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7528 ExternalUnsignedByteArray* array =
7529 ExternalUnsignedByteArray::cast(elements());
7530 return array->SetValue(index, value);
7531 }
7532 case EXTERNAL_SHORT_ELEMENTS: {
7533 ExternalShortArray* array = ExternalShortArray::cast(elements());
7534 return array->SetValue(index, value);
7535 }
7536 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7537 ExternalUnsignedShortArray* array =
7538 ExternalUnsignedShortArray::cast(elements());
7539 return array->SetValue(index, value);
7540 }
7541 case EXTERNAL_INT_ELEMENTS: {
7542 ExternalIntArray* array = ExternalIntArray::cast(elements());
7543 return array->SetValue(index, value);
7544 }
7545 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7546 ExternalUnsignedIntArray* array =
7547 ExternalUnsignedIntArray::cast(elements());
7548 return array->SetValue(index, value);
7549 }
7550 case EXTERNAL_FLOAT_ELEMENTS: {
7551 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7552 return array->SetValue(index, value);
7553 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007554 case DICTIONARY_ELEMENTS: {
7555 // Insert element in the dictionary.
7556 FixedArray* elms = FixedArray::cast(elements());
7557 NumberDictionary* dictionary = NumberDictionary::cast(elms);
7558
7559 int entry = dictionary->FindEntry(index);
7560 if (entry != NumberDictionary::kNotFound) {
7561 Object* element = dictionary->ValueAt(entry);
7562 PropertyDetails details = dictionary->DetailsAt(entry);
7563 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007564 return SetElementWithCallback(element, index, value, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007565 } else {
7566 dictionary->UpdateMaxNumberKey(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007567 // If put fails instrict mode, throw exception.
7568 if (!dictionary->ValueAtPut(entry, value) &&
7569 strict_mode == kStrictMode) {
Steve Block44f0eee2011-05-26 01:26:41 +01007570 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007571 Handle<Object> holder(this);
7572 Handle<Object> args[2] = { number, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01007573 return isolate->Throw(
7574 *isolate->factory()->NewTypeError("strict_read_only_property",
7575 HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007576 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007577 }
7578 } else {
7579 // Index not already used. Look for an accessor in the prototype chain.
Steve Block1e0659c2011-05-24 12:43:12 +01007580 if (check_prototype) {
7581 bool found;
7582 MaybeObject* result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007583 // Strict mode not needed. No-setter case already handled.
Steve Block1e0659c2011-05-24 12:43:12 +01007584 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7585 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007586 }
Steve Block8defd9f2010-07-08 12:39:36 +01007587 // When we set the is_extensible flag to false we always force
7588 // the element into dictionary mode (and force them to stay there).
7589 if (!map()->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007590 if (strict_mode == kNonStrictMode) {
7591 return isolate->heap()->undefined_value();
7592 } else {
7593 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
7594 Handle<String> index_string(
7595 isolate->factory()->NumberToString(number));
7596 Handle<Object> args[1] = { index_string };
7597 return isolate->Throw(
7598 *isolate->factory()->NewTypeError("object_not_extensible",
7599 HandleVector(args, 1)));
7600 }
Steve Block8defd9f2010-07-08 12:39:36 +01007601 }
John Reck59135872010-11-02 12:39:01 -07007602 Object* result;
7603 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
7604 if (!maybe_result->ToObject(&result)) return maybe_result;
7605 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007606 if (elms != FixedArray::cast(result)) {
7607 set_elements(FixedArray::cast(result));
7608 }
7609 }
7610
7611 // Update the array length if this JSObject is an array.
7612 if (IsJSArray()) {
7613 JSArray* array = JSArray::cast(this);
John Reck59135872010-11-02 12:39:01 -07007614 Object* return_value;
7615 { MaybeObject* maybe_return_value =
7616 array->JSArrayUpdateLengthFromIndex(index, value);
7617 if (!maybe_return_value->ToObject(&return_value)) {
7618 return maybe_return_value;
7619 }
7620 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007621 }
7622
7623 // Attempt to put this object back in fast case.
7624 if (ShouldConvertToFastElements()) {
7625 uint32_t new_length = 0;
7626 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007627 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007628 } else {
7629 new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
7630 }
John Reck59135872010-11-02 12:39:01 -07007631 Object* obj;
7632 { MaybeObject* maybe_obj =
7633 SetFastElementsCapacityAndLength(new_length, new_length);
7634 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7635 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007636#ifdef DEBUG
7637 if (FLAG_trace_normalization) {
7638 PrintF("Object elements are fast case again:\n");
7639 Print();
7640 }
7641#endif
7642 }
7643
7644 return value;
7645 }
7646 default:
7647 UNREACHABLE();
7648 break;
7649 }
7650 // All possible cases have been handled above. Add a return to avoid the
7651 // complaints from the compiler.
7652 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01007653 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007654}
7655
7656
John Reck59135872010-11-02 12:39:01 -07007657MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
7658 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007659 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007660 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00007661 // Check to see if we need to update the length. For now, we make
7662 // sure that the length stays within 32-bits (unsigned).
7663 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07007664 Object* len;
7665 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01007666 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07007667 if (!maybe_len->ToObject(&len)) return maybe_len;
7668 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007669 set_length(len);
7670 }
7671 return value;
7672}
7673
7674
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007675MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007676 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007677 // Get element works for both JSObject and JSArray since
7678 // JSArray::length cannot change.
7679 switch (GetElementsKind()) {
7680 case FAST_ELEMENTS: {
7681 FixedArray* elms = FixedArray::cast(elements());
7682 if (index < static_cast<uint32_t>(elms->length())) {
7683 Object* value = elms->get(index);
7684 if (!value->IsTheHole()) return value;
7685 }
7686 break;
7687 }
Steve Block44f0eee2011-05-26 01:26:41 +01007688 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007689 case EXTERNAL_BYTE_ELEMENTS:
7690 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7691 case EXTERNAL_SHORT_ELEMENTS:
7692 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7693 case EXTERNAL_INT_ELEMENTS:
7694 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7695 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007696 MaybeObject* maybe_value = GetExternalElement(index);
7697 Object* value;
7698 if (!maybe_value->ToObject(&value)) return maybe_value;
7699 if (!value->IsUndefined()) return value;
Steve Block3ce2e202009-11-05 08:53:23 +00007700 break;
7701 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007702 case DICTIONARY_ELEMENTS: {
7703 NumberDictionary* dictionary = element_dictionary();
7704 int entry = dictionary->FindEntry(index);
7705 if (entry != NumberDictionary::kNotFound) {
7706 Object* element = dictionary->ValueAt(entry);
7707 PropertyDetails details = dictionary->DetailsAt(entry);
7708 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007709 return GetElementWithCallback(receiver,
7710 element,
7711 index,
7712 this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007713 }
7714 return element;
7715 }
7716 break;
7717 }
7718 default:
7719 UNREACHABLE();
7720 break;
7721 }
7722
7723 // Continue searching via the prototype chain.
7724 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007725 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007726 return pt->GetElementWithReceiver(receiver, index);
7727}
7728
7729
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007730MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007731 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007732 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007733 // Make sure that the top context does not change when doing
7734 // callbacks or interceptor calls.
7735 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007736 HandleScope scope(isolate);
7737 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
7738 Handle<Object> this_handle(receiver, isolate);
7739 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007740 if (!interceptor->getter()->IsUndefined()) {
7741 v8::IndexedPropertyGetter getter =
7742 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007743 LOG(isolate,
7744 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
7745 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007746 v8::AccessorInfo info(args.end());
7747 v8::Handle<v8::Value> result;
7748 {
7749 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007750 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007751 result = getter(index, info);
7752 }
Steve Block44f0eee2011-05-26 01:26:41 +01007753 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007754 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
7755 }
7756
John Reck59135872010-11-02 12:39:01 -07007757 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00007758 holder_handle->GetElementPostInterceptor(*this_handle, index);
Steve Block44f0eee2011-05-26 01:26:41 +01007759 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007760 return raw_result;
7761}
7762
7763
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007764MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007765 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007766 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007767 if (IsAccessCheckNeeded()) {
7768 Heap* heap = GetHeap();
7769 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
7770 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
7771 return heap->undefined_value();
7772 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007773 }
7774
7775 if (HasIndexedInterceptor()) {
7776 return GetElementWithInterceptor(receiver, index);
7777 }
7778
7779 // Get element works for both JSObject and JSArray since
7780 // JSArray::length cannot change.
7781 switch (GetElementsKind()) {
7782 case FAST_ELEMENTS: {
7783 FixedArray* elms = FixedArray::cast(elements());
7784 if (index < static_cast<uint32_t>(elms->length())) {
7785 Object* value = elms->get(index);
7786 if (!value->IsTheHole()) return value;
7787 }
7788 break;
7789 }
Steve Block44f0eee2011-05-26 01:26:41 +01007790 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007791 case EXTERNAL_BYTE_ELEMENTS:
7792 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7793 case EXTERNAL_SHORT_ELEMENTS:
7794 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7795 case EXTERNAL_INT_ELEMENTS:
7796 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7797 case EXTERNAL_FLOAT_ELEMENTS: {
7798 MaybeObject* maybe_value = GetExternalElement(index);
7799 Object* value;
7800 if (!maybe_value->ToObject(&value)) return maybe_value;
7801 if (!value->IsUndefined()) return value;
7802 break;
7803 }
7804 case DICTIONARY_ELEMENTS: {
7805 NumberDictionary* dictionary = element_dictionary();
7806 int entry = dictionary->FindEntry(index);
7807 if (entry != NumberDictionary::kNotFound) {
7808 Object* element = dictionary->ValueAt(entry);
7809 PropertyDetails details = dictionary->DetailsAt(entry);
7810 if (details.type() == CALLBACKS) {
7811 return GetElementWithCallback(receiver,
7812 element,
7813 index,
7814 this);
7815 }
7816 return element;
7817 }
7818 break;
7819 }
7820 }
7821
7822 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007823 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007824 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007825 return pt->GetElementWithReceiver(receiver, index);
7826}
7827
7828
7829MaybeObject* JSObject::GetExternalElement(uint32_t index) {
7830 // Get element works for both JSObject and JSArray since
7831 // JSArray::length cannot change.
7832 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007833 case EXTERNAL_PIXEL_ELEMENTS: {
7834 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007835 if (index < static_cast<uint32_t>(pixels->length())) {
7836 uint8_t value = pixels->get(index);
7837 return Smi::FromInt(value);
7838 }
7839 break;
7840 }
Steve Block3ce2e202009-11-05 08:53:23 +00007841 case EXTERNAL_BYTE_ELEMENTS: {
7842 ExternalByteArray* array = ExternalByteArray::cast(elements());
7843 if (index < static_cast<uint32_t>(array->length())) {
7844 int8_t value = array->get(index);
7845 return Smi::FromInt(value);
7846 }
7847 break;
7848 }
7849 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7850 ExternalUnsignedByteArray* array =
7851 ExternalUnsignedByteArray::cast(elements());
7852 if (index < static_cast<uint32_t>(array->length())) {
7853 uint8_t value = array->get(index);
7854 return Smi::FromInt(value);
7855 }
7856 break;
7857 }
7858 case EXTERNAL_SHORT_ELEMENTS: {
7859 ExternalShortArray* array = ExternalShortArray::cast(elements());
7860 if (index < static_cast<uint32_t>(array->length())) {
7861 int16_t value = array->get(index);
7862 return Smi::FromInt(value);
7863 }
7864 break;
7865 }
7866 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7867 ExternalUnsignedShortArray* array =
7868 ExternalUnsignedShortArray::cast(elements());
7869 if (index < static_cast<uint32_t>(array->length())) {
7870 uint16_t value = array->get(index);
7871 return Smi::FromInt(value);
7872 }
7873 break;
7874 }
7875 case EXTERNAL_INT_ELEMENTS: {
7876 ExternalIntArray* array = ExternalIntArray::cast(elements());
7877 if (index < static_cast<uint32_t>(array->length())) {
7878 int32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007879 return GetHeap()->NumberFromInt32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007880 }
7881 break;
7882 }
7883 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7884 ExternalUnsignedIntArray* array =
7885 ExternalUnsignedIntArray::cast(elements());
7886 if (index < static_cast<uint32_t>(array->length())) {
7887 uint32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007888 return GetHeap()->NumberFromUint32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007889 }
7890 break;
7891 }
7892 case EXTERNAL_FLOAT_ELEMENTS: {
7893 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7894 if (index < static_cast<uint32_t>(array->length())) {
7895 float value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007896 return GetHeap()->AllocateHeapNumber(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007897 }
7898 break;
7899 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007900 case FAST_ELEMENTS:
7901 case DICTIONARY_ELEMENTS:
7902 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00007903 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007904 }
Steve Block44f0eee2011-05-26 01:26:41 +01007905 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007906}
7907
7908
7909bool JSObject::HasDenseElements() {
7910 int capacity = 0;
7911 int number_of_elements = 0;
7912
7913 switch (GetElementsKind()) {
7914 case FAST_ELEMENTS: {
7915 FixedArray* elms = FixedArray::cast(elements());
7916 capacity = elms->length();
7917 for (int i = 0; i < capacity; i++) {
7918 if (!elms->get(i)->IsTheHole()) number_of_elements++;
7919 }
7920 break;
7921 }
Steve Block44f0eee2011-05-26 01:26:41 +01007922 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007923 case EXTERNAL_BYTE_ELEMENTS:
7924 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7925 case EXTERNAL_SHORT_ELEMENTS:
7926 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7927 case EXTERNAL_INT_ELEMENTS:
7928 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7929 case EXTERNAL_FLOAT_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +00007930 return true;
7931 }
7932 case DICTIONARY_ELEMENTS: {
7933 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7934 capacity = dictionary->Capacity();
7935 number_of_elements = dictionary->NumberOfElements();
7936 break;
7937 }
7938 default:
7939 UNREACHABLE();
7940 break;
7941 }
7942
7943 if (capacity == 0) return true;
7944 return (number_of_elements > (capacity / 2));
7945}
7946
7947
7948bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
7949 ASSERT(HasFastElements());
7950 // Keep the array in fast case if the current backing storage is
7951 // almost filled and if the new capacity is no more than twice the
7952 // old capacity.
7953 int elements_length = FixedArray::cast(elements())->length();
7954 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
7955}
7956
7957
7958bool JSObject::ShouldConvertToFastElements() {
7959 ASSERT(HasDictionaryElements());
7960 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7961 // If the elements are sparse, we should not go back to fast case.
7962 if (!HasDenseElements()) return false;
7963 // If an element has been added at a very high index in the elements
7964 // dictionary, we cannot go back to fast case.
7965 if (dictionary->requires_slow_elements()) return false;
7966 // An object requiring access checks is never allowed to have fast
7967 // elements. If it had fast elements we would skip security checks.
7968 if (IsAccessCheckNeeded()) return false;
7969 // If the dictionary backing storage takes up roughly half as much
7970 // space as a fast-case backing storage would the array should have
7971 // fast elements.
7972 uint32_t length = 0;
7973 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007974 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007975 } else {
7976 length = dictionary->max_number_key();
7977 }
7978 return static_cast<uint32_t>(dictionary->Capacity()) >=
7979 (length / (2 * NumberDictionary::kEntrySize));
7980}
7981
7982
7983// Certain compilers request function template instantiation when they
7984// see the definition of the other template functions in the
7985// class. This requires us to have the template functions put
7986// together, so even though this function belongs in objects-debug.cc,
7987// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007988#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00007989template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01007990void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007991 int capacity = HashTable<Shape, Key>::Capacity();
7992 for (int i = 0; i < capacity; i++) {
7993 Object* k = HashTable<Shape, Key>::KeyAt(i);
7994 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007995 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00007996 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007997 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00007998 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007999 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008000 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008001 PrintF(out, ": ");
8002 ValueAt(i)->ShortPrint(out);
8003 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008004 }
8005 }
8006}
8007#endif
8008
8009
8010template<typename Shape, typename Key>
8011void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
8012 int pos = 0;
8013 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00008014 AssertNoAllocation no_gc;
8015 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008016 for (int i = 0; i < capacity; i++) {
8017 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8018 if (Dictionary<Shape, Key>::IsKey(k)) {
8019 elements->set(pos++, ValueAt(i), mode);
8020 }
8021 }
8022 ASSERT(pos == elements->length());
8023}
8024
8025
8026InterceptorInfo* JSObject::GetNamedInterceptor() {
8027 ASSERT(map()->has_named_interceptor());
8028 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008029 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008030 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008031 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008032 return InterceptorInfo::cast(result);
8033}
8034
8035
8036InterceptorInfo* JSObject::GetIndexedInterceptor() {
8037 ASSERT(map()->has_indexed_interceptor());
8038 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008039 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008040 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008041 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008042 return InterceptorInfo::cast(result);
8043}
8044
8045
John Reck59135872010-11-02 12:39:01 -07008046MaybeObject* JSObject::GetPropertyPostInterceptor(
8047 JSObject* receiver,
8048 String* name,
8049 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008050 // Check local property in holder, ignore interceptor.
8051 LookupResult result;
8052 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008053 if (result.IsProperty()) {
8054 return GetProperty(receiver, &result, name, attributes);
8055 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008056 // Continue searching via the prototype chain.
8057 Object* pt = GetPrototype();
8058 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008059 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008060 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8061}
8062
8063
John Reck59135872010-11-02 12:39:01 -07008064MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Steve Blockd0582a62009-12-15 09:54:21 +00008065 JSObject* receiver,
8066 String* name,
8067 PropertyAttributes* attributes) {
8068 // Check local property in holder, ignore interceptor.
8069 LookupResult result;
8070 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008071 if (result.IsProperty()) {
8072 return GetProperty(receiver, &result, name, attributes);
8073 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01008074 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00008075}
8076
8077
John Reck59135872010-11-02 12:39:01 -07008078MaybeObject* JSObject::GetPropertyWithInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00008079 JSObject* receiver,
8080 String* name,
8081 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01008082 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008083 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01008084 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008085 Handle<JSObject> receiver_handle(receiver);
8086 Handle<JSObject> holder_handle(this);
8087 Handle<String> name_handle(name);
8088
8089 if (!interceptor->getter()->IsUndefined()) {
8090 v8::NamedPropertyGetter getter =
8091 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008092 LOG(isolate,
8093 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8094 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008095 v8::AccessorInfo info(args.end());
8096 v8::Handle<v8::Value> result;
8097 {
8098 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008099 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008100 result = getter(v8::Utils::ToLocal(name_handle), info);
8101 }
Steve Block44f0eee2011-05-26 01:26:41 +01008102 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008103 if (!result.IsEmpty()) {
8104 *attributes = NONE;
8105 return *v8::Utils::OpenHandle(*result);
8106 }
8107 }
8108
John Reck59135872010-11-02 12:39:01 -07008109 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00008110 *receiver_handle,
8111 *name_handle,
8112 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01008113 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008114 return result;
8115}
8116
8117
8118bool JSObject::HasRealNamedProperty(String* key) {
8119 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008120 if (IsAccessCheckNeeded()) {
8121 Heap* heap = GetHeap();
8122 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8123 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8124 return false;
8125 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008126 }
8127
8128 LookupResult result;
8129 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008130 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00008131}
8132
8133
8134bool JSObject::HasRealElementProperty(uint32_t index) {
8135 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008136 if (IsAccessCheckNeeded()) {
8137 Heap* heap = GetHeap();
8138 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8139 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8140 return false;
8141 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008142 }
8143
8144 // Handle [] on String objects.
8145 if (this->IsStringObjectWithCharacterAt(index)) return true;
8146
8147 switch (GetElementsKind()) {
8148 case FAST_ELEMENTS: {
8149 uint32_t length = IsJSArray() ?
8150 static_cast<uint32_t>(
8151 Smi::cast(JSArray::cast(this)->length())->value()) :
8152 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8153 return (index < length) &&
8154 !FixedArray::cast(elements())->get(index)->IsTheHole();
8155 }
Steve Block44f0eee2011-05-26 01:26:41 +01008156 case EXTERNAL_PIXEL_ELEMENTS: {
8157 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008158 return index < static_cast<uint32_t>(pixels->length());
8159 }
Steve Block3ce2e202009-11-05 08:53:23 +00008160 case EXTERNAL_BYTE_ELEMENTS:
8161 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8162 case EXTERNAL_SHORT_ELEMENTS:
8163 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8164 case EXTERNAL_INT_ELEMENTS:
8165 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8166 case EXTERNAL_FLOAT_ELEMENTS: {
8167 ExternalArray* array = ExternalArray::cast(elements());
8168 return index < static_cast<uint32_t>(array->length());
8169 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008170 case DICTIONARY_ELEMENTS: {
8171 return element_dictionary()->FindEntry(index)
8172 != NumberDictionary::kNotFound;
8173 }
8174 default:
8175 UNREACHABLE();
8176 break;
8177 }
8178 // All possibilities have been handled above already.
8179 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008180 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008181}
8182
8183
8184bool JSObject::HasRealNamedCallbackProperty(String* key) {
8185 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008186 if (IsAccessCheckNeeded()) {
8187 Heap* heap = GetHeap();
8188 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8189 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8190 return false;
8191 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008192 }
8193
8194 LookupResult result;
8195 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008196 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00008197}
8198
8199
8200int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
8201 if (HasFastProperties()) {
8202 DescriptorArray* descs = map()->instance_descriptors();
8203 int result = 0;
8204 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01008205 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008206 if (details.IsProperty() && (details.attributes() & filter) == 0) {
8207 result++;
8208 }
8209 }
8210 return result;
8211 } else {
8212 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
8213 }
8214}
8215
8216
8217int JSObject::NumberOfEnumProperties() {
8218 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
8219}
8220
8221
8222void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
8223 Object* temp = get(i);
8224 set(i, get(j));
8225 set(j, temp);
8226 if (this != numbers) {
8227 temp = numbers->get(i);
8228 numbers->set(i, numbers->get(j));
8229 numbers->set(j, temp);
8230 }
8231}
8232
8233
8234static void InsertionSortPairs(FixedArray* content,
8235 FixedArray* numbers,
8236 int len) {
8237 for (int i = 1; i < len; i++) {
8238 int j = i;
8239 while (j > 0 &&
8240 (NumberToUint32(numbers->get(j - 1)) >
8241 NumberToUint32(numbers->get(j)))) {
8242 content->SwapPairs(numbers, j - 1, j);
8243 j--;
8244 }
8245 }
8246}
8247
8248
8249void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
8250 // In-place heap sort.
8251 ASSERT(content->length() == numbers->length());
8252
8253 // Bottom-up max-heap construction.
8254 for (int i = 1; i < len; ++i) {
8255 int child_index = i;
8256 while (child_index > 0) {
8257 int parent_index = ((child_index + 1) >> 1) - 1;
8258 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8259 uint32_t child_value = NumberToUint32(numbers->get(child_index));
8260 if (parent_value < child_value) {
8261 content->SwapPairs(numbers, parent_index, child_index);
8262 } else {
8263 break;
8264 }
8265 child_index = parent_index;
8266 }
8267 }
8268
8269 // Extract elements and create sorted array.
8270 for (int i = len - 1; i > 0; --i) {
8271 // Put max element at the back of the array.
8272 content->SwapPairs(numbers, 0, i);
8273 // Sift down the new top element.
8274 int parent_index = 0;
8275 while (true) {
8276 int child_index = ((parent_index + 1) << 1) - 1;
8277 if (child_index >= i) break;
8278 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
8279 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
8280 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8281 if (child_index + 1 >= i || child1_value > child2_value) {
8282 if (parent_value > child1_value) break;
8283 content->SwapPairs(numbers, parent_index, child_index);
8284 parent_index = child_index;
8285 } else {
8286 if (parent_value > child2_value) break;
8287 content->SwapPairs(numbers, parent_index, child_index + 1);
8288 parent_index = child_index + 1;
8289 }
8290 }
8291 }
8292}
8293
8294
8295// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
8296void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
8297 ASSERT(this->length() == numbers->length());
8298 // For small arrays, simply use insertion sort.
8299 if (len <= 10) {
8300 InsertionSortPairs(this, numbers, len);
8301 return;
8302 }
8303 // Check the range of indices.
8304 uint32_t min_index = NumberToUint32(numbers->get(0));
8305 uint32_t max_index = min_index;
8306 uint32_t i;
8307 for (i = 1; i < len; i++) {
8308 if (NumberToUint32(numbers->get(i)) < min_index) {
8309 min_index = NumberToUint32(numbers->get(i));
8310 } else if (NumberToUint32(numbers->get(i)) > max_index) {
8311 max_index = NumberToUint32(numbers->get(i));
8312 }
8313 }
8314 if (max_index - min_index + 1 == len) {
8315 // Indices form a contiguous range, unless there are duplicates.
8316 // Do an in-place linear time sort assuming distinct numbers, but
8317 // avoid hanging in case they are not.
8318 for (i = 0; i < len; i++) {
8319 uint32_t p;
8320 uint32_t j = 0;
8321 // While the current element at i is not at its correct position p,
8322 // swap the elements at these two positions.
8323 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
8324 j++ < len) {
8325 SwapPairs(numbers, i, p);
8326 }
8327 }
8328 } else {
8329 HeapSortPairs(this, numbers, len);
8330 return;
8331 }
8332}
8333
8334
8335// Fill in the names of local properties into the supplied storage. The main
8336// purpose of this function is to provide reflection information for the object
8337// mirrors.
8338void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
8339 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
8340 if (HasFastProperties()) {
8341 DescriptorArray* descs = map()->instance_descriptors();
8342 for (int i = 0; i < descs->number_of_descriptors(); i++) {
8343 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
8344 }
8345 ASSERT(storage->length() >= index);
8346 } else {
8347 property_dictionary()->CopyKeysTo(storage);
8348 }
8349}
8350
8351
8352int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
8353 return GetLocalElementKeys(NULL, filter);
8354}
8355
8356
8357int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00008358 // Fast case for objects with no elements.
8359 if (!IsJSValue() && HasFastElements()) {
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 if (length == 0) return 0;
8365 }
8366 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00008367 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
8368}
8369
8370
8371int JSObject::GetLocalElementKeys(FixedArray* storage,
8372 PropertyAttributes filter) {
8373 int counter = 0;
8374 switch (GetElementsKind()) {
8375 case FAST_ELEMENTS: {
8376 int length = IsJSArray() ?
8377 Smi::cast(JSArray::cast(this)->length())->value() :
8378 FixedArray::cast(elements())->length();
8379 for (int i = 0; i < length; i++) {
8380 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
8381 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008382 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008383 }
8384 counter++;
8385 }
8386 }
8387 ASSERT(!storage || storage->length() >= counter);
8388 break;
8389 }
Steve Block44f0eee2011-05-26 01:26:41 +01008390 case EXTERNAL_PIXEL_ELEMENTS: {
8391 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008392 while (counter < length) {
8393 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008394 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00008395 }
8396 counter++;
8397 }
8398 ASSERT(!storage || storage->length() >= counter);
8399 break;
8400 }
Steve Block3ce2e202009-11-05 08:53:23 +00008401 case EXTERNAL_BYTE_ELEMENTS:
8402 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8403 case EXTERNAL_SHORT_ELEMENTS:
8404 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8405 case EXTERNAL_INT_ELEMENTS:
8406 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8407 case EXTERNAL_FLOAT_ELEMENTS: {
8408 int length = ExternalArray::cast(elements())->length();
8409 while (counter < length) {
8410 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008411 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00008412 }
8413 counter++;
8414 }
8415 ASSERT(!storage || storage->length() >= counter);
8416 break;
8417 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008418 case DICTIONARY_ELEMENTS: {
8419 if (storage != NULL) {
8420 element_dictionary()->CopyKeysTo(storage, filter);
8421 }
8422 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
8423 break;
8424 }
8425 default:
8426 UNREACHABLE();
8427 break;
8428 }
8429
8430 if (this->IsJSValue()) {
8431 Object* val = JSValue::cast(this)->value();
8432 if (val->IsString()) {
8433 String* str = String::cast(val);
8434 if (storage) {
8435 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00008436 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008437 }
8438 }
8439 counter += str->length();
8440 }
8441 }
8442 ASSERT(!storage || storage->length() == counter);
8443 return counter;
8444}
8445
8446
8447int JSObject::GetEnumElementKeys(FixedArray* storage) {
8448 return GetLocalElementKeys(storage,
8449 static_cast<PropertyAttributes>(DONT_ENUM));
8450}
8451
8452
Steve Blocka7e24c12009-10-30 11:49:00 +00008453// StringKey simply carries a string object as key.
8454class StringKey : public HashTableKey {
8455 public:
8456 explicit StringKey(String* string) :
8457 string_(string),
8458 hash_(HashForObject(string)) { }
8459
8460 bool IsMatch(Object* string) {
8461 // We know that all entries in a hash table had their hash keys created.
8462 // Use that knowledge to have fast failure.
8463 if (hash_ != HashForObject(string)) {
8464 return false;
8465 }
8466 return string_->Equals(String::cast(string));
8467 }
8468
8469 uint32_t Hash() { return hash_; }
8470
8471 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
8472
8473 Object* AsObject() { return string_; }
8474
8475 String* string_;
8476 uint32_t hash_;
8477};
8478
8479
8480// StringSharedKeys are used as keys in the eval cache.
8481class StringSharedKey : public HashTableKey {
8482 public:
Steve Block1e0659c2011-05-24 12:43:12 +01008483 StringSharedKey(String* source,
8484 SharedFunctionInfo* shared,
8485 StrictModeFlag strict_mode)
8486 : source_(source),
8487 shared_(shared),
8488 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008489
8490 bool IsMatch(Object* other) {
8491 if (!other->IsFixedArray()) return false;
8492 FixedArray* pair = FixedArray::cast(other);
8493 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8494 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01008495 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8496 Smi::cast(pair->get(2))->value());
8497 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008498 String* source = String::cast(pair->get(1));
8499 return source->Equals(source_);
8500 }
8501
8502 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01008503 SharedFunctionInfo* shared,
8504 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008505 uint32_t hash = source->Hash();
8506 if (shared->HasSourceCode()) {
8507 // Instead of using the SharedFunctionInfo pointer in the hash
8508 // code computation, we use a combination of the hash of the
8509 // script source code and the start and end positions. We do
8510 // this to ensure that the cache entries can survive garbage
8511 // collection.
8512 Script* script = Script::cast(shared->script());
8513 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01008514 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00008515 hash += shared->start_position();
8516 }
8517 return hash;
8518 }
8519
8520 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01008521 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008522 }
8523
8524 uint32_t HashForObject(Object* obj) {
8525 FixedArray* pair = FixedArray::cast(obj);
8526 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8527 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01008528 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8529 Smi::cast(pair->get(2))->value());
8530 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00008531 }
8532
John Reck59135872010-11-02 12:39:01 -07008533 MUST_USE_RESULT MaybeObject* AsObject() {
8534 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008535 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07008536 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8537 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008538 FixedArray* pair = FixedArray::cast(obj);
8539 pair->set(0, shared_);
8540 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01008541 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00008542 return pair;
8543 }
8544
8545 private:
8546 String* source_;
8547 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01008548 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008549};
8550
8551
8552// RegExpKey carries the source and flags of a regular expression as key.
8553class RegExpKey : public HashTableKey {
8554 public:
8555 RegExpKey(String* string, JSRegExp::Flags flags)
8556 : string_(string),
8557 flags_(Smi::FromInt(flags.value())) { }
8558
Steve Block3ce2e202009-11-05 08:53:23 +00008559 // Rather than storing the key in the hash table, a pointer to the
8560 // stored value is stored where the key should be. IsMatch then
8561 // compares the search key to the found object, rather than comparing
8562 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00008563 bool IsMatch(Object* obj) {
8564 FixedArray* val = FixedArray::cast(obj);
8565 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
8566 && (flags_ == val->get(JSRegExp::kFlagsIndex));
8567 }
8568
8569 uint32_t Hash() { return RegExpHash(string_, flags_); }
8570
8571 Object* AsObject() {
8572 // Plain hash maps, which is where regexp keys are used, don't
8573 // use this function.
8574 UNREACHABLE();
8575 return NULL;
8576 }
8577
8578 uint32_t HashForObject(Object* obj) {
8579 FixedArray* val = FixedArray::cast(obj);
8580 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
8581 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
8582 }
8583
8584 static uint32_t RegExpHash(String* string, Smi* flags) {
8585 return string->Hash() + flags->value();
8586 }
8587
8588 String* string_;
8589 Smi* flags_;
8590};
8591
8592// Utf8SymbolKey carries a vector of chars as key.
8593class Utf8SymbolKey : public HashTableKey {
8594 public:
8595 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00008596 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008597
8598 bool IsMatch(Object* string) {
8599 return String::cast(string)->IsEqualTo(string_);
8600 }
8601
8602 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00008603 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008604 unibrow::Utf8InputBuffer<> buffer(string_.start(),
8605 static_cast<unsigned>(string_.length()));
8606 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00008607 hash_field_ = String::ComputeHashField(&buffer, chars_);
8608 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008609 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8610 return result;
8611 }
8612
8613 uint32_t HashForObject(Object* other) {
8614 return String::cast(other)->Hash();
8615 }
8616
John Reck59135872010-11-02 12:39:01 -07008617 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00008618 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008619 return Isolate::Current()->heap()->AllocateSymbol(
8620 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008621 }
8622
8623 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00008624 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008625 int chars_; // Caches the number of characters when computing the hash code.
8626};
8627
8628
Steve Block9fac8402011-05-12 15:51:54 +01008629template <typename Char>
8630class SequentialSymbolKey : public HashTableKey {
8631 public:
8632 explicit SequentialSymbolKey(Vector<const Char> string)
8633 : string_(string), hash_field_(0) { }
8634
8635 uint32_t Hash() {
8636 StringHasher hasher(string_.length());
8637
8638 // Very long strings have a trivial hash that doesn't inspect the
8639 // string contents.
8640 if (hasher.has_trivial_hash()) {
8641 hash_field_ = hasher.GetHashField();
8642 } else {
8643 int i = 0;
8644 // Do the iterative array index computation as long as there is a
8645 // chance this is an array index.
8646 while (i < string_.length() && hasher.is_array_index()) {
8647 hasher.AddCharacter(static_cast<uc32>(string_[i]));
8648 i++;
8649 }
8650
8651 // Process the remaining characters without updating the array
8652 // index.
8653 while (i < string_.length()) {
8654 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
8655 i++;
8656 }
8657 hash_field_ = hasher.GetHashField();
8658 }
8659
8660 uint32_t result = hash_field_ >> String::kHashShift;
8661 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8662 return result;
8663 }
8664
8665
8666 uint32_t HashForObject(Object* other) {
8667 return String::cast(other)->Hash();
8668 }
8669
8670 Vector<const Char> string_;
8671 uint32_t hash_field_;
8672};
8673
8674
8675
8676class AsciiSymbolKey : public SequentialSymbolKey<char> {
8677 public:
8678 explicit AsciiSymbolKey(Vector<const char> str)
8679 : SequentialSymbolKey<char>(str) { }
8680
8681 bool IsMatch(Object* string) {
8682 return String::cast(string)->IsAsciiEqualTo(string_);
8683 }
8684
8685 MaybeObject* AsObject() {
8686 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008687 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008688 }
8689};
8690
8691
8692class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
8693 public:
8694 explicit TwoByteSymbolKey(Vector<const uc16> str)
8695 : SequentialSymbolKey<uc16>(str) { }
8696
8697 bool IsMatch(Object* string) {
8698 return String::cast(string)->IsTwoByteEqualTo(string_);
8699 }
8700
8701 MaybeObject* AsObject() {
8702 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008703 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008704 }
8705};
8706
8707
Steve Blocka7e24c12009-10-30 11:49:00 +00008708// SymbolKey carries a string/symbol object as key.
8709class SymbolKey : public HashTableKey {
8710 public:
Steve Block44f0eee2011-05-26 01:26:41 +01008711 explicit SymbolKey(String* string)
8712 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008713
8714 bool IsMatch(Object* string) {
8715 return String::cast(string)->Equals(string_);
8716 }
8717
8718 uint32_t Hash() { return string_->Hash(); }
8719
8720 uint32_t HashForObject(Object* other) {
8721 return String::cast(other)->Hash();
8722 }
8723
John Reck59135872010-11-02 12:39:01 -07008724 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01008725 // Attempt to flatten the string, so that symbols will most often
8726 // be flat strings.
8727 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01008728 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008729 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01008730 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008731 if (map != NULL) {
8732 string_->set_map(map);
8733 ASSERT(string_->IsSymbol());
8734 return string_;
8735 }
8736 // Otherwise allocate a new symbol.
8737 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01008738 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00008739 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00008740 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00008741 }
8742
8743 static uint32_t StringHash(Object* obj) {
8744 return String::cast(obj)->Hash();
8745 }
8746
8747 String* string_;
8748};
8749
8750
8751template<typename Shape, typename Key>
8752void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
8753 IteratePointers(v, 0, kElementsStartOffset);
8754}
8755
8756
8757template<typename Shape, typename Key>
8758void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
8759 IteratePointers(v,
8760 kElementsStartOffset,
8761 kHeaderSize + length() * kPointerSize);
8762}
8763
8764
8765template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008766MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
8767 PretenureFlag pretenure) {
Steve Block6ded16b2010-05-10 14:33:55 +01008768 const int kMinCapacity = 32;
8769 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
8770 if (capacity < kMinCapacity) {
8771 capacity = kMinCapacity; // Guarantee min capacity.
Leon Clarkee46be812010-01-19 14:06:41 +00008772 } else if (capacity > HashTable::kMaxCapacity) {
8773 return Failure::OutOfMemoryException();
8774 }
8775
John Reck59135872010-11-02 12:39:01 -07008776 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008777 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
8778 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07008779 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00008780 }
John Reck59135872010-11-02 12:39:01 -07008781 HashTable::cast(obj)->SetNumberOfElements(0);
8782 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
8783 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008784 return obj;
8785}
8786
8787
Leon Clarkee46be812010-01-19 14:06:41 +00008788// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008789int StringDictionary::FindEntry(String* key) {
8790 if (!key->IsSymbol()) {
8791 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
8792 }
8793
8794 // Optimized for symbol key. Knowledge of the key type allows:
8795 // 1. Move the check if the key is a symbol out of the loop.
8796 // 2. Avoid comparing hash codes in symbol to symbol comparision.
8797 // 3. Detect a case when a dictionary key is not a symbol but the key is.
8798 // In case of positive result the dictionary key may be replaced by
8799 // the symbol with minimal performance penalty. It gives a chance to
8800 // perform further lookups in code stubs (and significant performance boost
8801 // a certain style of code).
8802
8803 // EnsureCapacity will guarantee the hash table is never full.
8804 uint32_t capacity = Capacity();
8805 uint32_t entry = FirstProbe(key->Hash(), capacity);
8806 uint32_t count = 1;
8807
8808 while (true) {
8809 int index = EntryToIndex(entry);
8810 Object* element = get(index);
8811 if (element->IsUndefined()) break; // Empty entry.
8812 if (key == element) return entry;
8813 if (!element->IsSymbol() &&
8814 !element->IsNull() &&
8815 String::cast(element)->Equals(key)) {
8816 // Replace a non-symbol key by the equivalent symbol for faster further
8817 // lookups.
8818 set(index, key);
8819 return entry;
8820 }
8821 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
8822 entry = NextProbe(entry, count++, capacity);
8823 }
8824 return kNotFound;
8825}
8826
8827
Steve Blocka7e24c12009-10-30 11:49:00 +00008828template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008829MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008830 int capacity = Capacity();
8831 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00008832 int nod = NumberOfDeletedElements();
8833 // Return if:
8834 // 50% is still free after adding n elements and
8835 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01008836 if (nod <= (capacity - nof) >> 1) {
8837 int needed_free = nof >> 1;
8838 if (nof + needed_free <= capacity) return this;
8839 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008840
Steve Block6ded16b2010-05-10 14:33:55 +01008841 const int kMinCapacityForPretenure = 256;
8842 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +01008843 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07008844 Object* obj;
8845 { MaybeObject* maybe_obj =
8846 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
8847 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8848 }
Leon Clarke4515c472010-02-03 11:58:03 +00008849
8850 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00008851 HashTable* table = HashTable::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00008852 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008853
8854 // Copy prefix to new array.
8855 for (int i = kPrefixStartIndex;
8856 i < kPrefixStartIndex + Shape::kPrefixSize;
8857 i++) {
8858 table->set(i, get(i), mode);
8859 }
8860 // Rehash the elements.
8861 for (int i = 0; i < capacity; i++) {
8862 uint32_t from_index = EntryToIndex(i);
8863 Object* k = get(from_index);
8864 if (IsKey(k)) {
8865 uint32_t hash = Shape::HashForObject(key, k);
8866 uint32_t insertion_index =
8867 EntryToIndex(table->FindInsertionEntry(hash));
8868 for (int j = 0; j < Shape::kEntrySize; j++) {
8869 table->set(insertion_index + j, get(from_index + j), mode);
8870 }
8871 }
8872 }
8873 table->SetNumberOfElements(NumberOfElements());
Leon Clarkee46be812010-01-19 14:06:41 +00008874 table->SetNumberOfDeletedElements(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008875 return table;
8876}
8877
8878
8879template<typename Shape, typename Key>
8880uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
8881 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00008882 uint32_t entry = FirstProbe(hash, capacity);
8883 uint32_t count = 1;
8884 // EnsureCapacity will guarantee the hash table is never full.
8885 while (true) {
8886 Object* element = KeyAt(entry);
8887 if (element->IsUndefined() || element->IsNull()) break;
8888 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008889 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008890 return entry;
8891}
8892
8893// Force instantiation of template instances class.
8894// Please note this list is compiler dependent.
8895
8896template class HashTable<SymbolTableShape, HashTableKey*>;
8897
8898template class HashTable<CompilationCacheShape, HashTableKey*>;
8899
8900template class HashTable<MapCacheShape, HashTableKey*>;
8901
8902template class Dictionary<StringDictionaryShape, String*>;
8903
8904template class Dictionary<NumberDictionaryShape, uint32_t>;
8905
John Reck59135872010-11-02 12:39:01 -07008906template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00008907 int);
8908
John Reck59135872010-11-02 12:39:01 -07008909template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00008910 int);
8911
John Reck59135872010-11-02 12:39:01 -07008912template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +00008913 uint32_t, Object*);
8914
8915template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
8916 Object*);
8917
8918template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
8919 Object*);
8920
8921template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
8922 FixedArray*, PropertyAttributes);
8923
8924template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
8925 int, JSObject::DeleteMode);
8926
8927template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
8928 int, JSObject::DeleteMode);
8929
8930template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
8931 FixedArray*);
8932
8933template int
8934Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
8935 PropertyAttributes);
8936
John Reck59135872010-11-02 12:39:01 -07008937template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00008938 String*, Object*, PropertyDetails);
8939
John Reck59135872010-11-02 12:39:01 -07008940template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +00008941Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
8942
8943template int
8944Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
8945 PropertyAttributes);
8946
John Reck59135872010-11-02 12:39:01 -07008947template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00008948 uint32_t, Object*, PropertyDetails);
8949
John Reck59135872010-11-02 12:39:01 -07008950template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
8951 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00008952
John Reck59135872010-11-02 12:39:01 -07008953template MaybeObject* Dictionary<StringDictionaryShape, String*>::
8954 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +00008955
John Reck59135872010-11-02 12:39:01 -07008956template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00008957 uint32_t, Object*, PropertyDetails, uint32_t);
8958
John Reck59135872010-11-02 12:39:01 -07008959template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00008960 String*, Object*, PropertyDetails, uint32_t);
8961
8962template
8963int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
8964
8965template
8966int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
8967
Leon Clarkee46be812010-01-19 14:06:41 +00008968template
8969int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
8970
8971
Steve Blocka7e24c12009-10-30 11:49:00 +00008972// Collates undefined and unexisting elements below limit from position
8973// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -07008974MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008975 ASSERT(HasDictionaryElements());
8976 // Must stay in dictionary mode, either because of requires_slow_elements,
8977 // or because we are not going to sort (and therefore compact) all of the
8978 // elements.
8979 NumberDictionary* dict = element_dictionary();
8980 HeapNumber* result_double = NULL;
8981 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
8982 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -07008983 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008984 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07008985 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
8986 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008987 result_double = HeapNumber::cast(new_double);
8988 }
8989
John Reck59135872010-11-02 12:39:01 -07008990 Object* obj;
8991 { MaybeObject* maybe_obj =
8992 NumberDictionary::Allocate(dict->NumberOfElements());
8993 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8994 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008995 NumberDictionary* new_dict = NumberDictionary::cast(obj);
8996
8997 AssertNoAllocation no_alloc;
8998
8999 uint32_t pos = 0;
9000 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01009001 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +00009002 for (int i = 0; i < capacity; i++) {
9003 Object* k = dict->KeyAt(i);
9004 if (dict->IsKey(k)) {
9005 ASSERT(k->IsNumber());
9006 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
9007 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
9008 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
9009 Object* value = dict->ValueAt(i);
9010 PropertyDetails details = dict->DetailsAt(i);
9011 if (details.type() == CALLBACKS) {
9012 // Bail out and do the sorting of undefineds and array holes in JS.
9013 return Smi::FromInt(-1);
9014 }
9015 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -07009016 // In the following we assert that adding the entry to the new dictionary
9017 // does not cause GC. This is the case because we made sure to allocate
9018 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +00009019 if (key < limit) {
9020 if (value->IsUndefined()) {
9021 undefs++;
9022 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01009023 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9024 // Adding an entry with the key beyond smi-range requires
9025 // allocation. Bailout.
9026 return Smi::FromInt(-1);
9027 }
John Reck59135872010-11-02 12:39:01 -07009028 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009029 pos++;
9030 }
9031 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01009032 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
9033 // Adding an entry with the key beyond smi-range requires
9034 // allocation. Bailout.
9035 return Smi::FromInt(-1);
9036 }
John Reck59135872010-11-02 12:39:01 -07009037 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009038 }
9039 }
9040 }
9041
9042 uint32_t result = pos;
9043 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009044 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009045 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01009046 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9047 // Adding an entry with the key beyond smi-range requires
9048 // allocation. Bailout.
9049 return Smi::FromInt(-1);
9050 }
Steve Block44f0eee2011-05-26 01:26:41 +01009051 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -07009052 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009053 pos++;
9054 undefs--;
9055 }
9056
9057 set_elements(new_dict);
9058
9059 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9060 return Smi::FromInt(static_cast<int>(result));
9061 }
9062
9063 ASSERT_NE(NULL, result_double);
9064 result_double->set_value(static_cast<double>(result));
9065 return result_double;
9066}
9067
9068
9069// Collects all defined (non-hole) and non-undefined (array) elements at
9070// the start of the elements array.
9071// If the object is in dictionary mode, it is converted to fast elements
9072// mode.
John Reck59135872010-11-02 12:39:01 -07009073MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Steve Block44f0eee2011-05-26 01:26:41 +01009074 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009075
Ben Murdoch8b112d22011-06-08 16:22:53 +01009076 Heap* heap = GetHeap();
9077
Steve Blocka7e24c12009-10-30 11:49:00 +00009078 if (HasDictionaryElements()) {
9079 // Convert to fast elements containing only the existing properties.
9080 // Ordering is irrelevant, since we are going to sort anyway.
9081 NumberDictionary* dict = element_dictionary();
9082 if (IsJSArray() || dict->requires_slow_elements() ||
9083 dict->max_number_key() >= limit) {
9084 return PrepareSlowElementsForSort(limit);
9085 }
9086 // Convert to fast elements.
9087
John Reck59135872010-11-02 12:39:01 -07009088 Object* obj;
9089 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
9090 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9091 }
Steve Block8defd9f2010-07-08 12:39:36 +01009092 Map* new_map = Map::cast(obj);
9093
Steve Block44f0eee2011-05-26 01:26:41 +01009094 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -07009095 Object* new_array;
9096 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +01009097 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -07009098 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
9099 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009100 FixedArray* fast_elements = FixedArray::cast(new_array);
9101 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +01009102
9103 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00009104 set_elements(fast_elements);
Iain Merrick75681382010-08-19 15:07:18 +01009105 } else {
John Reck59135872010-11-02 12:39:01 -07009106 Object* obj;
9107 { MaybeObject* maybe_obj = EnsureWritableFastElements();
9108 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9109 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009110 }
9111 ASSERT(HasFastElements());
9112
9113 // Collect holes at the end, undefined before that and the rest at the
9114 // start, and return the number of non-hole, non-undefined values.
9115
9116 FixedArray* elements = FixedArray::cast(this->elements());
9117 uint32_t elements_length = static_cast<uint32_t>(elements->length());
9118 if (limit > elements_length) {
9119 limit = elements_length ;
9120 }
9121 if (limit == 0) {
9122 return Smi::FromInt(0);
9123 }
9124
9125 HeapNumber* result_double = NULL;
9126 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9127 // Pessimistically allocate space for return value before
9128 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -07009129 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +01009130 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07009131 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9132 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009133 result_double = HeapNumber::cast(new_double);
9134 }
9135
9136 AssertNoAllocation no_alloc;
9137
9138 // Split elements into defined, undefined and the_hole, in that order.
9139 // Only count locations for undefined and the hole, and fill them afterwards.
Leon Clarke4515c472010-02-03 11:58:03 +00009140 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009141 unsigned int undefs = limit;
9142 unsigned int holes = limit;
9143 // Assume most arrays contain no holes and undefined values, so minimize the
9144 // number of stores of non-undefined, non-the-hole values.
9145 for (unsigned int i = 0; i < undefs; i++) {
9146 Object* current = elements->get(i);
9147 if (current->IsTheHole()) {
9148 holes--;
9149 undefs--;
9150 } else if (current->IsUndefined()) {
9151 undefs--;
9152 } else {
9153 continue;
9154 }
9155 // Position i needs to be filled.
9156 while (undefs > i) {
9157 current = elements->get(undefs);
9158 if (current->IsTheHole()) {
9159 holes--;
9160 undefs--;
9161 } else if (current->IsUndefined()) {
9162 undefs--;
9163 } else {
9164 elements->set(i, current, write_barrier);
9165 break;
9166 }
9167 }
9168 }
9169 uint32_t result = undefs;
9170 while (undefs < holes) {
9171 elements->set_undefined(undefs);
9172 undefs++;
9173 }
9174 while (holes < limit) {
9175 elements->set_the_hole(holes);
9176 holes++;
9177 }
9178
9179 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9180 return Smi::FromInt(static_cast<int>(result));
9181 }
9182 ASSERT_NE(NULL, result_double);
9183 result_double->set_value(static_cast<double>(result));
9184 return result_double;
9185}
9186
9187
Steve Block44f0eee2011-05-26 01:26:41 +01009188Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009189 uint8_t clamped_value = 0;
9190 if (index < static_cast<uint32_t>(length())) {
9191 if (value->IsSmi()) {
9192 int int_value = Smi::cast(value)->value();
9193 if (int_value < 0) {
9194 clamped_value = 0;
9195 } else if (int_value > 255) {
9196 clamped_value = 255;
9197 } else {
9198 clamped_value = static_cast<uint8_t>(int_value);
9199 }
9200 } else if (value->IsHeapNumber()) {
9201 double double_value = HeapNumber::cast(value)->value();
9202 if (!(double_value > 0)) {
9203 // NaN and less than zero clamp to zero.
9204 clamped_value = 0;
9205 } else if (double_value > 255) {
9206 // Greater than 255 clamp to 255.
9207 clamped_value = 255;
9208 } else {
9209 // Other doubles are rounded to the nearest integer.
9210 clamped_value = static_cast<uint8_t>(double_value + 0.5);
9211 }
9212 } else {
9213 // Clamp undefined to zero (default). All other types have been
9214 // converted to a number type further up in the call chain.
9215 ASSERT(value->IsUndefined());
9216 }
9217 set(index, clamped_value);
9218 }
9219 return Smi::FromInt(clamped_value);
9220}
9221
9222
Steve Block3ce2e202009-11-05 08:53:23 +00009223template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +01009224static MaybeObject* ExternalArrayIntSetter(Heap* heap,
9225 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -07009226 uint32_t index,
9227 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009228 ValueType cast_value = 0;
9229 if (index < static_cast<uint32_t>(receiver->length())) {
9230 if (value->IsSmi()) {
9231 int int_value = Smi::cast(value)->value();
9232 cast_value = static_cast<ValueType>(int_value);
9233 } else if (value->IsHeapNumber()) {
9234 double double_value = HeapNumber::cast(value)->value();
9235 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
9236 } else {
9237 // Clamp undefined to zero (default). All other types have been
9238 // converted to a number type further up in the call chain.
9239 ASSERT(value->IsUndefined());
9240 }
9241 receiver->set(index, cast_value);
9242 }
Steve Block44f0eee2011-05-26 01:26:41 +01009243 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009244}
9245
9246
John Reck59135872010-11-02 12:39:01 -07009247MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009248 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009249 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009250}
9251
9252
John Reck59135872010-11-02 12:39:01 -07009253MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
9254 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009255 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009256 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009257}
9258
9259
John Reck59135872010-11-02 12:39:01 -07009260MaybeObject* ExternalShortArray::SetValue(uint32_t index,
9261 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009262 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009263 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009264}
9265
9266
John Reck59135872010-11-02 12:39:01 -07009267MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
9268 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009269 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009270 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009271}
9272
9273
John Reck59135872010-11-02 12:39:01 -07009274MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009275 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009276 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009277}
9278
9279
John Reck59135872010-11-02 12:39:01 -07009280MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009281 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009282 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009283 if (index < static_cast<uint32_t>(length())) {
9284 if (value->IsSmi()) {
9285 int int_value = Smi::cast(value)->value();
9286 cast_value = static_cast<uint32_t>(int_value);
9287 } else if (value->IsHeapNumber()) {
9288 double double_value = HeapNumber::cast(value)->value();
9289 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
9290 } else {
9291 // Clamp undefined to zero (default). All other types have been
9292 // converted to a number type further up in the call chain.
9293 ASSERT(value->IsUndefined());
9294 }
9295 set(index, cast_value);
9296 }
Steve Block44f0eee2011-05-26 01:26:41 +01009297 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009298}
9299
9300
John Reck59135872010-11-02 12:39:01 -07009301MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009302 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009303 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009304 if (index < static_cast<uint32_t>(length())) {
9305 if (value->IsSmi()) {
9306 int int_value = Smi::cast(value)->value();
9307 cast_value = static_cast<float>(int_value);
9308 } else if (value->IsHeapNumber()) {
9309 double double_value = HeapNumber::cast(value)->value();
9310 cast_value = static_cast<float>(double_value);
9311 } else {
9312 // Clamp undefined to zero (default). All other types have been
9313 // converted to a number type further up in the call chain.
9314 ASSERT(value->IsUndefined());
9315 }
9316 set(index, cast_value);
9317 }
Steve Block44f0eee2011-05-26 01:26:41 +01009318 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009319}
9320
9321
Ben Murdochb0fe1622011-05-05 13:52:32 +01009322JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009323 ASSERT(!HasFastProperties());
9324 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009325 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009326}
9327
9328
John Reck59135872010-11-02 12:39:01 -07009329MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009330 ASSERT(!HasFastProperties());
9331 int entry = property_dictionary()->FindEntry(name);
9332 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009333 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07009334 Object* cell;
9335 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +01009336 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -07009337 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
9338 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009339 PropertyDetails details(NONE, NORMAL);
9340 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -07009341 Object* dictionary;
9342 { MaybeObject* maybe_dictionary =
9343 property_dictionary()->Add(name, cell, details);
9344 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
9345 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009346 set_properties(StringDictionary::cast(dictionary));
9347 return cell;
9348 } else {
9349 Object* value = property_dictionary()->ValueAt(entry);
9350 ASSERT(value->IsJSGlobalPropertyCell());
9351 return value;
9352 }
9353}
9354
9355
John Reck59135872010-11-02 12:39:01 -07009356MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009357 SymbolKey key(string);
9358 return LookupKey(&key, s);
9359}
9360
9361
Steve Blockd0582a62009-12-15 09:54:21 +00009362// This class is used for looking up two character strings in the symbol table.
9363// If we don't have a hit we don't want to waste much time so we unroll the
9364// string hash calculation loop here for speed. Doesn't work if the two
9365// characters form a decimal integer, since such strings have a different hash
9366// algorithm.
9367class TwoCharHashTableKey : public HashTableKey {
9368 public:
9369 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
9370 : c1_(c1), c2_(c2) {
9371 // Char 1.
9372 uint32_t hash = c1 + (c1 << 10);
9373 hash ^= hash >> 6;
9374 // Char 2.
9375 hash += c2;
9376 hash += hash << 10;
9377 hash ^= hash >> 6;
9378 // GetHash.
9379 hash += hash << 3;
9380 hash ^= hash >> 11;
9381 hash += hash << 15;
9382 if (hash == 0) hash = 27;
9383#ifdef DEBUG
9384 StringHasher hasher(2);
9385 hasher.AddCharacter(c1);
9386 hasher.AddCharacter(c2);
9387 // If this assert fails then we failed to reproduce the two-character
9388 // version of the string hashing algorithm above. One reason could be
9389 // that we were passed two digits as characters, since the hash
9390 // algorithm is different in that case.
9391 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
9392#endif
9393 hash_ = hash;
9394 }
9395
9396 bool IsMatch(Object* o) {
9397 if (!o->IsString()) return false;
9398 String* other = String::cast(o);
9399 if (other->length() != 2) return false;
9400 if (other->Get(0) != c1_) return false;
9401 return other->Get(1) == c2_;
9402 }
9403
9404 uint32_t Hash() { return hash_; }
9405 uint32_t HashForObject(Object* key) {
9406 if (!key->IsString()) return 0;
9407 return String::cast(key)->Hash();
9408 }
9409
9410 Object* AsObject() {
9411 // The TwoCharHashTableKey is only used for looking in the symbol
9412 // table, not for adding to it.
9413 UNREACHABLE();
9414 return NULL;
9415 }
9416 private:
9417 uint32_t c1_;
9418 uint32_t c2_;
9419 uint32_t hash_;
9420};
9421
9422
Steve Blocka7e24c12009-10-30 11:49:00 +00009423bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
9424 SymbolKey key(string);
9425 int entry = FindEntry(&key);
9426 if (entry == kNotFound) {
9427 return false;
9428 } else {
9429 String* result = String::cast(KeyAt(entry));
9430 ASSERT(StringShape(result).IsSymbol());
9431 *symbol = result;
9432 return true;
9433 }
9434}
9435
9436
Steve Blockd0582a62009-12-15 09:54:21 +00009437bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
9438 uint32_t c2,
9439 String** symbol) {
9440 TwoCharHashTableKey key(c1, c2);
9441 int entry = FindEntry(&key);
9442 if (entry == kNotFound) {
9443 return false;
9444 } else {
9445 String* result = String::cast(KeyAt(entry));
9446 ASSERT(StringShape(result).IsSymbol());
9447 *symbol = result;
9448 return true;
9449 }
9450}
9451
9452
John Reck59135872010-11-02 12:39:01 -07009453MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009454 Utf8SymbolKey key(str);
9455 return LookupKey(&key, s);
9456}
9457
9458
Steve Block9fac8402011-05-12 15:51:54 +01009459MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
9460 Object** s) {
9461 AsciiSymbolKey key(str);
9462 return LookupKey(&key, s);
9463}
9464
9465
9466MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
9467 Object** s) {
9468 TwoByteSymbolKey key(str);
9469 return LookupKey(&key, s);
9470}
9471
John Reck59135872010-11-02 12:39:01 -07009472MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009473 int entry = FindEntry(key);
9474
9475 // Symbol already in table.
9476 if (entry != kNotFound) {
9477 *s = KeyAt(entry);
9478 return this;
9479 }
9480
9481 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -07009482 Object* obj;
9483 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9484 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9485 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009486
9487 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -07009488 Object* symbol;
9489 { MaybeObject* maybe_symbol = key->AsObject();
9490 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
9491 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009492
9493 // If the symbol table grew as part of EnsureCapacity, obj is not
9494 // the current symbol table and therefore we cannot use
9495 // SymbolTable::cast here.
9496 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
9497
9498 // Add the new symbol and return it along with the symbol table.
9499 entry = table->FindInsertionEntry(key->Hash());
9500 table->set(EntryToIndex(entry), symbol);
9501 table->ElementAdded();
9502 *s = symbol;
9503 return table;
9504}
9505
9506
9507Object* CompilationCacheTable::Lookup(String* src) {
9508 StringKey key(src);
9509 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009510 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009511 return get(EntryToIndex(entry) + 1);
9512}
9513
9514
Steve Block1e0659c2011-05-24 12:43:12 +01009515Object* CompilationCacheTable::LookupEval(String* src,
9516 Context* context,
9517 StrictModeFlag strict_mode) {
9518 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009519 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009520 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009521 return get(EntryToIndex(entry) + 1);
9522}
9523
9524
9525Object* CompilationCacheTable::LookupRegExp(String* src,
9526 JSRegExp::Flags flags) {
9527 RegExpKey key(src, flags);
9528 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009529 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009530 return get(EntryToIndex(entry) + 1);
9531}
9532
9533
John Reck59135872010-11-02 12:39:01 -07009534MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009535 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -07009536 Object* obj;
9537 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9538 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9539 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009540
9541 CompilationCacheTable* cache =
9542 reinterpret_cast<CompilationCacheTable*>(obj);
9543 int entry = cache->FindInsertionEntry(key.Hash());
9544 cache->set(EntryToIndex(entry), src);
9545 cache->set(EntryToIndex(entry) + 1, value);
9546 cache->ElementAdded();
9547 return cache;
9548}
9549
9550
John Reck59135872010-11-02 12:39:01 -07009551MaybeObject* CompilationCacheTable::PutEval(String* src,
9552 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +01009553 SharedFunctionInfo* value) {
9554 StringSharedKey key(src,
9555 context->closure()->shared(),
9556 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -07009557 Object* obj;
9558 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9559 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9560 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009561
9562 CompilationCacheTable* cache =
9563 reinterpret_cast<CompilationCacheTable*>(obj);
9564 int entry = cache->FindInsertionEntry(key.Hash());
9565
John Reck59135872010-11-02 12:39:01 -07009566 Object* k;
9567 { MaybeObject* maybe_k = key.AsObject();
9568 if (!maybe_k->ToObject(&k)) return maybe_k;
9569 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009570
9571 cache->set(EntryToIndex(entry), k);
9572 cache->set(EntryToIndex(entry) + 1, value);
9573 cache->ElementAdded();
9574 return cache;
9575}
9576
9577
John Reck59135872010-11-02 12:39:01 -07009578MaybeObject* CompilationCacheTable::PutRegExp(String* src,
9579 JSRegExp::Flags flags,
9580 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009581 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -07009582 Object* obj;
9583 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9584 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9585 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009586
9587 CompilationCacheTable* cache =
9588 reinterpret_cast<CompilationCacheTable*>(obj);
9589 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +00009590 // We store the value in the key slot, and compare the search key
9591 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +00009592 cache->set(EntryToIndex(entry), value);
9593 cache->set(EntryToIndex(entry) + 1, value);
9594 cache->ElementAdded();
9595 return cache;
9596}
9597
9598
Ben Murdochb0fe1622011-05-05 13:52:32 +01009599void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009600 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01009601 for (int entry = 0, size = Capacity(); entry < size; entry++) {
9602 int entry_index = EntryToIndex(entry);
9603 int value_index = entry_index + 1;
9604 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009605 fast_set(this, entry_index, null_value);
9606 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009607 ElementRemoved();
9608 }
9609 }
9610 return;
9611}
9612
9613
Steve Blocka7e24c12009-10-30 11:49:00 +00009614// SymbolsKey used for HashTable where key is array of symbols.
9615class SymbolsKey : public HashTableKey {
9616 public:
9617 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
9618
9619 bool IsMatch(Object* symbols) {
9620 FixedArray* o = FixedArray::cast(symbols);
9621 int len = symbols_->length();
9622 if (o->length() != len) return false;
9623 for (int i = 0; i < len; i++) {
9624 if (o->get(i) != symbols_->get(i)) return false;
9625 }
9626 return true;
9627 }
9628
9629 uint32_t Hash() { return HashForObject(symbols_); }
9630
9631 uint32_t HashForObject(Object* obj) {
9632 FixedArray* symbols = FixedArray::cast(obj);
9633 int len = symbols->length();
9634 uint32_t hash = 0;
9635 for (int i = 0; i < len; i++) {
9636 hash ^= String::cast(symbols->get(i))->Hash();
9637 }
9638 return hash;
9639 }
9640
9641 Object* AsObject() { return symbols_; }
9642
9643 private:
9644 FixedArray* symbols_;
9645};
9646
9647
9648Object* MapCache::Lookup(FixedArray* array) {
9649 SymbolsKey key(array);
9650 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009651 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009652 return get(EntryToIndex(entry) + 1);
9653}
9654
9655
John Reck59135872010-11-02 12:39:01 -07009656MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009657 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -07009658 Object* obj;
9659 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9660 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9661 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009662
9663 MapCache* cache = reinterpret_cast<MapCache*>(obj);
9664 int entry = cache->FindInsertionEntry(key.Hash());
9665 cache->set(EntryToIndex(entry), array);
9666 cache->set(EntryToIndex(entry) + 1, value);
9667 cache->ElementAdded();
9668 return cache;
9669}
9670
9671
9672template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009673MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
9674 Object* obj;
9675 { MaybeObject* maybe_obj =
9676 HashTable<Shape, Key>::Allocate(at_least_space_for);
9677 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009678 }
John Reck59135872010-11-02 12:39:01 -07009679 // Initialize the next enumeration index.
9680 Dictionary<Shape, Key>::cast(obj)->
9681 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +00009682 return obj;
9683}
9684
9685
9686template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009687MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +01009688 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009689 int length = HashTable<Shape, Key>::NumberOfElements();
9690
9691 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -07009692 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009693 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009694 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9695 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009696 FixedArray* iteration_order = FixedArray::cast(obj);
9697 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009698 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009699 }
9700
9701 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +01009702 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009703 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9704 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009705 FixedArray* enumeration_order = FixedArray::cast(obj);
9706
9707 // Fill the enumeration order array with property details.
9708 int capacity = HashTable<Shape, Key>::Capacity();
9709 int pos = 0;
9710 for (int i = 0; i < capacity; i++) {
9711 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +00009712 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009713 }
9714 }
9715
9716 // Sort the arrays wrt. enumeration order.
9717 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
9718
9719 // Overwrite the enumeration_order with the enumeration indices.
9720 for (int i = 0; i < length; i++) {
9721 int index = Smi::cast(iteration_order->get(i))->value();
9722 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +00009723 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +00009724 }
9725
9726 // Update the dictionary with new indices.
9727 capacity = HashTable<Shape, Key>::Capacity();
9728 pos = 0;
9729 for (int i = 0; i < capacity; i++) {
9730 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
9731 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
9732 PropertyDetails details = DetailsAt(i);
9733 PropertyDetails new_details =
9734 PropertyDetails(details.attributes(), details.type(), enum_index);
9735 DetailsAtPut(i, new_details);
9736 }
9737 }
9738
9739 // Set the next enumeration index.
9740 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
9741 return this;
9742}
9743
9744template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009745MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009746 // Check whether there are enough enumeration indices to add n elements.
9747 if (Shape::kIsEnumerable &&
9748 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
9749 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -07009750 Object* result;
9751 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
9752 if (!maybe_result->ToObject(&result)) return maybe_result;
9753 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009754 }
9755 return HashTable<Shape, Key>::EnsureCapacity(n, key);
9756}
9757
9758
9759void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
9760 // Do nothing if the interval [from, to) is empty.
9761 if (from >= to) return;
9762
Steve Block44f0eee2011-05-26 01:26:41 +01009763 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009764 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009765 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009766 int capacity = Capacity();
9767 for (int i = 0; i < capacity; i++) {
9768 Object* key = KeyAt(i);
9769 if (key->IsNumber()) {
9770 uint32_t number = static_cast<uint32_t>(key->Number());
9771 if (from <= number && number < to) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009772 SetEntry(i, sentinel, sentinel);
Steve Blocka7e24c12009-10-30 11:49:00 +00009773 removed_entries++;
9774 }
9775 }
9776 }
9777
9778 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +00009779 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +00009780}
9781
9782
9783template<typename Shape, typename Key>
9784Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
9785 JSObject::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01009786 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009787 PropertyDetails details = DetailsAt(entry);
9788 // Ignore attributes if forcing a deletion.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009789 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +01009790 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009791 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009792 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009793 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +01009794 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009795}
9796
9797
9798template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009799MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009800 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +00009801
9802 // If the entry is present set the value;
9803 if (entry != Dictionary<Shape, Key>::kNotFound) {
9804 ValueAtPut(entry, value);
9805 return this;
9806 }
9807
9808 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -07009809 Object* obj;
9810 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9811 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9812 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009813
John Reck59135872010-11-02 12:39:01 -07009814 Object* k;
9815 { MaybeObject* maybe_k = Shape::AsObject(key);
9816 if (!maybe_k->ToObject(&k)) return maybe_k;
9817 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009818 PropertyDetails details = PropertyDetails(NONE, NORMAL);
9819 return Dictionary<Shape, Key>::cast(obj)->
9820 AddEntry(key, value, details, Shape::Hash(key));
9821}
9822
9823
9824template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009825MaybeObject* Dictionary<Shape, Key>::Add(Key key,
9826 Object* value,
9827 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009828 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009829 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +00009830 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -07009831 Object* obj;
9832 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9833 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9834 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009835 return Dictionary<Shape, Key>::cast(obj)->
9836 AddEntry(key, value, details, Shape::Hash(key));
9837}
9838
9839
9840// Add a key, value pair to the dictionary.
9841template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009842MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
9843 Object* value,
9844 PropertyDetails details,
9845 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009846 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -07009847 Object* k;
9848 { MaybeObject* maybe_k = Shape::AsObject(key);
9849 if (!maybe_k->ToObject(&k)) return maybe_k;
9850 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009851
9852 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
9853 // Insert element at empty or deleted entry
9854 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
9855 // Assign an enumeration index to the property and update
9856 // SetNextEnumerationIndex.
9857 int index = NextEnumerationIndex();
9858 details = PropertyDetails(details.attributes(), details.type(), index);
9859 SetNextEnumerationIndex(index + 1);
9860 }
9861 SetEntry(entry, k, value, details);
9862 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
9863 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
9864 HashTable<Shape, Key>::ElementAdded();
9865 return this;
9866}
9867
9868
9869void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
9870 // If the dictionary requires slow elements an element has already
9871 // been added at a high index.
9872 if (requires_slow_elements()) return;
9873 // Check if this index is high enough that we should require slow
9874 // elements.
9875 if (key > kRequiresSlowElementsLimit) {
9876 set_requires_slow_elements();
9877 return;
9878 }
9879 // Update max key value.
9880 Object* max_index_object = get(kMaxNumberKeyIndex);
9881 if (!max_index_object->IsSmi() || max_number_key() < key) {
9882 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00009883 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00009884 }
9885}
9886
9887
John Reck59135872010-11-02 12:39:01 -07009888MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
9889 Object* value,
9890 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009891 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009892 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +00009893 return Add(key, value, details);
9894}
9895
9896
John Reck59135872010-11-02 12:39:01 -07009897MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009898 UpdateMaxNumberKey(key);
9899 return AtPut(key, value);
9900}
9901
9902
John Reck59135872010-11-02 12:39:01 -07009903MaybeObject* NumberDictionary::Set(uint32_t key,
9904 Object* value,
9905 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009906 int entry = FindEntry(key);
9907 if (entry == kNotFound) return AddNumberEntry(key, value, details);
9908 // Preserve enumeration index.
9909 details = PropertyDetails(details.attributes(),
9910 details.type(),
9911 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -07009912 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
9913 Object* object_key;
9914 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +01009915 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00009916 return this;
9917}
9918
9919
9920
9921template<typename Shape, typename Key>
9922int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
9923 PropertyAttributes filter) {
9924 int capacity = HashTable<Shape, Key>::Capacity();
9925 int result = 0;
9926 for (int i = 0; i < capacity; i++) {
9927 Object* k = HashTable<Shape, Key>::KeyAt(i);
9928 if (HashTable<Shape, Key>::IsKey(k)) {
9929 PropertyDetails details = DetailsAt(i);
9930 if (details.IsDeleted()) continue;
9931 PropertyAttributes attr = details.attributes();
9932 if ((attr & filter) == 0) result++;
9933 }
9934 }
9935 return result;
9936}
9937
9938
9939template<typename Shape, typename Key>
9940int Dictionary<Shape, Key>::NumberOfEnumElements() {
9941 return NumberOfElementsFilterAttributes(
9942 static_cast<PropertyAttributes>(DONT_ENUM));
9943}
9944
9945
9946template<typename Shape, typename Key>
9947void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
9948 PropertyAttributes filter) {
9949 ASSERT(storage->length() >= NumberOfEnumElements());
9950 int capacity = HashTable<Shape, Key>::Capacity();
9951 int index = 0;
9952 for (int i = 0; i < capacity; i++) {
9953 Object* k = HashTable<Shape, Key>::KeyAt(i);
9954 if (HashTable<Shape, Key>::IsKey(k)) {
9955 PropertyDetails details = DetailsAt(i);
9956 if (details.IsDeleted()) continue;
9957 PropertyAttributes attr = details.attributes();
9958 if ((attr & filter) == 0) storage->set(index++, k);
9959 }
9960 }
9961 storage->SortPairs(storage, index);
9962 ASSERT(storage->length() >= index);
9963}
9964
9965
9966void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
9967 FixedArray* sort_array) {
9968 ASSERT(storage->length() >= NumberOfEnumElements());
9969 int capacity = Capacity();
9970 int index = 0;
9971 for (int i = 0; i < capacity; i++) {
9972 Object* k = KeyAt(i);
9973 if (IsKey(k)) {
9974 PropertyDetails details = DetailsAt(i);
9975 if (details.IsDeleted() || details.IsDontEnum()) continue;
9976 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +00009977 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009978 index++;
9979 }
9980 }
9981 storage->SortPairs(sort_array, sort_array->length());
9982 ASSERT(storage->length() >= index);
9983}
9984
9985
9986template<typename Shape, typename Key>
9987void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
9988 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
9989 static_cast<PropertyAttributes>(NONE)));
9990 int capacity = HashTable<Shape, Key>::Capacity();
9991 int index = 0;
9992 for (int i = 0; i < capacity; i++) {
9993 Object* k = HashTable<Shape, Key>::KeyAt(i);
9994 if (HashTable<Shape, Key>::IsKey(k)) {
9995 PropertyDetails details = DetailsAt(i);
9996 if (details.IsDeleted()) continue;
9997 storage->set(index++, k);
9998 }
9999 }
10000 ASSERT(storage->length() >= index);
10001}
10002
10003
10004// Backwards lookup (slow).
10005template<typename Shape, typename Key>
10006Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
10007 int capacity = HashTable<Shape, Key>::Capacity();
10008 for (int i = 0; i < capacity; i++) {
10009 Object* k = HashTable<Shape, Key>::KeyAt(i);
10010 if (Dictionary<Shape, Key>::IsKey(k)) {
10011 Object* e = ValueAt(i);
10012 if (e->IsJSGlobalPropertyCell()) {
10013 e = JSGlobalPropertyCell::cast(e)->value();
10014 }
10015 if (e == value) return k;
10016 }
10017 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010018 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010010019 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010020}
10021
10022
John Reck59135872010-11-02 12:39:01 -070010023MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000010024 JSObject* obj, int unused_property_fields) {
10025 // Make sure we preserve dictionary representation if there are too many
10026 // descriptors.
10027 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
10028
10029 // Figure out if it is necessary to generate new enumeration indices.
10030 int max_enumeration_index =
10031 NextEnumerationIndex() +
10032 (DescriptorArray::kMaxNumberOfDescriptors -
10033 NumberOfElements());
10034 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070010035 Object* result;
10036 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10037 if (!maybe_result->ToObject(&result)) return maybe_result;
10038 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010039 }
10040
10041 int instance_descriptor_length = 0;
10042 int number_of_fields = 0;
10043
Ben Murdoch8b112d22011-06-08 16:22:53 +010010044 Heap* heap = GetHeap();
10045
Steve Blocka7e24c12009-10-30 11:49:00 +000010046 // Compute the length of the instance descriptor.
10047 int capacity = Capacity();
10048 for (int i = 0; i < capacity; i++) {
10049 Object* k = KeyAt(i);
10050 if (IsKey(k)) {
10051 Object* value = ValueAt(i);
10052 PropertyType type = DetailsAt(i).type();
10053 ASSERT(type != FIELD);
10054 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000010055 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010010056 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000010057 number_of_fields += 1;
10058 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010059 }
10060 }
10061
10062 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070010063 Object* descriptors_unchecked;
10064 { MaybeObject* maybe_descriptors_unchecked =
10065 DescriptorArray::Allocate(instance_descriptor_length);
10066 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
10067 return maybe_descriptors_unchecked;
10068 }
10069 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010070 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
10071
10072 int inobject_props = obj->map()->inobject_properties();
10073 int number_of_allocated_fields =
10074 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010010075 if (number_of_allocated_fields < 0) {
10076 // There is enough inobject space for all fields (including unused).
10077 number_of_allocated_fields = 0;
10078 unused_property_fields = inobject_props - number_of_fields;
10079 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010080
10081 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070010082 Object* fields;
10083 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010010084 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070010085 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
10086 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010087
10088 // Fill in the instance descriptor and the fields.
10089 int next_descriptor = 0;
10090 int current_offset = 0;
10091 for (int i = 0; i < capacity; i++) {
10092 Object* k = KeyAt(i);
10093 if (IsKey(k)) {
10094 Object* value = ValueAt(i);
10095 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070010096 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010010097 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070010098 if (!maybe_key->ToObject(&key)) return maybe_key;
10099 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010100 PropertyDetails details = DetailsAt(i);
10101 PropertyType type = details.type();
10102
Steve Block44f0eee2011-05-26 01:26:41 +010010103 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010104 ConstantFunctionDescriptor d(String::cast(key),
10105 JSFunction::cast(value),
10106 details.attributes(),
10107 details.index());
10108 descriptors->Set(next_descriptor++, &d);
10109 } else if (type == NORMAL) {
10110 if (current_offset < inobject_props) {
10111 obj->InObjectPropertyAtPut(current_offset,
10112 value,
10113 UPDATE_WRITE_BARRIER);
10114 } else {
10115 int offset = current_offset - inobject_props;
10116 FixedArray::cast(fields)->set(offset, value);
10117 }
10118 FieldDescriptor d(String::cast(key),
10119 current_offset++,
10120 details.attributes(),
10121 details.index());
10122 descriptors->Set(next_descriptor++, &d);
10123 } else if (type == CALLBACKS) {
10124 CallbacksDescriptor d(String::cast(key),
10125 value,
10126 details.attributes(),
10127 details.index());
10128 descriptors->Set(next_descriptor++, &d);
10129 } else {
10130 UNREACHABLE();
10131 }
10132 }
10133 }
10134 ASSERT(current_offset == number_of_fields);
10135
10136 descriptors->Sort();
10137 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070010138 Object* new_map;
10139 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
10140 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10141 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010142
10143 // Transform the object.
10144 obj->set_map(Map::cast(new_map));
10145 obj->map()->set_instance_descriptors(descriptors);
10146 obj->map()->set_unused_property_fields(unused_property_fields);
10147
10148 obj->set_properties(FixedArray::cast(fields));
10149 ASSERT(obj->IsJSObject());
10150
10151 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
10152 // Check that it really works.
10153 ASSERT(obj->HasFastProperties());
10154
10155 return obj;
10156}
10157
10158
10159#ifdef ENABLE_DEBUGGER_SUPPORT
10160// Check if there is a break point at this code position.
10161bool DebugInfo::HasBreakPoint(int code_position) {
10162 // Get the break point info object for this code position.
10163 Object* break_point_info = GetBreakPointInfo(code_position);
10164
10165 // If there is no break point info object or no break points in the break
10166 // point info object there is no break point at this code position.
10167 if (break_point_info->IsUndefined()) return false;
10168 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
10169}
10170
10171
10172// Get the break point info object for this code position.
10173Object* DebugInfo::GetBreakPointInfo(int code_position) {
10174 // Find the index of the break point info object for this code position.
10175 int index = GetBreakPointInfoIndex(code_position);
10176
10177 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010178 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010179 return BreakPointInfo::cast(break_points()->get(index));
10180}
10181
10182
10183// Clear a break point at the specified code position.
10184void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
10185 int code_position,
10186 Handle<Object> break_point_object) {
10187 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10188 if (break_point_info->IsUndefined()) return;
10189 BreakPointInfo::ClearBreakPoint(
10190 Handle<BreakPointInfo>::cast(break_point_info),
10191 break_point_object);
10192}
10193
10194
10195void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
10196 int code_position,
10197 int source_position,
10198 int statement_position,
10199 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010200 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010201 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10202 if (!break_point_info->IsUndefined()) {
10203 BreakPointInfo::SetBreakPoint(
10204 Handle<BreakPointInfo>::cast(break_point_info),
10205 break_point_object);
10206 return;
10207 }
10208
10209 // Adding a new break point for a code position which did not have any
10210 // break points before. Try to find a free slot.
10211 int index = kNoBreakPointInfo;
10212 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10213 if (debug_info->break_points()->get(i)->IsUndefined()) {
10214 index = i;
10215 break;
10216 }
10217 }
10218 if (index == kNoBreakPointInfo) {
10219 // No free slot - extend break point info array.
10220 Handle<FixedArray> old_break_points =
10221 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010222 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010010223 isolate->factory()->NewFixedArray(
10224 old_break_points->length() +
10225 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010226
10227 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000010228 for (int i = 0; i < old_break_points->length(); i++) {
10229 new_break_points->set(i, old_break_points->get(i));
10230 }
10231 index = old_break_points->length();
10232 }
10233 ASSERT(index != kNoBreakPointInfo);
10234
10235 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010010236 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
10237 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000010238 new_break_point_info->set_code_position(Smi::FromInt(code_position));
10239 new_break_point_info->set_source_position(Smi::FromInt(source_position));
10240 new_break_point_info->
10241 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010010242 new_break_point_info->set_break_point_objects(
10243 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010244 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
10245 debug_info->break_points()->set(index, *new_break_point_info);
10246}
10247
10248
10249// Get the break point objects for a code position.
10250Object* DebugInfo::GetBreakPointObjects(int code_position) {
10251 Object* break_point_info = GetBreakPointInfo(code_position);
10252 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010253 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010254 }
10255 return BreakPointInfo::cast(break_point_info)->break_point_objects();
10256}
10257
10258
10259// Get the total number of break points.
10260int DebugInfo::GetBreakPointCount() {
10261 if (break_points()->IsUndefined()) return 0;
10262 int count = 0;
10263 for (int i = 0; i < break_points()->length(); i++) {
10264 if (!break_points()->get(i)->IsUndefined()) {
10265 BreakPointInfo* break_point_info =
10266 BreakPointInfo::cast(break_points()->get(i));
10267 count += break_point_info->GetBreakPointCount();
10268 }
10269 }
10270 return count;
10271}
10272
10273
10274Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
10275 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010276 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010010277 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010278 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10279 if (!debug_info->break_points()->get(i)->IsUndefined()) {
10280 Handle<BreakPointInfo> break_point_info =
10281 Handle<BreakPointInfo>(BreakPointInfo::cast(
10282 debug_info->break_points()->get(i)));
10283 if (BreakPointInfo::HasBreakPointObject(break_point_info,
10284 break_point_object)) {
10285 return *break_point_info;
10286 }
10287 }
10288 }
Steve Block44f0eee2011-05-26 01:26:41 +010010289 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010290}
10291
10292
10293// Find the index of the break point info object for the specified code
10294// position.
10295int DebugInfo::GetBreakPointInfoIndex(int code_position) {
10296 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
10297 for (int i = 0; i < break_points()->length(); i++) {
10298 if (!break_points()->get(i)->IsUndefined()) {
10299 BreakPointInfo* break_point_info =
10300 BreakPointInfo::cast(break_points()->get(i));
10301 if (break_point_info->code_position()->value() == code_position) {
10302 return i;
10303 }
10304 }
10305 }
10306 return kNoBreakPointInfo;
10307}
10308
10309
10310// Remove the specified break point object.
10311void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
10312 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010313 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010314 // If there are no break points just ignore.
10315 if (break_point_info->break_point_objects()->IsUndefined()) return;
10316 // If there is a single break point clear it if it is the same.
10317 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10318 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010319 break_point_info->set_break_point_objects(
10320 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010321 }
10322 return;
10323 }
10324 // If there are multiple break points shrink the array
10325 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
10326 Handle<FixedArray> old_array =
10327 Handle<FixedArray>(
10328 FixedArray::cast(break_point_info->break_point_objects()));
10329 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010330 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010331 int found_count = 0;
10332 for (int i = 0; i < old_array->length(); i++) {
10333 if (old_array->get(i) == *break_point_object) {
10334 ASSERT(found_count == 0);
10335 found_count++;
10336 } else {
10337 new_array->set(i - found_count, old_array->get(i));
10338 }
10339 }
10340 // If the break point was found in the list change it.
10341 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
10342}
10343
10344
10345// Add the specified break point object.
10346void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
10347 Handle<Object> break_point_object) {
10348 // If there was no break point objects before just set it.
10349 if (break_point_info->break_point_objects()->IsUndefined()) {
10350 break_point_info->set_break_point_objects(*break_point_object);
10351 return;
10352 }
10353 // If the break point object is the same as before just ignore.
10354 if (break_point_info->break_point_objects() == *break_point_object) return;
10355 // If there was one break point object before replace with array.
10356 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010357 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010358 array->set(0, break_point_info->break_point_objects());
10359 array->set(1, *break_point_object);
10360 break_point_info->set_break_point_objects(*array);
10361 return;
10362 }
10363 // If there was more than one break point before extend array.
10364 Handle<FixedArray> old_array =
10365 Handle<FixedArray>(
10366 FixedArray::cast(break_point_info->break_point_objects()));
10367 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010368 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010369 for (int i = 0; i < old_array->length(); i++) {
10370 // If the break point was there before just ignore.
10371 if (old_array->get(i) == *break_point_object) return;
10372 new_array->set(i, old_array->get(i));
10373 }
10374 // Add the new break point.
10375 new_array->set(old_array->length(), *break_point_object);
10376 break_point_info->set_break_point_objects(*new_array);
10377}
10378
10379
10380bool BreakPointInfo::HasBreakPointObject(
10381 Handle<BreakPointInfo> break_point_info,
10382 Handle<Object> break_point_object) {
10383 // No break point.
10384 if (break_point_info->break_point_objects()->IsUndefined()) return false;
10385 // Single beak point.
10386 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10387 return break_point_info->break_point_objects() == *break_point_object;
10388 }
10389 // Multiple break points.
10390 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
10391 for (int i = 0; i < array->length(); i++) {
10392 if (array->get(i) == *break_point_object) {
10393 return true;
10394 }
10395 }
10396 return false;
10397}
10398
10399
10400// Get the number of break points.
10401int BreakPointInfo::GetBreakPointCount() {
10402 // No break point.
10403 if (break_point_objects()->IsUndefined()) return 0;
10404 // Single beak point.
10405 if (!break_point_objects()->IsFixedArray()) return 1;
10406 // Multiple break points.
10407 return FixedArray::cast(break_point_objects())->length();
10408}
10409#endif
10410
10411
10412} } // namespace v8::internal