blob: 6ce4c44177e61c40a99d40ec5287cb72feea6656 [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) {
3716 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003717 Map* meta_map = heap()->meta_map();
3718 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003719 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
3720 *RawField(current, Map::kInstanceDescriptorsOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01003721 if (d == heap()->empty_descriptor_array()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003722 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003723 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003724 callback(current, data);
3725 current = prev;
3726 continue;
3727 }
3728
3729 FixedArray* contents = reinterpret_cast<FixedArray*>(
3730 d->get(DescriptorArray::kContentArrayIndex));
3731 Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3732 Object* map_or_index = *map_or_index_field;
3733 bool map_done = true;
3734 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3735 i < contents->length();
3736 i += 2) {
3737 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3738 if (details.IsTransition()) {
3739 Map* next = reinterpret_cast<Map*>(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;
Steve Block44f0eee2011-05-26 01:26:41 +01003748 *map_or_index_field = heap()->fixed_array_map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003749 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003750 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003751 callback(current, data);
3752 current = prev;
3753 }
3754}
3755
3756
John Reck59135872010-11-02 12:39:01 -07003757MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003758 ASSERT(code->ic_state() == MONOMORPHIC);
3759
3760 // The number of monomorphic stubs for normal load/store/call IC's can grow to
3761 // a large number and therefore they need to go into a hash table. They are
3762 // used to load global properties from cells.
3763 if (code->type() == NORMAL) {
3764 // Make sure that a hash table is allocated for the normal load code cache.
3765 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07003766 Object* result;
3767 { MaybeObject* maybe_result =
3768 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
3769 if (!maybe_result->ToObject(&result)) return maybe_result;
3770 }
Steve Block6ded16b2010-05-10 14:33:55 +01003771 set_normal_type_cache(result);
3772 }
3773 return UpdateNormalTypeCache(name, code);
3774 } else {
3775 ASSERT(default_cache()->IsFixedArray());
3776 return UpdateDefaultCache(name, code);
3777 }
3778}
3779
3780
John Reck59135872010-11-02 12:39:01 -07003781MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003782 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00003783 // flags. This allows call constant stubs to overwrite call field
3784 // stubs, etc.
3785 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
3786
3787 // First check whether we can update existing code cache without
3788 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01003789 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003790 int length = cache->length();
3791 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01003792 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003793 Object* key = cache->get(i);
3794 if (key->IsNull()) {
3795 if (deleted_index < 0) deleted_index = i;
3796 continue;
3797 }
3798 if (key->IsUndefined()) {
3799 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01003800 cache->set(i + kCodeCacheEntryNameOffset, name);
3801 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003802 return this;
3803 }
3804 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003805 Code::Flags found =
3806 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00003807 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01003808 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003809 return this;
3810 }
3811 }
3812 }
3813
3814 // Reached the end of the code cache. If there were deleted
3815 // elements, reuse the space for the first of them.
3816 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01003817 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
3818 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003819 return this;
3820 }
3821
Steve Block6ded16b2010-05-10 14:33:55 +01003822 // Extend the code cache with some new entries (at least one). Must be a
3823 // multiple of the entry size.
3824 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
3825 new_length = new_length - new_length % kCodeCacheEntrySize;
3826 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07003827 Object* result;
3828 { MaybeObject* maybe_result = cache->CopySize(new_length);
3829 if (!maybe_result->ToObject(&result)) return maybe_result;
3830 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003831
3832 // Add the (name, code) pair to the new cache.
3833 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01003834 cache->set(length + kCodeCacheEntryNameOffset, name);
3835 cache->set(length + kCodeCacheEntryCodeOffset, code);
3836 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00003837 return this;
3838}
3839
3840
John Reck59135872010-11-02 12:39:01 -07003841MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003842 // Adding a new entry can cause a new cache to be allocated.
3843 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07003844 Object* new_cache;
3845 { MaybeObject* maybe_new_cache = cache->Put(name, code);
3846 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
3847 }
Steve Block6ded16b2010-05-10 14:33:55 +01003848 set_normal_type_cache(new_cache);
3849 return this;
3850}
3851
3852
3853Object* CodeCache::Lookup(String* name, Code::Flags flags) {
3854 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
3855 return LookupNormalTypeCache(name, flags);
3856 } else {
3857 return LookupDefaultCache(name, flags);
3858 }
3859}
3860
3861
3862Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
3863 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003864 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003865 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
3866 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00003867 // Skip deleted elements.
3868 if (key->IsNull()) continue;
3869 if (key->IsUndefined()) return key;
3870 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003871 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
3872 if (code->flags() == flags) {
3873 return code;
3874 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003875 }
3876 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003877 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003878}
3879
3880
Steve Block6ded16b2010-05-10 14:33:55 +01003881Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
3882 if (!normal_type_cache()->IsUndefined()) {
3883 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3884 return cache->Lookup(name, flags);
3885 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003886 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003887 }
3888}
3889
3890
3891int CodeCache::GetIndex(Object* name, Code* code) {
3892 if (code->type() == NORMAL) {
3893 if (normal_type_cache()->IsUndefined()) return -1;
3894 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3895 return cache->GetIndex(String::cast(name), code->flags());
3896 }
3897
3898 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003899 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003900 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
3901 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00003902 }
3903 return -1;
3904}
3905
3906
Steve Block6ded16b2010-05-10 14:33:55 +01003907void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
3908 if (code->type() == NORMAL) {
3909 ASSERT(!normal_type_cache()->IsUndefined());
3910 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3911 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
3912 cache->RemoveByIndex(index);
3913 } else {
3914 FixedArray* array = default_cache();
3915 ASSERT(array->length() >= index && array->get(index)->IsCode());
3916 // Use null instead of undefined for deleted elements to distinguish
3917 // deleted elements from unused elements. This distinction is used
3918 // when looking up in the cache and when updating the cache.
3919 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
3920 array->set_null(index - 1); // Name.
3921 array->set_null(index); // Code.
3922 }
3923}
3924
3925
3926// The key in the code cache hash table consists of the property name and the
3927// code object. The actual match is on the name and the code flags. If a key
3928// is created using the flags and not a code object it can only be used for
3929// lookup not to create a new entry.
3930class CodeCacheHashTableKey : public HashTableKey {
3931 public:
3932 CodeCacheHashTableKey(String* name, Code::Flags flags)
3933 : name_(name), flags_(flags), code_(NULL) { }
3934
3935 CodeCacheHashTableKey(String* name, Code* code)
3936 : name_(name),
3937 flags_(code->flags()),
3938 code_(code) { }
3939
3940
3941 bool IsMatch(Object* other) {
3942 if (!other->IsFixedArray()) return false;
3943 FixedArray* pair = FixedArray::cast(other);
3944 String* name = String::cast(pair->get(0));
3945 Code::Flags flags = Code::cast(pair->get(1))->flags();
3946 if (flags != flags_) {
3947 return false;
3948 }
3949 return name_->Equals(name);
3950 }
3951
3952 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
3953 return name->Hash() ^ flags;
3954 }
3955
3956 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
3957
3958 uint32_t HashForObject(Object* obj) {
3959 FixedArray* pair = FixedArray::cast(obj);
3960 String* name = String::cast(pair->get(0));
3961 Code* code = Code::cast(pair->get(1));
3962 return NameFlagsHashHelper(name, code->flags());
3963 }
3964
John Reck59135872010-11-02 12:39:01 -07003965 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01003966 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07003967 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01003968 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07003969 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3970 }
Steve Block6ded16b2010-05-10 14:33:55 +01003971 FixedArray* pair = FixedArray::cast(obj);
3972 pair->set(0, name_);
3973 pair->set(1, code_);
3974 return pair;
3975 }
3976
3977 private:
3978 String* name_;
3979 Code::Flags flags_;
3980 Code* code_;
3981};
3982
3983
3984Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
3985 CodeCacheHashTableKey key(name, flags);
3986 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01003987 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003988 return get(EntryToIndex(entry) + 1);
3989}
3990
3991
John Reck59135872010-11-02 12:39:01 -07003992MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003993 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07003994 Object* obj;
3995 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
3996 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3997 }
Steve Block6ded16b2010-05-10 14:33:55 +01003998
3999 // Don't use this, as the table might have grown.
4000 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4001
4002 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004003 Object* k;
4004 { MaybeObject* maybe_k = key.AsObject();
4005 if (!maybe_k->ToObject(&k)) return maybe_k;
4006 }
Steve Block6ded16b2010-05-10 14:33:55 +01004007
4008 cache->set(EntryToIndex(entry), k);
4009 cache->set(EntryToIndex(entry) + 1, code);
4010 cache->ElementAdded();
4011 return cache;
4012}
4013
4014
4015int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4016 CodeCacheHashTableKey key(name, flags);
4017 int entry = FindEntry(&key);
4018 return (entry == kNotFound) ? -1 : entry;
4019}
4020
4021
4022void CodeCacheHashTable::RemoveByIndex(int index) {
4023 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004024 Heap* heap = GetHeap();
4025 set(EntryToIndex(index), heap->null_value());
4026 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004027 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004028}
4029
4030
Steve Blocka7e24c12009-10-30 11:49:00 +00004031static bool HasKey(FixedArray* array, Object* key) {
4032 int len0 = array->length();
4033 for (int i = 0; i < len0; i++) {
4034 Object* element = array->get(i);
4035 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4036 if (element->IsString() &&
4037 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4038 return true;
4039 }
4040 }
4041 return false;
4042}
4043
4044
John Reck59135872010-11-02 12:39:01 -07004045MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Steve Block44f0eee2011-05-26 01:26:41 +01004046 ASSERT(!array->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00004047 switch (array->GetElementsKind()) {
4048 case JSObject::FAST_ELEMENTS:
4049 return UnionOfKeys(FixedArray::cast(array->elements()));
4050 case JSObject::DICTIONARY_ELEMENTS: {
4051 NumberDictionary* dict = array->element_dictionary();
4052 int size = dict->NumberOfElements();
4053
4054 // Allocate a temporary fixed array.
John Reck59135872010-11-02 12:39:01 -07004055 Object* object;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004056 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
John Reck59135872010-11-02 12:39:01 -07004057 if (!maybe_object->ToObject(&object)) return maybe_object;
4058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004059 FixedArray* key_array = FixedArray::cast(object);
4060
4061 int capacity = dict->Capacity();
4062 int pos = 0;
4063 // Copy the elements from the JSArray to the temporary fixed array.
4064 for (int i = 0; i < capacity; i++) {
4065 if (dict->IsKey(dict->KeyAt(i))) {
4066 key_array->set(pos++, dict->ValueAt(i));
4067 }
4068 }
4069 // Compute the union of this and the temporary fixed array.
4070 return UnionOfKeys(key_array);
4071 }
4072 default:
4073 UNREACHABLE();
4074 }
4075 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01004076 return GetHeap()->null_value(); // Failure case needs to "return" a value.
Steve Blocka7e24c12009-10-30 11:49:00 +00004077}
4078
4079
John Reck59135872010-11-02 12:39:01 -07004080MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004081 int len0 = length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004082#ifdef DEBUG
4083 if (FLAG_enable_slow_asserts) {
4084 for (int i = 0; i < len0; i++) {
4085 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4086 }
4087 }
4088#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004089 int len1 = other->length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004090 // Optimize if 'other' is empty.
4091 // We cannot optimize if 'this' is empty, as other may have holes
4092 // or non keys.
Steve Blocka7e24c12009-10-30 11:49:00 +00004093 if (len1 == 0) return this;
4094
4095 // Compute how many elements are not in this.
4096 int extra = 0;
4097 for (int y = 0; y < len1; y++) {
4098 Object* value = other->get(y);
4099 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
4100 }
4101
4102 if (extra == 0) return this;
4103
4104 // Allocate the result
John Reck59135872010-11-02 12:39:01 -07004105 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004106 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
John Reck59135872010-11-02 12:39:01 -07004107 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4108 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004109 // Fill in the content
Leon Clarke4515c472010-02-03 11:58:03 +00004110 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004111 FixedArray* result = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00004112 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004113 for (int i = 0; i < len0; i++) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004114 Object* e = get(i);
4115 ASSERT(e->IsString() || e->IsNumber());
4116 result->set(i, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004117 }
4118 // Fill in the extra keys.
4119 int index = 0;
4120 for (int y = 0; y < len1; y++) {
4121 Object* value = other->get(y);
4122 if (!value->IsTheHole() && !HasKey(this, value)) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004123 Object* e = other->get(y);
4124 ASSERT(e->IsString() || e->IsNumber());
4125 result->set(len0 + index, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004126 index++;
4127 }
4128 }
4129 ASSERT(extra == index);
4130 return result;
4131}
4132
4133
John Reck59135872010-11-02 12:39:01 -07004134MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004135 Heap* heap = GetHeap();
4136 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004137 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004138 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004139 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4140 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004141 FixedArray* result = FixedArray::cast(obj);
4142 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004143 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004144 int len = length();
4145 if (new_length < len) len = new_length;
4146 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004147 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004148 for (int i = 0; i < len; i++) {
4149 result->set(i, get(i), mode);
4150 }
4151 return result;
4152}
4153
4154
4155void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004156 AssertNoAllocation no_gc;
4157 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004158 for (int index = 0; index < len; index++) {
4159 dest->set(dest_pos+index, get(pos+index), mode);
4160 }
4161}
4162
4163
4164#ifdef DEBUG
4165bool FixedArray::IsEqualTo(FixedArray* other) {
4166 if (length() != other->length()) return false;
4167 for (int i = 0 ; i < length(); ++i) {
4168 if (get(i) != other->get(i)) return false;
4169 }
4170 return true;
4171}
4172#endif
4173
4174
John Reck59135872010-11-02 12:39:01 -07004175MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004176 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004177 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004178 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004179 }
4180 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004181 Object* array;
4182 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004183 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004184 if (!maybe_array->ToObject(&array)) return maybe_array;
4185 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004186 // Do not use DescriptorArray::cast on incomplete object.
4187 FixedArray* result = FixedArray::cast(array);
4188
4189 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004190 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004191 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004192 if (!maybe_array->ToObject(&array)) return maybe_array;
4193 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004194 result->set(kContentArrayIndex, array);
4195 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004196 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004197 return result;
4198}
4199
4200
4201void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4202 FixedArray* new_cache) {
4203 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4204 if (HasEnumCache()) {
4205 FixedArray::cast(get(kEnumerationIndexIndex))->
4206 set(kEnumCacheBridgeCacheIndex, new_cache);
4207 } else {
4208 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4209 FixedArray::cast(bridge_storage)->
4210 set(kEnumCacheBridgeCacheIndex, new_cache);
4211 fast_set(FixedArray::cast(bridge_storage),
4212 kEnumCacheBridgeEnumIndex,
4213 get(kEnumerationIndexIndex));
4214 set(kEnumerationIndexIndex, bridge_storage);
4215 }
4216}
4217
4218
John Reck59135872010-11-02 12:39:01 -07004219MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4220 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004221 // Transitions are only kept when inserting another transition.
4222 // This precondition is not required by this function's implementation, but
4223 // is currently required by the semantics of maps, so we check it.
4224 // Conversely, we filter after replacing, so replacing a transition and
4225 // removing all other transitions is not supported.
4226 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4227 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4228 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4229
4230 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004231 Object* result;
4232 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4233 if (!maybe_result->ToObject(&result)) return maybe_result;
4234 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004235
4236 int transitions = 0;
4237 int null_descriptors = 0;
4238 if (remove_transitions) {
4239 for (int i = 0; i < number_of_descriptors(); i++) {
4240 if (IsTransition(i)) transitions++;
4241 if (IsNullDescriptor(i)) null_descriptors++;
4242 }
4243 } else {
4244 for (int i = 0; i < number_of_descriptors(); i++) {
4245 if (IsNullDescriptor(i)) null_descriptors++;
4246 }
4247 }
4248 int new_size = number_of_descriptors() - transitions - null_descriptors;
4249
4250 // If key is in descriptor, we replace it in-place when filtering.
4251 // Count a null descriptor for key as inserted, not replaced.
4252 int index = Search(descriptor->GetKey());
4253 const bool inserting = (index == kNotFound);
4254 const bool replacing = !inserting;
4255 bool keep_enumeration_index = false;
4256 if (inserting) {
4257 ++new_size;
4258 }
4259 if (replacing) {
4260 // We are replacing an existing descriptor. We keep the enumeration
4261 // index of a visible property.
4262 PropertyType t = PropertyDetails(GetDetails(index)).type();
4263 if (t == CONSTANT_FUNCTION ||
4264 t == FIELD ||
4265 t == CALLBACKS ||
4266 t == INTERCEPTOR) {
4267 keep_enumeration_index = true;
4268 } else if (remove_transitions) {
4269 // Replaced descriptor has been counted as removed if it is
4270 // a transition that will be replaced. Adjust count in this case.
4271 ++new_size;
4272 }
4273 }
John Reck59135872010-11-02 12:39:01 -07004274 { MaybeObject* maybe_result = Allocate(new_size);
4275 if (!maybe_result->ToObject(&result)) return maybe_result;
4276 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004277 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4278 // Set the enumeration index in the descriptors and set the enumeration index
4279 // in the result.
4280 int enumeration_index = NextEnumerationIndex();
4281 if (!descriptor->GetDetails().IsTransition()) {
4282 if (keep_enumeration_index) {
4283 descriptor->SetEnumerationIndex(
4284 PropertyDetails(GetDetails(index)).index());
4285 } else {
4286 descriptor->SetEnumerationIndex(enumeration_index);
4287 ++enumeration_index;
4288 }
4289 }
4290 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4291
4292 // Copy the descriptors, filtering out transitions and null descriptors,
4293 // and inserting or replacing a descriptor.
4294 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4295 int from_index = 0;
4296 int to_index = 0;
4297
4298 for (; from_index < number_of_descriptors(); from_index++) {
4299 String* key = GetKey(from_index);
4300 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4301 break;
4302 }
4303 if (IsNullDescriptor(from_index)) continue;
4304 if (remove_transitions && IsTransition(from_index)) continue;
4305 new_descriptors->CopyFrom(to_index++, this, from_index);
4306 }
4307
4308 new_descriptors->Set(to_index++, descriptor);
4309 if (replacing) from_index++;
4310
4311 for (; from_index < number_of_descriptors(); from_index++) {
4312 if (IsNullDescriptor(from_index)) continue;
4313 if (remove_transitions && IsTransition(from_index)) continue;
4314 new_descriptors->CopyFrom(to_index++, this, from_index);
4315 }
4316
4317 ASSERT(to_index == new_descriptors->number_of_descriptors());
4318 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4319
4320 return new_descriptors;
4321}
4322
4323
John Reck59135872010-11-02 12:39:01 -07004324MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004325 // Remove all transitions and null descriptors. Return a copy of the array
4326 // with all transitions removed, or a Failure object if the new array could
4327 // not be allocated.
4328
4329 // Compute the size of the map transition entries to be removed.
4330 int num_removed = 0;
4331 for (int i = 0; i < number_of_descriptors(); i++) {
4332 if (!IsProperty(i)) num_removed++;
4333 }
4334
4335 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07004336 Object* result;
4337 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4338 if (!maybe_result->ToObject(&result)) return maybe_result;
4339 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004340 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4341
4342 // Copy the content.
4343 int next_descriptor = 0;
4344 for (int i = 0; i < number_of_descriptors(); i++) {
4345 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
4346 }
4347 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4348
4349 return new_descriptors;
4350}
4351
4352
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004353void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004354 // In-place heap sort.
4355 int len = number_of_descriptors();
4356
4357 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004358 // Index of the last node with children
4359 const int max_parent_index = (len / 2) - 1;
4360 for (int i = max_parent_index; i >= 0; --i) {
4361 int parent_index = i;
4362 const uint32_t parent_hash = GetKey(i)->Hash();
4363 while (parent_index <= max_parent_index) {
4364 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004365 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004366 if (child_index + 1 < len) {
4367 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4368 if (right_child_hash > child_hash) {
4369 child_index++;
4370 child_hash = right_child_hash;
4371 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004372 }
Steve Block6ded16b2010-05-10 14:33:55 +01004373 if (child_hash <= parent_hash) break;
4374 Swap(parent_index, child_index);
4375 // Now element at child_index could be < its children.
4376 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004377 }
4378 }
4379
4380 // Extract elements and create sorted array.
4381 for (int i = len - 1; i > 0; --i) {
4382 // Put max element at the back of the array.
4383 Swap(0, i);
4384 // Sift down the new top element.
4385 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004386 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4387 const int max_parent_index = (i / 2) - 1;
4388 while (parent_index <= max_parent_index) {
4389 int child_index = parent_index * 2 + 1;
4390 uint32_t child_hash = GetKey(child_index)->Hash();
4391 if (child_index + 1 < i) {
4392 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4393 if (right_child_hash > child_hash) {
4394 child_index++;
4395 child_hash = right_child_hash;
4396 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004397 }
Steve Block6ded16b2010-05-10 14:33:55 +01004398 if (child_hash <= parent_hash) break;
4399 Swap(parent_index, child_index);
4400 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004401 }
4402 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004403}
Steve Blocka7e24c12009-10-30 11:49:00 +00004404
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004405
4406void DescriptorArray::Sort() {
4407 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004408 SLOW_ASSERT(IsSortedNoDuplicates());
4409}
4410
4411
4412int DescriptorArray::BinarySearch(String* name, int low, int high) {
4413 uint32_t hash = name->Hash();
4414
4415 while (low <= high) {
4416 int mid = (low + high) / 2;
4417 String* mid_name = GetKey(mid);
4418 uint32_t mid_hash = mid_name->Hash();
4419
4420 if (mid_hash > hash) {
4421 high = mid - 1;
4422 continue;
4423 }
4424 if (mid_hash < hash) {
4425 low = mid + 1;
4426 continue;
4427 }
4428 // Found an element with the same hash-code.
4429 ASSERT(hash == mid_hash);
4430 // There might be more, so we find the first one and
4431 // check them all to see if we have a match.
4432 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4433 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4434 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4435 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4436 }
4437 break;
4438 }
4439 return kNotFound;
4440}
4441
4442
4443int DescriptorArray::LinearSearch(String* name, int len) {
4444 uint32_t hash = name->Hash();
4445 for (int number = 0; number < len; number++) {
4446 String* entry = GetKey(number);
4447 if ((entry->Hash() == hash) &&
4448 name->Equals(entry) &&
4449 !is_null_descriptor(number)) {
4450 return number;
4451 }
4452 }
4453 return kNotFound;
4454}
4455
4456
Ben Murdochb0fe1622011-05-05 13:52:32 +01004457MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4458 PretenureFlag pretenure) {
4459 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004460 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004461 pretenure);
4462}
4463
4464
4465MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
4466 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01004467 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
4468 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004469 pretenure);
4470}
4471
4472
Steve Blocka7e24c12009-10-30 11:49:00 +00004473#ifdef DEBUG
4474bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
4475 if (IsEmpty()) return other->IsEmpty();
4476 if (other->IsEmpty()) return false;
4477 if (length() != other->length()) return false;
4478 for (int i = 0; i < length(); ++i) {
4479 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
4480 }
4481 return GetContentArray()->IsEqualTo(other->GetContentArray());
4482}
4483#endif
4484
4485
Steve Blocka7e24c12009-10-30 11:49:00 +00004486bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01004487 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004488 return true;
4489}
4490
4491
4492int String::Utf8Length() {
4493 if (IsAsciiRepresentation()) return length();
4494 // Attempt to flatten before accessing the string. It probably
4495 // doesn't make Utf8Length faster, but it is very likely that
4496 // the string will be accessed later (for example by WriteUtf8)
4497 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01004498 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01004499 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01004500 Access<StringInputBuffer> buffer(
4501 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004502 buffer->Reset(0, this);
4503 int result = 0;
4504 while (buffer->has_more())
4505 result += unibrow::Utf8::Length(buffer->GetNext());
4506 return result;
4507}
4508
4509
4510Vector<const char> String::ToAsciiVector() {
4511 ASSERT(IsAsciiRepresentation());
4512 ASSERT(IsFlat());
4513
4514 int offset = 0;
4515 int length = this->length();
4516 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4517 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004518 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004519 ConsString* cons = ConsString::cast(string);
4520 ASSERT(cons->second()->length() == 0);
4521 string = cons->first();
4522 string_tag = StringShape(string).representation_tag();
4523 }
4524 if (string_tag == kSeqStringTag) {
4525 SeqAsciiString* seq = SeqAsciiString::cast(string);
4526 char* start = seq->GetChars();
4527 return Vector<const char>(start + offset, length);
4528 }
4529 ASSERT(string_tag == kExternalStringTag);
4530 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
4531 const char* start = ext->resource()->data();
4532 return Vector<const char>(start + offset, length);
4533}
4534
4535
4536Vector<const uc16> String::ToUC16Vector() {
4537 ASSERT(IsTwoByteRepresentation());
4538 ASSERT(IsFlat());
4539
4540 int offset = 0;
4541 int length = this->length();
4542 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4543 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004544 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004545 ConsString* cons = ConsString::cast(string);
4546 ASSERT(cons->second()->length() == 0);
4547 string = cons->first();
4548 string_tag = StringShape(string).representation_tag();
4549 }
4550 if (string_tag == kSeqStringTag) {
4551 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
4552 return Vector<const uc16>(seq->GetChars() + offset, length);
4553 }
4554 ASSERT(string_tag == kExternalStringTag);
4555 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
4556 const uc16* start =
4557 reinterpret_cast<const uc16*>(ext->resource()->data());
4558 return Vector<const uc16>(start + offset, length);
4559}
4560
4561
4562SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4563 RobustnessFlag robust_flag,
4564 int offset,
4565 int length,
4566 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004567 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4568 return SmartPointer<char>(NULL);
4569 }
Steve Block44f0eee2011-05-26 01:26:41 +01004570 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004571
4572 // Negative length means the to the end of the string.
4573 if (length < 0) length = kMaxInt - offset;
4574
4575 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01004576 Access<StringInputBuffer> buffer(
4577 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004578 buffer->Reset(offset, this);
4579 int character_position = offset;
4580 int utf8_bytes = 0;
4581 while (buffer->has_more()) {
4582 uint16_t character = buffer->GetNext();
4583 if (character_position < offset + length) {
4584 utf8_bytes += unibrow::Utf8::Length(character);
4585 }
4586 character_position++;
4587 }
4588
4589 if (length_return) {
4590 *length_return = utf8_bytes;
4591 }
4592
4593 char* result = NewArray<char>(utf8_bytes + 1);
4594
4595 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
4596 buffer->Rewind();
4597 buffer->Seek(offset);
4598 character_position = offset;
4599 int utf8_byte_position = 0;
4600 while (buffer->has_more()) {
4601 uint16_t character = buffer->GetNext();
4602 if (character_position < offset + length) {
4603 if (allow_nulls == DISALLOW_NULLS && character == 0) {
4604 character = ' ';
4605 }
4606 utf8_byte_position +=
4607 unibrow::Utf8::Encode(result + utf8_byte_position, character);
4608 }
4609 character_position++;
4610 }
4611 result[utf8_byte_position] = 0;
4612 return SmartPointer<char>(result);
4613}
4614
4615
4616SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4617 RobustnessFlag robust_flag,
4618 int* length_return) {
4619 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
4620}
4621
4622
4623const uc16* String::GetTwoByteData() {
4624 return GetTwoByteData(0);
4625}
4626
4627
4628const uc16* String::GetTwoByteData(unsigned start) {
4629 ASSERT(!IsAsciiRepresentation());
4630 switch (StringShape(this).representation_tag()) {
4631 case kSeqStringTag:
4632 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
4633 case kExternalStringTag:
4634 return ExternalTwoByteString::cast(this)->
4635 ExternalTwoByteStringGetData(start);
Steve Blocka7e24c12009-10-30 11:49:00 +00004636 case kConsStringTag:
4637 UNREACHABLE();
4638 return NULL;
4639 }
4640 UNREACHABLE();
4641 return NULL;
4642}
4643
4644
4645SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004646 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4647 return SmartPointer<uc16>();
4648 }
Steve Block44f0eee2011-05-26 01:26:41 +01004649 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004650
Steve Block44f0eee2011-05-26 01:26:41 +01004651 Access<StringInputBuffer> buffer(
4652 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004653 buffer->Reset(this);
4654
4655 uc16* result = NewArray<uc16>(length() + 1);
4656
4657 int i = 0;
4658 while (buffer->has_more()) {
4659 uint16_t character = buffer->GetNext();
4660 result[i++] = character;
4661 }
4662 result[i] = 0;
4663 return SmartPointer<uc16>(result);
4664}
4665
4666
4667const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
4668 return reinterpret_cast<uc16*>(
4669 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
4670}
4671
4672
4673void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4674 unsigned* offset_ptr,
4675 unsigned max_chars) {
4676 unsigned chars_read = 0;
4677 unsigned offset = *offset_ptr;
4678 while (chars_read < max_chars) {
4679 uint16_t c = *reinterpret_cast<uint16_t*>(
4680 reinterpret_cast<char*>(this) -
4681 kHeapObjectTag + kHeaderSize + offset * kShortSize);
4682 if (c <= kMaxAsciiCharCode) {
4683 // Fast case for ASCII characters. Cursor is an input output argument.
4684 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4685 rbb->util_buffer,
4686 rbb->capacity,
4687 rbb->cursor)) {
4688 break;
4689 }
4690 } else {
4691 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4692 rbb->util_buffer,
4693 rbb->capacity,
4694 rbb->cursor)) {
4695 break;
4696 }
4697 }
4698 offset++;
4699 chars_read++;
4700 }
4701 *offset_ptr = offset;
4702 rbb->remaining += chars_read;
4703}
4704
4705
4706const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
4707 unsigned* remaining,
4708 unsigned* offset_ptr,
4709 unsigned max_chars) {
4710 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
4711 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
4712 *remaining = max_chars;
4713 *offset_ptr += max_chars;
4714 return b;
4715}
4716
4717
4718// This will iterate unless the block of string data spans two 'halves' of
4719// a ConsString, in which case it will recurse. Since the block of string
4720// data to be read has a maximum size this limits the maximum recursion
4721// depth to something sane. Since C++ does not have tail call recursion
4722// elimination, the iteration must be explicit. Since this is not an
4723// -IntoBuffer method it can delegate to one of the efficient
4724// *AsciiStringReadBlock routines.
4725const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
4726 unsigned* offset_ptr,
4727 unsigned max_chars) {
4728 ConsString* current = this;
4729 unsigned offset = *offset_ptr;
4730 int offset_correction = 0;
4731
4732 while (true) {
4733 String* left = current->first();
4734 unsigned left_length = (unsigned)left->length();
4735 if (left_length > offset &&
4736 (max_chars <= left_length - offset ||
4737 (rbb->capacity <= left_length - offset &&
4738 (max_chars = left_length - offset, true)))) { // comma operator!
4739 // Left hand side only - iterate unless we have reached the bottom of
4740 // the cons tree. The assignment on the left of the comma operator is
4741 // in order to make use of the fact that the -IntoBuffer routines can
4742 // produce at most 'capacity' characters. This enables us to postpone
4743 // the point where we switch to the -IntoBuffer routines (below) in order
4744 // to maximize the chances of delegating a big chunk of work to the
4745 // efficient *AsciiStringReadBlock routines.
4746 if (StringShape(left).IsCons()) {
4747 current = ConsString::cast(left);
4748 continue;
4749 } else {
4750 const unibrow::byte* answer =
4751 String::ReadBlock(left, rbb, &offset, max_chars);
4752 *offset_ptr = offset + offset_correction;
4753 return answer;
4754 }
4755 } else if (left_length <= offset) {
4756 // Right hand side only - iterate unless we have reached the bottom of
4757 // the cons tree.
4758 String* right = current->second();
4759 offset -= left_length;
4760 offset_correction += left_length;
4761 if (StringShape(right).IsCons()) {
4762 current = ConsString::cast(right);
4763 continue;
4764 } else {
4765 const unibrow::byte* answer =
4766 String::ReadBlock(right, rbb, &offset, max_chars);
4767 *offset_ptr = offset + offset_correction;
4768 return answer;
4769 }
4770 } else {
4771 // The block to be read spans two sides of the ConsString, so we call the
4772 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
4773 // are able to assemble data from several part strings because they use
4774 // the util_buffer to store their data and never return direct pointers
4775 // to their storage. We don't try to read more than the buffer capacity
4776 // here or we can get too much recursion.
4777 ASSERT(rbb->remaining == 0);
4778 ASSERT(rbb->cursor == 0);
4779 current->ConsStringReadBlockIntoBuffer(
4780 rbb,
4781 &offset,
4782 max_chars > rbb->capacity ? rbb->capacity : max_chars);
4783 *offset_ptr = offset + offset_correction;
4784 return rbb->util_buffer;
4785 }
4786 }
4787}
4788
4789
Steve Blocka7e24c12009-10-30 11:49:00 +00004790uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
4791 ASSERT(index >= 0 && index < length());
4792 return resource()->data()[index];
4793}
4794
4795
4796const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
4797 unsigned* remaining,
4798 unsigned* offset_ptr,
4799 unsigned max_chars) {
4800 // Cast const char* to unibrow::byte* (signedness difference).
4801 const unibrow::byte* b =
4802 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
4803 *remaining = max_chars;
4804 *offset_ptr += max_chars;
4805 return b;
4806}
4807
4808
4809const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
4810 unsigned start) {
4811 return resource()->data() + start;
4812}
4813
4814
4815uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
4816 ASSERT(index >= 0 && index < length());
4817 return resource()->data()[index];
4818}
4819
4820
4821void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
4822 ReadBlockBuffer* rbb,
4823 unsigned* offset_ptr,
4824 unsigned max_chars) {
4825 unsigned chars_read = 0;
4826 unsigned offset = *offset_ptr;
4827 const uint16_t* data = resource()->data();
4828 while (chars_read < max_chars) {
4829 uint16_t c = data[offset];
4830 if (c <= kMaxAsciiCharCode) {
4831 // Fast case for ASCII characters. Cursor is an input output argument.
4832 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4833 rbb->util_buffer,
4834 rbb->capacity,
4835 rbb->cursor))
4836 break;
4837 } else {
4838 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4839 rbb->util_buffer,
4840 rbb->capacity,
4841 rbb->cursor))
4842 break;
4843 }
4844 offset++;
4845 chars_read++;
4846 }
4847 *offset_ptr = offset;
4848 rbb->remaining += chars_read;
4849}
4850
4851
4852void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4853 unsigned* offset_ptr,
4854 unsigned max_chars) {
4855 unsigned capacity = rbb->capacity - rbb->cursor;
4856 if (max_chars > capacity) max_chars = capacity;
4857 memcpy(rbb->util_buffer + rbb->cursor,
4858 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
4859 *offset_ptr * kCharSize,
4860 max_chars);
4861 rbb->remaining += max_chars;
4862 *offset_ptr += max_chars;
4863 rbb->cursor += max_chars;
4864}
4865
4866
4867void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
4868 ReadBlockBuffer* rbb,
4869 unsigned* offset_ptr,
4870 unsigned max_chars) {
4871 unsigned capacity = rbb->capacity - rbb->cursor;
4872 if (max_chars > capacity) max_chars = capacity;
4873 memcpy(rbb->util_buffer + rbb->cursor,
4874 resource()->data() + *offset_ptr,
4875 max_chars);
4876 rbb->remaining += max_chars;
4877 *offset_ptr += max_chars;
4878 rbb->cursor += max_chars;
4879}
4880
4881
4882// This method determines the type of string involved and then copies
4883// a whole chunk of characters into a buffer, or returns a pointer to a buffer
4884// where they can be found. The pointer is not necessarily valid across a GC
4885// (see AsciiStringReadBlock).
4886const unibrow::byte* String::ReadBlock(String* input,
4887 ReadBlockBuffer* rbb,
4888 unsigned* offset_ptr,
4889 unsigned max_chars) {
4890 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
4891 if (max_chars == 0) {
4892 rbb->remaining = 0;
4893 return NULL;
4894 }
4895 switch (StringShape(input).representation_tag()) {
4896 case kSeqStringTag:
4897 if (input->IsAsciiRepresentation()) {
4898 SeqAsciiString* str = SeqAsciiString::cast(input);
4899 return str->SeqAsciiStringReadBlock(&rbb->remaining,
4900 offset_ptr,
4901 max_chars);
4902 } else {
4903 SeqTwoByteString* str = SeqTwoByteString::cast(input);
4904 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
4905 offset_ptr,
4906 max_chars);
4907 return rbb->util_buffer;
4908 }
4909 case kConsStringTag:
4910 return ConsString::cast(input)->ConsStringReadBlock(rbb,
4911 offset_ptr,
4912 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00004913 case kExternalStringTag:
4914 if (input->IsAsciiRepresentation()) {
4915 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
4916 &rbb->remaining,
4917 offset_ptr,
4918 max_chars);
4919 } else {
4920 ExternalTwoByteString::cast(input)->
4921 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
4922 offset_ptr,
4923 max_chars);
4924 return rbb->util_buffer;
4925 }
4926 default:
4927 break;
4928 }
4929
4930 UNREACHABLE();
4931 return 0;
4932}
4933
4934
Steve Blocka7e24c12009-10-30 11:49:00 +00004935void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01004936 Isolate* isolate = Isolate::Current();
4937 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00004938 while (current != NULL) {
4939 current->PostGarbageCollection();
4940 current = current->prev_;
4941 }
4942}
4943
4944
4945// Reserve space for statics needing saving and restoring.
4946int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01004947 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00004948}
4949
4950
4951// Archive statics that are thread local.
4952char* Relocatable::ArchiveState(char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01004953 Isolate* isolate = Isolate::Current();
4954 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
4955 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00004956 return to + ArchiveSpacePerThread();
4957}
4958
4959
4960// Restore statics that are thread local.
4961char* Relocatable::RestoreState(char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01004962 Isolate* isolate = Isolate::Current();
4963 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00004964 return from + ArchiveSpacePerThread();
4965}
4966
4967
4968char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
4969 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
4970 Iterate(v, top);
4971 return thread_storage + ArchiveSpacePerThread();
4972}
4973
4974
4975void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01004976 Isolate* isolate = Isolate::Current();
4977 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00004978}
4979
4980
4981void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
4982 Relocatable* current = top;
4983 while (current != NULL) {
4984 current->IterateInstance(v);
4985 current = current->prev_;
4986 }
4987}
4988
4989
Steve Block44f0eee2011-05-26 01:26:41 +01004990FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
4991 : Relocatable(isolate),
4992 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00004993 length_(str->length()) {
4994 PostGarbageCollection();
4995}
4996
4997
Steve Block44f0eee2011-05-26 01:26:41 +01004998FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
4999 : Relocatable(isolate),
5000 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005001 is_ascii_(true),
5002 length_(input.length()),
5003 start_(input.start()) { }
5004
5005
5006void FlatStringReader::PostGarbageCollection() {
5007 if (str_ == NULL) return;
5008 Handle<String> str(str_);
5009 ASSERT(str->IsFlat());
5010 is_ascii_ = str->IsAsciiRepresentation();
5011 if (is_ascii_) {
5012 start_ = str->ToAsciiVector().start();
5013 } else {
5014 start_ = str->ToUC16Vector().start();
5015 }
5016}
5017
5018
5019void StringInputBuffer::Seek(unsigned pos) {
5020 Reset(pos, input_);
5021}
5022
5023
5024void SafeStringInputBuffer::Seek(unsigned pos) {
5025 Reset(pos, input_);
5026}
5027
5028
5029// This method determines the type of string involved and then copies
5030// a whole chunk of characters into a buffer. It can be used with strings
5031// that have been glued together to form a ConsString and which must cooperate
5032// to fill up a buffer.
5033void String::ReadBlockIntoBuffer(String* input,
5034 ReadBlockBuffer* rbb,
5035 unsigned* offset_ptr,
5036 unsigned max_chars) {
5037 ASSERT(*offset_ptr <= (unsigned)input->length());
5038 if (max_chars == 0) return;
5039
5040 switch (StringShape(input).representation_tag()) {
5041 case kSeqStringTag:
5042 if (input->IsAsciiRepresentation()) {
5043 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5044 offset_ptr,
5045 max_chars);
5046 return;
5047 } else {
5048 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5049 offset_ptr,
5050 max_chars);
5051 return;
5052 }
5053 case kConsStringTag:
5054 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5055 offset_ptr,
5056 max_chars);
5057 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005058 case kExternalStringTag:
5059 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005060 ExternalAsciiString::cast(input)->
5061 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5062 } else {
5063 ExternalTwoByteString::cast(input)->
5064 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5065 offset_ptr,
5066 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005067 }
5068 return;
5069 default:
5070 break;
5071 }
5072
5073 UNREACHABLE();
5074 return;
5075}
5076
5077
5078const unibrow::byte* String::ReadBlock(String* input,
5079 unibrow::byte* util_buffer,
5080 unsigned capacity,
5081 unsigned* remaining,
5082 unsigned* offset_ptr) {
5083 ASSERT(*offset_ptr <= (unsigned)input->length());
5084 unsigned chars = input->length() - *offset_ptr;
5085 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5086 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5087 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5088 *remaining = rbb.remaining;
5089 return answer;
5090}
5091
5092
5093const unibrow::byte* String::ReadBlock(String** raw_input,
5094 unibrow::byte* util_buffer,
5095 unsigned capacity,
5096 unsigned* remaining,
5097 unsigned* offset_ptr) {
5098 Handle<String> input(raw_input);
5099 ASSERT(*offset_ptr <= (unsigned)input->length());
5100 unsigned chars = input->length() - *offset_ptr;
5101 if (chars > capacity) chars = capacity;
5102 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5103 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5104 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5105 *remaining = rbb.remaining;
5106 return rbb.util_buffer;
5107}
5108
5109
5110// This will iterate unless the block of string data spans two 'halves' of
5111// a ConsString, in which case it will recurse. Since the block of string
5112// data to be read has a maximum size this limits the maximum recursion
5113// depth to something sane. Since C++ does not have tail call recursion
5114// elimination, the iteration must be explicit.
5115void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5116 unsigned* offset_ptr,
5117 unsigned max_chars) {
5118 ConsString* current = this;
5119 unsigned offset = *offset_ptr;
5120 int offset_correction = 0;
5121
5122 while (true) {
5123 String* left = current->first();
5124 unsigned left_length = (unsigned)left->length();
5125 if (left_length > offset &&
5126 max_chars <= left_length - offset) {
5127 // Left hand side only - iterate unless we have reached the bottom of
5128 // the cons tree.
5129 if (StringShape(left).IsCons()) {
5130 current = ConsString::cast(left);
5131 continue;
5132 } else {
5133 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5134 *offset_ptr = offset + offset_correction;
5135 return;
5136 }
5137 } else if (left_length <= offset) {
5138 // Right hand side only - iterate unless we have reached the bottom of
5139 // the cons tree.
5140 offset -= left_length;
5141 offset_correction += left_length;
5142 String* right = current->second();
5143 if (StringShape(right).IsCons()) {
5144 current = ConsString::cast(right);
5145 continue;
5146 } else {
5147 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5148 *offset_ptr = offset + offset_correction;
5149 return;
5150 }
5151 } else {
5152 // The block to be read spans two sides of the ConsString, so we recurse.
5153 // First recurse on the left.
5154 max_chars -= left_length - offset;
5155 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5156 // We may have reached the max or there may not have been enough space
5157 // in the buffer for the characters in the left hand side.
5158 if (offset == left_length) {
5159 // Recurse on the right.
5160 String* right = String::cast(current->second());
5161 offset -= left_length;
5162 offset_correction += left_length;
5163 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5164 }
5165 *offset_ptr = offset + offset_correction;
5166 return;
5167 }
5168 }
5169}
5170
5171
Steve Blocka7e24c12009-10-30 11:49:00 +00005172uint16_t ConsString::ConsStringGet(int index) {
5173 ASSERT(index >= 0 && index < this->length());
5174
5175 // Check for a flattened cons string
5176 if (second()->length() == 0) {
5177 String* left = first();
5178 return left->Get(index);
5179 }
5180
5181 String* string = String::cast(this);
5182
5183 while (true) {
5184 if (StringShape(string).IsCons()) {
5185 ConsString* cons_string = ConsString::cast(string);
5186 String* left = cons_string->first();
5187 if (left->length() > index) {
5188 string = left;
5189 } else {
5190 index -= left->length();
5191 string = cons_string->second();
5192 }
5193 } else {
5194 return string->Get(index);
5195 }
5196 }
5197
5198 UNREACHABLE();
5199 return 0;
5200}
5201
5202
5203template <typename sinkchar>
5204void String::WriteToFlat(String* src,
5205 sinkchar* sink,
5206 int f,
5207 int t) {
5208 String* source = src;
5209 int from = f;
5210 int to = t;
5211 while (true) {
5212 ASSERT(0 <= from && from <= to && to <= source->length());
5213 switch (StringShape(source).full_representation_tag()) {
5214 case kAsciiStringTag | kExternalStringTag: {
5215 CopyChars(sink,
5216 ExternalAsciiString::cast(source)->resource()->data() + from,
5217 to - from);
5218 return;
5219 }
5220 case kTwoByteStringTag | kExternalStringTag: {
5221 const uc16* data =
5222 ExternalTwoByteString::cast(source)->resource()->data();
5223 CopyChars(sink,
5224 data + from,
5225 to - from);
5226 return;
5227 }
5228 case kAsciiStringTag | kSeqStringTag: {
5229 CopyChars(sink,
5230 SeqAsciiString::cast(source)->GetChars() + from,
5231 to - from);
5232 return;
5233 }
5234 case kTwoByteStringTag | kSeqStringTag: {
5235 CopyChars(sink,
5236 SeqTwoByteString::cast(source)->GetChars() + from,
5237 to - from);
5238 return;
5239 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005240 case kAsciiStringTag | kConsStringTag:
5241 case kTwoByteStringTag | kConsStringTag: {
5242 ConsString* cons_string = ConsString::cast(source);
5243 String* first = cons_string->first();
5244 int boundary = first->length();
5245 if (to - boundary >= boundary - from) {
5246 // Right hand side is longer. Recurse over left.
5247 if (from < boundary) {
5248 WriteToFlat(first, sink, from, boundary);
5249 sink += boundary - from;
5250 from = 0;
5251 } else {
5252 from -= boundary;
5253 }
5254 to -= boundary;
5255 source = cons_string->second();
5256 } else {
5257 // Left hand side is longer. Recurse over right.
5258 if (to > boundary) {
5259 String* second = cons_string->second();
5260 WriteToFlat(second,
5261 sink + boundary - from,
5262 0,
5263 to - boundary);
5264 to = boundary;
5265 }
5266 source = first;
5267 }
5268 break;
5269 }
5270 }
5271 }
5272}
5273
5274
Steve Blocka7e24c12009-10-30 11:49:00 +00005275template <typename IteratorA, typename IteratorB>
5276static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5277 // General slow case check. We know that the ia and ib iterators
5278 // have the same length.
5279 while (ia->has_more()) {
5280 uc32 ca = ia->GetNext();
5281 uc32 cb = ib->GetNext();
5282 if (ca != cb)
5283 return false;
5284 }
5285 return true;
5286}
5287
5288
5289// Compares the contents of two strings by reading and comparing
5290// int-sized blocks of characters.
5291template <typename Char>
5292static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5293 int length = a.length();
5294 ASSERT_EQ(length, b.length());
5295 const Char* pa = a.start();
5296 const Char* pb = b.start();
5297 int i = 0;
5298#ifndef V8_HOST_CAN_READ_UNALIGNED
5299 // If this architecture isn't comfortable reading unaligned ints
5300 // then we have to check that the strings are aligned before
5301 // comparing them blockwise.
5302 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5303 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5304 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5305 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5306#endif
5307 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5308 int endpoint = length - kStepSize;
5309 // Compare blocks until we reach near the end of the string.
5310 for (; i <= endpoint; i += kStepSize) {
5311 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5312 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5313 if (wa != wb) {
5314 return false;
5315 }
5316 }
5317#ifndef V8_HOST_CAN_READ_UNALIGNED
5318 }
5319#endif
5320 // Compare the remaining characters that didn't fit into a block.
5321 for (; i < length; i++) {
5322 if (a[i] != b[i]) {
5323 return false;
5324 }
5325 }
5326 return true;
5327}
5328
5329
Steve Blocka7e24c12009-10-30 11:49:00 +00005330template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005331static inline bool CompareStringContentsPartial(Isolate* isolate,
5332 IteratorA* ia,
5333 String* b) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005334 if (b->IsFlat()) {
5335 if (b->IsAsciiRepresentation()) {
5336 VectorIterator<char> ib(b->ToAsciiVector());
5337 return CompareStringContents(ia, &ib);
5338 } else {
5339 VectorIterator<uc16> ib(b->ToUC16Vector());
5340 return CompareStringContents(ia, &ib);
5341 }
5342 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005343 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5344 return CompareStringContents(ia,
5345 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005346 }
5347}
5348
5349
Steve Blocka7e24c12009-10-30 11:49:00 +00005350bool String::SlowEquals(String* other) {
5351 // Fast check: negative check with lengths.
5352 int len = length();
5353 if (len != other->length()) return false;
5354 if (len == 0) return true;
5355
5356 // Fast check: if hash code is computed for both strings
5357 // a fast negative check can be performed.
5358 if (HasHashCode() && other->HasHashCode()) {
5359 if (Hash() != other->Hash()) return false;
5360 }
5361
Leon Clarkef7060e22010-06-03 12:02:55 +01005362 // We know the strings are both non-empty. Compare the first chars
5363 // before we try to flatten the strings.
5364 if (this->Get(0) != other->Get(0)) return false;
5365
5366 String* lhs = this->TryFlattenGetString();
5367 String* rhs = other->TryFlattenGetString();
5368
5369 if (StringShape(lhs).IsSequentialAscii() &&
5370 StringShape(rhs).IsSequentialAscii()) {
5371 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5372 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005373 return CompareRawStringContents(Vector<const char>(str1, len),
5374 Vector<const char>(str2, len));
5375 }
5376
Steve Block44f0eee2011-05-26 01:26:41 +01005377 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01005378 if (lhs->IsFlat()) {
Ben Murdochbb769b22010-08-11 14:56:33 +01005379 if (lhs->IsAsciiRepresentation()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01005380 Vector<const char> vec1 = lhs->ToAsciiVector();
5381 if (rhs->IsFlat()) {
5382 if (rhs->IsAsciiRepresentation()) {
5383 Vector<const char> vec2 = rhs->ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005384 return CompareRawStringContents(vec1, vec2);
5385 } else {
5386 VectorIterator<char> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005387 VectorIterator<uc16> ib(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005388 return CompareStringContents(&buf1, &ib);
5389 }
5390 } else {
5391 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005392 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5393 return CompareStringContents(&buf1,
5394 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005395 }
5396 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005397 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5398 if (rhs->IsFlat()) {
5399 if (rhs->IsAsciiRepresentation()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005400 VectorIterator<uc16> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005401 VectorIterator<char> ib(rhs->ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005402 return CompareStringContents(&buf1, &ib);
5403 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005404 Vector<const uc16> vec2(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005405 return CompareRawStringContents(vec1, vec2);
5406 }
5407 } else {
5408 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005409 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5410 return CompareStringContents(&buf1,
5411 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005412 }
5413 }
5414 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005415 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5416 return CompareStringContentsPartial(isolate,
5417 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00005418 }
5419}
5420
5421
5422bool String::MarkAsUndetectable() {
5423 if (StringShape(this).IsSymbol()) return false;
5424
5425 Map* map = this->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005426 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01005427 if (map == heap->string_map()) {
5428 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005429 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01005430 } else if (map == heap->ascii_string_map()) {
5431 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005432 return true;
5433 }
5434 // Rest cannot be marked as undetectable
5435 return false;
5436}
5437
5438
5439bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01005440 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00005441 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005442 Access<UnicodeCache::Utf8Decoder>
5443 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00005444 decoder->Reset(str.start(), str.length());
5445 int i;
5446 for (i = 0; i < slen && decoder->has_more(); i++) {
5447 uc32 r = decoder->GetNext();
5448 if (Get(i) != r) return false;
5449 }
5450 return i == slen && !decoder->has_more();
5451}
5452
5453
Steve Block9fac8402011-05-12 15:51:54 +01005454bool String::IsAsciiEqualTo(Vector<const char> str) {
5455 int slen = length();
5456 if (str.length() != slen) return false;
5457 for (int i = 0; i < slen; i++) {
5458 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
5459 }
5460 return true;
5461}
5462
5463
5464bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
5465 int slen = length();
5466 if (str.length() != slen) return false;
5467 for (int i = 0; i < slen; i++) {
5468 if (Get(i) != str[i]) return false;
5469 }
5470 return true;
5471}
5472
5473
Steve Blocka7e24c12009-10-30 11:49:00 +00005474uint32_t String::ComputeAndSetHash() {
5475 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005476 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005477
Steve Block6ded16b2010-05-10 14:33:55 +01005478 const int len = length();
5479
Steve Blocka7e24c12009-10-30 11:49:00 +00005480 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01005481 uint32_t field = 0;
5482 if (StringShape(this).IsSequentialAscii()) {
5483 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
5484 } else if (StringShape(this).IsSequentialTwoByte()) {
5485 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
5486 } else {
5487 StringInputBuffer buffer(this);
5488 field = ComputeHashField(&buffer, len);
5489 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005490
5491 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00005492 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00005493
5494 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005495 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005496 uint32_t result = field >> kHashShift;
5497 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
5498 return result;
5499}
5500
5501
5502bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
5503 uint32_t* index,
5504 int length) {
5505 if (length == 0 || length > kMaxArrayIndexSize) return false;
5506 uc32 ch = buffer->GetNext();
5507
5508 // If the string begins with a '0' character, it must only consist
5509 // of it to be a legal array index.
5510 if (ch == '0') {
5511 *index = 0;
5512 return length == 1;
5513 }
5514
5515 // Convert string to uint32 array index; character by character.
5516 int d = ch - '0';
5517 if (d < 0 || d > 9) return false;
5518 uint32_t result = d;
5519 while (buffer->has_more()) {
5520 d = buffer->GetNext() - '0';
5521 if (d < 0 || d > 9) return false;
5522 // Check that the new result is below the 32 bit limit.
5523 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
5524 result = (result * 10) + d;
5525 }
5526
5527 *index = result;
5528 return true;
5529}
5530
5531
5532bool String::SlowAsArrayIndex(uint32_t* index) {
5533 if (length() <= kMaxCachedArrayIndexLength) {
5534 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00005535 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005536 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00005537 // Isolate the array index form the full hash field.
5538 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00005539 return true;
5540 } else {
5541 StringInputBuffer buffer(this);
5542 return ComputeArrayIndex(&buffer, index, length());
5543 }
5544}
5545
5546
Iain Merrick9ac36c92010-09-13 15:29:50 +01005547uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005548 // For array indexes mix the length into the hash as an array index could
5549 // be zero.
5550 ASSERT(length > 0);
5551 ASSERT(length <= String::kMaxArrayIndexSize);
5552 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5553 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01005554
5555 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005556 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01005557
5558 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
5559 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
5560 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005561 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00005562}
5563
5564
5565uint32_t StringHasher::GetHashField() {
5566 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00005567 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005568 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005569 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00005570 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005571 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005572 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005573 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005574 }
5575}
5576
5577
Steve Blockd0582a62009-12-15 09:54:21 +00005578uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
5579 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005580 StringHasher hasher(length);
5581
5582 // Very long strings have a trivial hash that doesn't inspect the
5583 // string contents.
5584 if (hasher.has_trivial_hash()) {
5585 return hasher.GetHashField();
5586 }
5587
5588 // Do the iterative array index computation as long as there is a
5589 // chance this is an array index.
5590 while (buffer->has_more() && hasher.is_array_index()) {
5591 hasher.AddCharacter(buffer->GetNext());
5592 }
5593
5594 // Process the remaining characters without updating the array
5595 // index.
5596 while (buffer->has_more()) {
5597 hasher.AddCharacterNoIndex(buffer->GetNext());
5598 }
5599
5600 return hasher.GetHashField();
5601}
5602
5603
John Reck59135872010-11-02 12:39:01 -07005604MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005605 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005606 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01005607 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00005608 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005609}
5610
5611
5612void String::PrintOn(FILE* file) {
5613 int length = this->length();
5614 for (int i = 0; i < length; i++) {
5615 fprintf(file, "%c", Get(i));
5616 }
5617}
5618
5619
5620void Map::CreateBackPointers() {
5621 DescriptorArray* descriptors = instance_descriptors();
5622 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01005623 if (descriptors->GetType(i) == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005624 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005625 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005626 // Get target.
5627 Map* target = Map::cast(descriptors->GetValue(i));
5628#ifdef DEBUG
5629 // Verify target.
5630 Object* source_prototype = prototype();
5631 Object* target_prototype = target->prototype();
5632 ASSERT(source_prototype->IsJSObject() ||
5633 source_prototype->IsMap() ||
5634 source_prototype->IsNull());
5635 ASSERT(target_prototype->IsJSObject() ||
5636 target_prototype->IsNull());
5637 ASSERT(source_prototype->IsMap() ||
5638 source_prototype == target_prototype);
5639#endif
5640 // Point target back to source. set_prototype() will not let us set
5641 // the prototype to a map, as we do here.
5642 *RawField(target, kPrototypeOffset) = this;
5643 }
5644 }
5645}
5646
5647
Steve Block44f0eee2011-05-26 01:26:41 +01005648void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005649 // Live DescriptorArray objects will be marked, so we must use
5650 // low-level accessors to get and modify their data.
5651 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
5652 *RawField(this, Map::kInstanceDescriptorsOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01005653 if (d == heap->raw_unchecked_empty_descriptor_array()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005654 Smi* NullDescriptorDetails =
5655 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
5656 FixedArray* contents = reinterpret_cast<FixedArray*>(
5657 d->get(DescriptorArray::kContentArrayIndex));
5658 ASSERT(contents->length() >= 2);
5659 for (int i = 0; i < contents->length(); i += 2) {
5660 // If the pair (value, details) is a map transition,
5661 // check if the target is live. If not, null the descriptor.
5662 // Also drop the back pointer for that map transition, so that this
5663 // map is not reached again by following a back pointer from a
5664 // non-live object.
5665 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01005666 if (details.type() == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005667 details.type() == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005668 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005669 Map* target = reinterpret_cast<Map*>(contents->get(i));
5670 ASSERT(target->IsHeapObject());
5671 if (!target->IsMarked()) {
5672 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01005673 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01005674 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00005675 ASSERT(target->prototype() == this ||
5676 target->prototype() == real_prototype);
5677 // Getter prototype() is read-only, set_prototype() has side effects.
5678 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5679 }
5680 }
5681 }
5682}
5683
5684
Steve Block791712a2010-08-27 10:21:07 +01005685void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5686 // Iterate over all fields in the body but take care in dealing with
5687 // the code entry.
5688 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5689 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5690 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5691}
5692
5693
Ben Murdochb0fe1622011-05-05 13:52:32 +01005694void JSFunction::MarkForLazyRecompilation() {
5695 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005696 ASSERT(shared()->allows_lazy_compilation() ||
5697 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01005698 Builtins* builtins = GetIsolate()->builtins();
5699 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005700}
5701
5702
5703uint32_t JSFunction::SourceHash() {
5704 uint32_t hash = 0;
5705 Object* script = shared()->script();
5706 if (!script->IsUndefined()) {
5707 Object* source = Script::cast(script)->source();
5708 if (source->IsUndefined()) hash = String::cast(source)->Hash();
5709 }
5710 hash ^= ComputeIntegerHash(shared()->start_position_and_type());
5711 hash += ComputeIntegerHash(shared()->end_position());
5712 return hash;
5713}
5714
5715
5716bool JSFunction::IsInlineable() {
5717 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005718 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005719 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005720 if (!shared_info->script()->IsScript()) return false;
5721 if (shared_info->optimization_disabled()) return false;
5722 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005723 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
5724 // If we never ran this (unlikely) then lets try to optimize it.
5725 if (code->kind() != Code::FUNCTION) return true;
5726 return code->optimizable();
5727}
5728
5729
Steve Blocka7e24c12009-10-30 11:49:00 +00005730Object* JSFunction::SetInstancePrototype(Object* value) {
5731 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01005732 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005733 if (has_initial_map()) {
5734 initial_map()->set_prototype(value);
5735 } else {
5736 // Put the value in the initial map field until an initial map is
5737 // needed. At that point, a new initial map is created and the
5738 // prototype is put into the initial map where it belongs.
5739 set_prototype_or_initial_map(value);
5740 }
Steve Block44f0eee2011-05-26 01:26:41 +01005741 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005742 return value;
5743}
5744
5745
John Reck59135872010-11-02 12:39:01 -07005746MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01005747 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00005748 Object* construct_prototype = value;
5749
5750 // If the value is not a JSObject, store the value in the map's
5751 // constructor field so it can be accessed. Also, set the prototype
5752 // used for constructing objects to the original object prototype.
5753 // See ECMA-262 13.2.2.
5754 if (!value->IsJSObject()) {
5755 // Copy the map so this does not affect unrelated functions.
5756 // Remove map transitions because they point to maps with a
5757 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005758 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07005759 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005760 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07005761 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005762 Map* new_map = Map::cast(new_object);
5763 Heap* heap = new_map->heap();
5764 set_map(new_map);
5765 new_map->set_constructor(value);
5766 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005767 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01005768 heap->isolate()->context()->global_context()->
5769 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00005770 } else {
5771 map()->set_non_instance_prototype(false);
5772 }
5773
5774 return SetInstancePrototype(construct_prototype);
5775}
5776
5777
Steve Block6ded16b2010-05-10 14:33:55 +01005778Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01005779 Context* global_context = context()->global_context();
5780 Map* no_prototype_map = shared()->strict_mode()
5781 ? global_context->strict_mode_function_without_prototype_map()
5782 : global_context->function_without_prototype_map();
5783
5784 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005785 // Be idempotent.
5786 return this;
5787 }
Steve Block44f0eee2011-05-26 01:26:41 +01005788
5789 ASSERT(!shared()->strict_mode() ||
5790 map() == global_context->strict_mode_function_map());
5791 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
5792
5793 set_map(no_prototype_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01005794 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005795 return this;
5796}
5797
5798
Steve Blocka7e24c12009-10-30 11:49:00 +00005799Object* JSFunction::SetInstanceClassName(String* name) {
5800 shared()->set_instance_class_name(name);
5801 return this;
5802}
5803
5804
Ben Murdochb0fe1622011-05-05 13:52:32 +01005805void JSFunction::PrintName(FILE* out) {
5806 SmartPointer<char> name = shared()->DebugName()->ToCString();
5807 PrintF(out, "%s", *name);
5808}
5809
5810
Steve Blocka7e24c12009-10-30 11:49:00 +00005811Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
5812 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
5813}
5814
5815
Steve Block44f0eee2011-05-26 01:26:41 +01005816MaybeObject* Oddball::Initialize(const char* to_string,
5817 Object* to_number,
5818 byte kind) {
John Reck59135872010-11-02 12:39:01 -07005819 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01005820 { MaybeObject* maybe_symbol =
5821 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07005822 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
5823 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005824 set_to_string(String::cast(symbol));
5825 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01005826 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00005827 return this;
5828}
5829
5830
Ben Murdochf87a2032010-10-22 12:50:53 +01005831String* SharedFunctionInfo::DebugName() {
5832 Object* n = name();
5833 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
5834 return String::cast(n);
5835}
5836
5837
Steve Blocka7e24c12009-10-30 11:49:00 +00005838bool SharedFunctionInfo::HasSourceCode() {
5839 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01005840 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00005841}
5842
5843
5844Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01005845 Isolate* isolate = GetIsolate();
5846 if (!HasSourceCode()) return isolate->heap()->undefined_value();
5847 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005848 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01005849 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00005850 start_position(), end_position());
5851}
5852
5853
Ben Murdochb0fe1622011-05-05 13:52:32 +01005854int SharedFunctionInfo::SourceSize() {
5855 return end_position() - start_position();
5856}
5857
5858
Steve Blocka7e24c12009-10-30 11:49:00 +00005859int SharedFunctionInfo::CalculateInstanceSize() {
5860 int instance_size =
5861 JSObject::kHeaderSize +
5862 expected_nof_properties() * kPointerSize;
5863 if (instance_size > JSObject::kMaxInstanceSize) {
5864 instance_size = JSObject::kMaxInstanceSize;
5865 }
5866 return instance_size;
5867}
5868
5869
5870int SharedFunctionInfo::CalculateInObjectProperties() {
5871 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
5872}
5873
5874
Andrei Popescu402d9372010-02-26 13:31:12 +00005875bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
5876 // Check the basic conditions for generating inline constructor code.
5877 if (!FLAG_inline_new
5878 || !has_only_simple_this_property_assignments()
5879 || this_property_assignments_count() == 0) {
5880 return false;
5881 }
5882
5883 // If the prototype is null inline constructors cause no problems.
5884 if (!prototype->IsJSObject()) {
5885 ASSERT(prototype->IsNull());
5886 return true;
5887 }
5888
Ben Murdoch8b112d22011-06-08 16:22:53 +01005889 Heap* heap = GetHeap();
5890
Andrei Popescu402d9372010-02-26 13:31:12 +00005891 // Traverse the proposed prototype chain looking for setters for properties of
5892 // the same names as are set by the inline constructor.
5893 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01005894 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00005895 obj = obj->GetPrototype()) {
5896 JSObject* js_object = JSObject::cast(obj);
5897 for (int i = 0; i < this_property_assignments_count(); i++) {
5898 LookupResult result;
5899 String* name = GetThisPropertyAssignmentName(i);
5900 js_object->LocalLookupRealNamedProperty(name, &result);
5901 if (result.IsProperty() && result.type() == CALLBACKS) {
5902 return false;
5903 }
5904 }
5905 }
5906
5907 return true;
5908}
5909
5910
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005911void SharedFunctionInfo::ForbidInlineConstructor() {
5912 set_compiler_hints(BooleanBit::set(compiler_hints(),
5913 kHasOnlySimpleThisPropertyAssignments,
5914 false));
5915}
5916
5917
Steve Blocka7e24c12009-10-30 11:49:00 +00005918void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00005919 bool only_simple_this_property_assignments,
5920 FixedArray* assignments) {
5921 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00005922 kHasOnlySimpleThisPropertyAssignments,
5923 only_simple_this_property_assignments));
5924 set_this_property_assignments(assignments);
5925 set_this_property_assignments_count(assignments->length() / 3);
5926}
5927
5928
5929void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01005930 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005931 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00005932 kHasOnlySimpleThisPropertyAssignments,
5933 false));
Steve Block44f0eee2011-05-26 01:26:41 +01005934 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005935 set_this_property_assignments_count(0);
5936}
5937
5938
5939String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
5940 Object* obj = this_property_assignments();
5941 ASSERT(obj->IsFixedArray());
5942 ASSERT(index < this_property_assignments_count());
5943 obj = FixedArray::cast(obj)->get(index * 3);
5944 ASSERT(obj->IsString());
5945 return String::cast(obj);
5946}
5947
5948
5949bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
5950 Object* obj = this_property_assignments();
5951 ASSERT(obj->IsFixedArray());
5952 ASSERT(index < this_property_assignments_count());
5953 obj = FixedArray::cast(obj)->get(index * 3 + 1);
5954 return Smi::cast(obj)->value() != -1;
5955}
5956
5957
5958int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
5959 ASSERT(IsThisPropertyAssignmentArgument(index));
5960 Object* obj =
5961 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
5962 return Smi::cast(obj)->value();
5963}
5964
5965
5966Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
5967 ASSERT(!IsThisPropertyAssignmentArgument(index));
5968 Object* obj =
5969 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
5970 return obj;
5971}
5972
5973
Steve Blocka7e24c12009-10-30 11:49:00 +00005974// Support function for printing the source code to a StringStream
5975// without any allocation in the heap.
5976void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
5977 int max_length) {
5978 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01005979 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005980 accumulator->Add("<No Source>");
5981 return;
5982 }
5983
Steve Blockd0582a62009-12-15 09:54:21 +00005984 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00005985 // Don't use String::cast because we don't want more assertion errors while
5986 // we are already creating a stack dump.
5987 String* script_source =
5988 reinterpret_cast<String*>(Script::cast(script())->source());
5989
5990 if (!script_source->LooksValid()) {
5991 accumulator->Add("<Invalid Source>");
5992 return;
5993 }
5994
5995 if (!is_toplevel()) {
5996 accumulator->Add("function ");
5997 Object* name = this->name();
5998 if (name->IsString() && String::cast(name)->length() > 0) {
5999 accumulator->PrintName(name);
6000 }
6001 }
6002
6003 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006004 if (len <= max_length || max_length < 0) {
6005 accumulator->Put(script_source, start_position(), end_position());
6006 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006007 accumulator->Put(script_source,
6008 start_position(),
6009 start_position() + max_length);
6010 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006011 }
6012}
6013
6014
Ben Murdochb0fe1622011-05-05 13:52:32 +01006015static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6016 if (code->instruction_size() != recompiled->instruction_size()) return false;
6017 ByteArray* code_relocation = code->relocation_info();
6018 ByteArray* recompiled_relocation = recompiled->relocation_info();
6019 int length = code_relocation->length();
6020 if (length != recompiled_relocation->length()) return false;
6021 int compare = memcmp(code_relocation->GetDataStartAddress(),
6022 recompiled_relocation->GetDataStartAddress(),
6023 length);
6024 return compare == 0;
6025}
6026
6027
6028void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6029 ASSERT(!has_deoptimization_support());
6030 AssertNoAllocation no_allocation;
6031 Code* code = this->code();
6032 if (IsCodeEquivalent(code, recompiled)) {
6033 // Copy the deoptimization data from the recompiled code.
6034 code->set_deoptimization_data(recompiled->deoptimization_data());
6035 code->set_has_deoptimization_support(true);
6036 } else {
6037 // TODO(3025757): In case the recompiled isn't equivalent to the
6038 // old code, we have to replace it. We should try to avoid this
6039 // altogether because it flushes valuable type feedback by
6040 // effectively resetting all IC state.
6041 set_code(recompiled);
6042 }
6043 ASSERT(has_deoptimization_support());
6044}
6045
6046
6047bool SharedFunctionInfo::VerifyBailoutId(int id) {
6048 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6049 // we are always bailing out on ARM.
6050
6051 ASSERT(id != AstNode::kNoNumber);
6052 Code* unoptimized = code();
6053 DeoptimizationOutputData* data =
6054 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6055 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6056 USE(ignore);
6057 return true; // Return true if there was no ASSERT.
6058}
6059
6060
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006061void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6062 ASSERT(!IsInobjectSlackTrackingInProgress());
6063
6064 // Only initiate the tracking the first time.
6065 if (live_objects_may_exist()) return;
6066 set_live_objects_may_exist(true);
6067
6068 // No tracking during the snapshot construction phase.
6069 if (Serializer::enabled()) return;
6070
6071 if (map->unused_property_fields() == 0) return;
6072
6073 // Nonzero counter is a leftover from the previous attempt interrupted
6074 // by GC, keep it.
6075 if (construction_count() == 0) {
6076 set_construction_count(kGenerousAllocationCount);
6077 }
6078 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006079 Builtins* builtins = map->heap()->isolate()->builtins();
6080 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006081 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006082 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006083}
6084
6085
6086// Called from GC, hence reinterpret_cast and unchecked accessors.
6087void SharedFunctionInfo::DetachInitialMap() {
6088 Map* map = reinterpret_cast<Map*>(initial_map());
6089
6090 // Make the map remember to restore the link if it survives the GC.
6091 map->set_bit_field2(
6092 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6093
6094 // Undo state changes made by StartInobjectTracking (except the
6095 // construction_count). This way if the initial map does not survive the GC
6096 // then StartInobjectTracking will be called again the next time the
6097 // constructor is called. The countdown will continue and (possibly after
6098 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006099 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6100 Builtins* builtins = map->heap()->isolate()->builtins();
6101 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006102 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006103 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006104 // It is safe to clear the flag: it will be set again if the map is live.
6105 set_live_objects_may_exist(false);
6106}
6107
6108
6109// Called from GC, hence reinterpret_cast and unchecked accessors.
6110void SharedFunctionInfo::AttachInitialMap(Map* map) {
6111 map->set_bit_field2(
6112 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6113
6114 // Resume inobject slack tracking.
6115 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006116 Builtins* builtins = map->heap()->isolate()->builtins();
6117 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006118 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006119 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006120 // The map survived the gc, so there may be objects referencing it.
6121 set_live_objects_may_exist(true);
6122}
6123
6124
6125static void GetMinInobjectSlack(Map* map, void* data) {
6126 int slack = map->unused_property_fields();
6127 if (*reinterpret_cast<int*>(data) > slack) {
6128 *reinterpret_cast<int*>(data) = slack;
6129 }
6130}
6131
6132
6133static void ShrinkInstanceSize(Map* map, void* data) {
6134 int slack = *reinterpret_cast<int*>(data);
6135 map->set_inobject_properties(map->inobject_properties() - slack);
6136 map->set_unused_property_fields(map->unused_property_fields() - slack);
6137 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6138
6139 // Visitor id might depend on the instance size, recalculate it.
6140 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6141}
6142
6143
6144void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6145 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6146 Map* map = Map::cast(initial_map());
6147
Steve Block44f0eee2011-05-26 01:26:41 +01006148 Heap* heap = map->heap();
6149 set_initial_map(heap->undefined_value());
6150 Builtins* builtins = heap->isolate()->builtins();
6151 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006152 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006153 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006154
6155 int slack = map->unused_property_fields();
6156 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6157 if (slack != 0) {
6158 // Resize the initial map and all maps in its transition tree.
6159 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
6160 // Give the correct expected_nof_properties to initial maps created later.
6161 ASSERT(expected_nof_properties() >= slack);
6162 set_expected_nof_properties(expected_nof_properties() - slack);
6163 }
6164}
6165
6166
Steve Blocka7e24c12009-10-30 11:49:00 +00006167void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6168 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6169 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6170 Object* old_target = target;
6171 VisitPointer(&target);
6172 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6173}
6174
6175
Steve Block791712a2010-08-27 10:21:07 +01006176void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6177 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6178 Object* old_code = code;
6179 VisitPointer(&code);
6180 if (code != old_code) {
6181 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6182 }
6183}
6184
6185
Ben Murdochb0fe1622011-05-05 13:52:32 +01006186void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6187 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6188 Object* cell = rinfo->target_cell();
6189 Object* old_cell = cell;
6190 VisitPointer(&cell);
6191 if (cell != old_cell) {
6192 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6193 }
6194}
6195
6196
Steve Blocka7e24c12009-10-30 11:49:00 +00006197void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006198 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6199 rinfo->IsPatchedReturnSequence()) ||
6200 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6201 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006202 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6203 Object* old_target = target;
6204 VisitPointer(&target);
6205 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6206}
6207
6208
Ben Murdochb0fe1622011-05-05 13:52:32 +01006209void Code::InvalidateRelocation() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006210 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006211}
6212
6213
Steve Blockd0582a62009-12-15 09:54:21 +00006214void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006215 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6216 it.rinfo()->apply(delta);
6217 }
6218 CPU::FlushICache(instruction_start(), instruction_size());
6219}
6220
6221
6222void Code::CopyFrom(const CodeDesc& desc) {
6223 // copy code
6224 memmove(instruction_start(), desc.buffer, desc.instr_size);
6225
Steve Blocka7e24c12009-10-30 11:49:00 +00006226 // copy reloc info
6227 memmove(relocation_start(),
6228 desc.buffer + desc.buffer_size - desc.reloc_size,
6229 desc.reloc_size);
6230
6231 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006232 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006233 int mode_mask = RelocInfo::kCodeTargetMask |
6234 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006235 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006236 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006237 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006238 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6239 RelocInfo::Mode mode = it.rinfo()->rmode();
6240 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006241 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006242 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006243 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006244 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006245 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006246 } else if (RelocInfo::IsCodeTarget(mode)) {
6247 // rewrite code handles in inline cache targets to direct
6248 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006249 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006250 Code* code = Code::cast(*p);
6251 it.rinfo()->set_target_address(code->instruction_start());
6252 } else {
6253 it.rinfo()->apply(delta);
6254 }
6255 }
6256 CPU::FlushICache(instruction_start(), instruction_size());
6257}
6258
6259
6260// Locate the source position which is closest to the address in the code. This
6261// is using the source position information embedded in the relocation info.
6262// The position returned is relative to the beginning of the script where the
6263// source for this function is found.
6264int Code::SourcePosition(Address pc) {
6265 int distance = kMaxInt;
6266 int position = RelocInfo::kNoPosition; // Initially no position found.
6267 // Run through all the relocation info to find the best matching source
6268 // position. All the code needs to be considered as the sequence of the
6269 // instructions in the code does not necessarily follow the same order as the
6270 // source.
6271 RelocIterator it(this, RelocInfo::kPositionMask);
6272 while (!it.done()) {
6273 // Only look at positions after the current pc.
6274 if (it.rinfo()->pc() < pc) {
6275 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006276
6277 int dist = static_cast<int>(pc - it.rinfo()->pc());
6278 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006279 // If this position is closer than the current candidate or if it has the
6280 // same distance as the current candidate and the position is higher then
6281 // this position is the new candidate.
6282 if ((dist < distance) ||
6283 (dist == distance && pos > position)) {
6284 position = pos;
6285 distance = dist;
6286 }
6287 }
6288 it.next();
6289 }
6290 return position;
6291}
6292
6293
6294// Same as Code::SourcePosition above except it only looks for statement
6295// positions.
6296int Code::SourceStatementPosition(Address pc) {
6297 // First find the position as close as possible using all position
6298 // information.
6299 int position = SourcePosition(pc);
6300 // Now find the closest statement position before the position.
6301 int statement_position = 0;
6302 RelocIterator it(this, RelocInfo::kPositionMask);
6303 while (!it.done()) {
6304 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006305 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006306 if (statement_position < p && p <= position) {
6307 statement_position = p;
6308 }
6309 }
6310 it.next();
6311 }
6312 return statement_position;
6313}
6314
6315
Ben Murdochb8e0da22011-05-16 14:20:40 +01006316SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006317 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006318 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006319}
6320
6321
6322void Code::SetNoStackCheckTable() {
6323 // Indicate the absence of a stack-check table by a table start after the
6324 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006325 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006326}
6327
6328
6329Map* Code::FindFirstMap() {
6330 ASSERT(is_inline_cache_stub());
6331 AssertNoAllocation no_allocation;
6332 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6333 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6334 RelocInfo* info = it.rinfo();
6335 Object* object = info->target_object();
6336 if (object->IsMap()) return Map::cast(object);
6337 }
6338 return NULL;
6339}
6340
6341
Steve Blocka7e24c12009-10-30 11:49:00 +00006342#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006343
6344#ifdef OBJECT_PRINT
6345
6346void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6347 disasm::NameConverter converter;
6348 int deopt_count = DeoptCount();
6349 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6350 if (0 == deopt_count) return;
6351
6352 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
6353 for (int i = 0; i < deopt_count; i++) {
6354 int command_count = 0;
6355 PrintF(out, "%6d %6d %6d",
6356 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
6357 int translation_index = TranslationIndex(i)->value();
6358 TranslationIterator iterator(TranslationByteArray(), translation_index);
6359 Translation::Opcode opcode =
6360 static_cast<Translation::Opcode>(iterator.Next());
6361 ASSERT(Translation::BEGIN == opcode);
6362 int frame_count = iterator.Next();
6363 if (FLAG_print_code_verbose) {
6364 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6365 frame_count);
6366 }
6367
6368 for (int i = 0; i < frame_count; ++i) {
6369 opcode = static_cast<Translation::Opcode>(iterator.Next());
6370 ASSERT(Translation::FRAME == opcode);
6371 int ast_id = iterator.Next();
6372 int function_id = iterator.Next();
6373 JSFunction* function =
6374 JSFunction::cast(LiteralArray()->get(function_id));
6375 unsigned height = iterator.Next();
6376 if (FLAG_print_code_verbose) {
6377 PrintF(out, "%24s %s {ast_id=%d, function=",
6378 "", Translation::StringFor(opcode), ast_id);
6379 function->PrintName(out);
6380 PrintF(out, ", height=%u}\n", height);
6381 }
6382
6383 // Size of translation is height plus all incoming arguments including
6384 // receiver.
6385 int size = height + function->shared()->formal_parameter_count() + 1;
6386 command_count += size;
6387 for (int j = 0; j < size; ++j) {
6388 opcode = static_cast<Translation::Opcode>(iterator.Next());
6389 if (FLAG_print_code_verbose) {
6390 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
6391 }
6392
6393 if (opcode == Translation::DUPLICATE) {
6394 opcode = static_cast<Translation::Opcode>(iterator.Next());
6395 if (FLAG_print_code_verbose) {
6396 PrintF(out, "%s ", Translation::StringFor(opcode));
6397 }
6398 --j; // Two commands share the same frame index.
6399 }
6400
6401 switch (opcode) {
6402 case Translation::BEGIN:
6403 case Translation::FRAME:
6404 case Translation::DUPLICATE:
6405 UNREACHABLE();
6406 break;
6407
6408 case Translation::REGISTER: {
6409 int reg_code = iterator.Next();
6410 if (FLAG_print_code_verbose) {
6411 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6412 }
6413 break;
6414 }
6415
6416 case Translation::INT32_REGISTER: {
6417 int reg_code = iterator.Next();
6418 if (FLAG_print_code_verbose) {
6419 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6420 }
6421 break;
6422 }
6423
6424 case Translation::DOUBLE_REGISTER: {
6425 int reg_code = iterator.Next();
6426 if (FLAG_print_code_verbose) {
6427 PrintF(out, "{input=%s}",
6428 DoubleRegister::AllocationIndexToString(reg_code));
6429 }
6430 break;
6431 }
6432
6433 case Translation::STACK_SLOT: {
6434 int input_slot_index = iterator.Next();
6435 if (FLAG_print_code_verbose) {
6436 PrintF(out, "{input=%d}", input_slot_index);
6437 }
6438 break;
6439 }
6440
6441 case Translation::INT32_STACK_SLOT: {
6442 int input_slot_index = iterator.Next();
6443 if (FLAG_print_code_verbose) {
6444 PrintF(out, "{input=%d}", input_slot_index);
6445 }
6446 break;
6447 }
6448
6449 case Translation::DOUBLE_STACK_SLOT: {
6450 int input_slot_index = iterator.Next();
6451 if (FLAG_print_code_verbose) {
6452 PrintF(out, "{input=%d}", input_slot_index);
6453 }
6454 break;
6455 }
6456
6457 case Translation::LITERAL: {
6458 unsigned literal_index = iterator.Next();
6459 if (FLAG_print_code_verbose) {
6460 PrintF(out, "{literal_id=%u}", literal_index);
6461 }
6462 break;
6463 }
6464
6465 case Translation::ARGUMENTS_OBJECT:
6466 break;
6467 }
6468 if (FLAG_print_code_verbose) PrintF(out, "\n");
6469 }
6470 }
6471 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
6472 }
6473}
6474
6475
6476void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
6477 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
6478 this->DeoptPoints());
6479 if (this->DeoptPoints() == 0) return;
6480
6481 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
6482 for (int i = 0; i < this->DeoptPoints(); i++) {
6483 int pc_and_state = this->PcAndState(i)->value();
6484 PrintF("%6d %8d %s\n",
6485 this->AstId(i)->value(),
6486 FullCodeGenerator::PcField::decode(pc_and_state),
6487 FullCodeGenerator::State2String(
6488 FullCodeGenerator::StateField::decode(pc_and_state)));
6489 }
6490}
6491
6492#endif
6493
6494
Steve Blocka7e24c12009-10-30 11:49:00 +00006495// Identify kind of code.
6496const char* Code::Kind2String(Kind kind) {
6497 switch (kind) {
6498 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006499 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006500 case STUB: return "STUB";
6501 case BUILTIN: return "BUILTIN";
6502 case LOAD_IC: return "LOAD_IC";
6503 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
Steve Block44f0eee2011-05-26 01:26:41 +01006504 case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006505 case STORE_IC: return "STORE_IC";
6506 case KEYED_STORE_IC: return "KEYED_STORE_IC";
Steve Block44f0eee2011-05-26 01:26:41 +01006507 case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006508 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006509 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006510 case TYPE_RECORDING_BINARY_OP_IC: return "TYPE_RECORDING_BINARY_OP_IC";
6511 case COMPARE_IC: return "COMPARE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006512 }
6513 UNREACHABLE();
6514 return NULL;
6515}
6516
6517
6518const char* Code::ICState2String(InlineCacheState state) {
6519 switch (state) {
6520 case UNINITIALIZED: return "UNINITIALIZED";
6521 case PREMONOMORPHIC: return "PREMONOMORPHIC";
6522 case MONOMORPHIC: return "MONOMORPHIC";
6523 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
6524 case MEGAMORPHIC: return "MEGAMORPHIC";
6525 case DEBUG_BREAK: return "DEBUG_BREAK";
6526 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
6527 }
6528 UNREACHABLE();
6529 return NULL;
6530}
6531
6532
6533const char* Code::PropertyType2String(PropertyType type) {
6534 switch (type) {
6535 case NORMAL: return "NORMAL";
6536 case FIELD: return "FIELD";
6537 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
6538 case CALLBACKS: return "CALLBACKS";
6539 case INTERCEPTOR: return "INTERCEPTOR";
6540 case MAP_TRANSITION: return "MAP_TRANSITION";
Steve Block44f0eee2011-05-26 01:26:41 +01006541 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006542 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
6543 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
6544 }
6545 UNREACHABLE();
6546 return NULL;
6547}
6548
Ben Murdochb0fe1622011-05-05 13:52:32 +01006549
Steve Block1e0659c2011-05-24 12:43:12 +01006550void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
6551 const char* name = NULL;
6552 switch (kind) {
6553 case CALL_IC:
6554 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
6555 name = "STRING_INDEX_OUT_OF_BOUNDS";
6556 }
6557 break;
6558 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006559 case KEYED_STORE_IC:
6560 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01006561 name = "STRICT";
6562 }
6563 break;
6564 default:
6565 break;
6566 }
6567 if (name != NULL) {
6568 PrintF(out, "extra_ic_state = %s\n", name);
6569 } else {
6570 PrintF(out, "etra_ic_state = %d\n", extra);
6571 }
6572}
6573
6574
Ben Murdochb0fe1622011-05-05 13:52:32 +01006575void Code::Disassemble(const char* name, FILE* out) {
6576 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006577 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006578 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01006579 PrintExtraICState(out, kind(), extra_ic_state());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006580 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
Steve Blocka7e24c12009-10-30 11:49:00 +00006581 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006582 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006583 }
6584 }
6585 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006586 PrintF(out, "name = %s\n", name);
6587 }
6588 if (kind() == OPTIMIZED_FUNCTION) {
6589 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00006590 }
6591
Ben Murdochb0fe1622011-05-05 13:52:32 +01006592 PrintF(out, "Instructions (size = %d)\n", instruction_size());
6593 Disassembler::Decode(out, this);
6594 PrintF(out, "\n");
6595
6596#ifdef DEBUG
6597 if (kind() == FUNCTION) {
6598 DeoptimizationOutputData* data =
6599 DeoptimizationOutputData::cast(this->deoptimization_data());
6600 data->DeoptimizationOutputDataPrint(out);
6601 } else if (kind() == OPTIMIZED_FUNCTION) {
6602 DeoptimizationInputData* data =
6603 DeoptimizationInputData::cast(this->deoptimization_data());
6604 data->DeoptimizationInputDataPrint(out);
6605 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006606 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006607#endif
6608
6609 if (kind() == OPTIMIZED_FUNCTION) {
6610 SafepointTable table(this);
6611 PrintF(out, "Safepoints (size = %u)\n", table.size());
6612 for (unsigned i = 0; i < table.length(); i++) {
6613 unsigned pc_offset = table.GetPcOffset(i);
6614 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
6615 table.PrintEntry(i);
6616 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01006617 SafepointEntry entry = table.GetEntry(i);
6618 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
6619 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006620 } else {
6621 PrintF(out, " <none>");
6622 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01006623 if (entry.argument_count() > 0) {
6624 PrintF(out, " argc: %d", entry.argument_count());
6625 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006626 PrintF(out, "\n");
6627 }
6628 PrintF(out, "\n");
6629 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01006630 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006631 // If there is no stack check table, the "table start" will at or after
6632 // (due to alignment) the end of the instruction stream.
6633 if (static_cast<int>(offset) < instruction_size()) {
6634 unsigned* address =
6635 reinterpret_cast<unsigned*>(instruction_start() + offset);
6636 unsigned length = address[0];
6637 PrintF(out, "Stack checks (size = %u)\n", length);
6638 PrintF(out, "ast_id pc_offset\n");
6639 for (unsigned i = 0; i < length; ++i) {
6640 unsigned index = (2 * i) + 1;
6641 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
6642 }
6643 PrintF(out, "\n");
6644 }
6645 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006646
6647 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006648 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
6649 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006650}
6651#endif // ENABLE_DISASSEMBLER
6652
6653
John Reck59135872010-11-02 12:39:01 -07006654MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
6655 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006656 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00006657 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006658 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01006659
John Reck59135872010-11-02 12:39:01 -07006660 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006661 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006662 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6663 }
Steve Block8defd9f2010-07-08 12:39:36 +01006664 FixedArray* elems = FixedArray::cast(obj);
6665
John Reck59135872010-11-02 12:39:01 -07006666 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
6667 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6668 }
Steve Block8defd9f2010-07-08 12:39:36 +01006669 Map* new_map = Map::cast(obj);
6670
Leon Clarke4515c472010-02-03 11:58:03 +00006671 AssertNoAllocation no_gc;
6672 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00006673 switch (GetElementsKind()) {
6674 case FAST_ELEMENTS: {
6675 FixedArray* old_elements = FixedArray::cast(elements());
6676 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
6677 // Fill out the new array with this content and array holes.
6678 for (uint32_t i = 0; i < old_length; i++) {
6679 elems->set(i, old_elements->get(i), mode);
6680 }
6681 break;
6682 }
6683 case DICTIONARY_ELEMENTS: {
6684 NumberDictionary* dictionary = NumberDictionary::cast(elements());
6685 for (int i = 0; i < dictionary->Capacity(); i++) {
6686 Object* key = dictionary->KeyAt(i);
6687 if (key->IsNumber()) {
6688 uint32_t entry = static_cast<uint32_t>(key->Number());
6689 elems->set(entry, dictionary->ValueAt(i), mode);
6690 }
6691 }
6692 break;
6693 }
6694 default:
6695 UNREACHABLE();
6696 break;
6697 }
Steve Block8defd9f2010-07-08 12:39:36 +01006698
6699 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00006700 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01006701
6702 if (IsJSArray()) {
6703 JSArray::cast(this)->set_length(Smi::FromInt(length));
6704 }
6705
6706 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00006707}
6708
6709
John Reck59135872010-11-02 12:39:01 -07006710MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006711 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006712 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00006713
6714 uint32_t new_length = static_cast<uint32_t>(len->Number());
6715
6716 switch (GetElementsKind()) {
6717 case FAST_ELEMENTS: {
6718 // Make sure we never try to shrink dense arrays into sparse arrays.
6719 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
6720 new_length);
John Reck59135872010-11-02 12:39:01 -07006721 Object* obj;
6722 { MaybeObject* maybe_obj = NormalizeElements();
6723 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6724 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006725
6726 // Update length for JSArrays.
6727 if (IsJSArray()) JSArray::cast(this)->set_length(len);
6728 break;
6729 }
6730 case DICTIONARY_ELEMENTS: {
6731 if (IsJSArray()) {
6732 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01006733 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00006734 element_dictionary()->RemoveNumberEntries(new_length, old_length),
6735 JSArray::cast(this)->set_length(len);
6736 }
6737 break;
6738 }
6739 default:
6740 UNREACHABLE();
6741 break;
6742 }
6743 return this;
6744}
6745
6746
John Reck59135872010-11-02 12:39:01 -07006747MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01006748 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006749 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00006750 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00006751 FixedArray* new_elements;
6752 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006753 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00006754 } else {
John Reck59135872010-11-02 12:39:01 -07006755 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006756 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006757 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6758 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006759 new_elements = FixedArray::cast(obj);
6760 }
6761 set_elements(new_elements);
6762 return this;
6763}
6764
6765
6766void JSArray::Expand(int required_size) {
6767 Handle<JSArray> self(this);
6768 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
6769 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00006770 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01006771 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00006772 // Can't use this any more now because we may have had a GC!
6773 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
6774 self->SetContent(*new_backing);
6775}
6776
6777
Steve Block44f0eee2011-05-26 01:26:41 +01006778static Failure* ArrayLengthRangeError(Heap* heap) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006779 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006780 return heap->isolate()->Throw(
6781 *FACTORY->NewRangeError("invalid_array_length",
6782 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00006783}
6784
6785
John Reck59135872010-11-02 12:39:01 -07006786MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006787 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01006788 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00006789
John Reck59135872010-11-02 12:39:01 -07006790 MaybeObject* maybe_smi_length = len->ToSmi();
6791 Object* smi_length = Smi::FromInt(0);
6792 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01006793 const int value = Smi::cast(smi_length)->value();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006794 if (value < 0) return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00006795 switch (GetElementsKind()) {
6796 case FAST_ELEMENTS: {
6797 int old_capacity = FixedArray::cast(elements())->length();
6798 if (value <= old_capacity) {
6799 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07006800 Object* obj;
6801 { MaybeObject* maybe_obj = EnsureWritableFastElements();
6802 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6803 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006804 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
6805 // NOTE: We may be able to optimize this by removing the
6806 // last part of the elements backing storage array and
6807 // setting the capacity to the new size.
6808 for (int i = value; i < old_length; i++) {
6809 FixedArray::cast(elements())->set_the_hole(i);
6810 }
Leon Clarke4515c472010-02-03 11:58:03 +00006811 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006812 }
6813 return this;
6814 }
6815 int min = NewElementsCapacity(old_capacity);
6816 int new_capacity = value > min ? value : min;
6817 if (new_capacity <= kMaxFastElementsLength ||
6818 !ShouldConvertToSlowElements(new_capacity)) {
John Reck59135872010-11-02 12:39:01 -07006819 Object* obj;
6820 { MaybeObject* maybe_obj =
6821 SetFastElementsCapacityAndLength(new_capacity, value);
6822 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6823 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006824 return this;
6825 }
6826 break;
6827 }
6828 case DICTIONARY_ELEMENTS: {
6829 if (IsJSArray()) {
6830 if (value == 0) {
6831 // If the length of a slow array is reset to zero, we clear
6832 // the array and flush backing storage. This has the added
6833 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07006834 Object* obj;
6835 { MaybeObject* maybe_obj = ResetElements();
6836 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6837 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006838 } else {
6839 // Remove deleted elements.
6840 uint32_t old_length =
6841 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
6842 element_dictionary()->RemoveNumberEntries(value, old_length);
6843 }
Leon Clarke4515c472010-02-03 11:58:03 +00006844 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006845 }
6846 return this;
6847 }
6848 default:
6849 UNREACHABLE();
6850 break;
6851 }
6852 }
6853
6854 // General slow case.
6855 if (len->IsNumber()) {
6856 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006857 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006858 return SetSlowElements(len);
6859 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006860 return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00006861 }
6862 }
6863
6864 // len is not a number so make the array size one and
6865 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07006866 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01006867 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07006868 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6869 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006870 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00006871 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006872 set_elements(FixedArray::cast(obj));
6873 return this;
6874}
6875
6876
John Reck59135872010-11-02 12:39:01 -07006877MaybeObject* JSObject::SetPrototype(Object* value,
6878 bool skip_hidden_prototypes) {
Steve Block44f0eee2011-05-26 01:26:41 +01006879 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00006880 // Silently ignore the change if value is not a JSObject or null.
6881 // SpiderMonkey behaves this way.
6882 if (!value->IsJSObject() && !value->IsNull()) return value;
6883
Ben Murdoch8b112d22011-06-08 16:22:53 +01006884 // From 8.6.2 Object Internal Methods
6885 // ...
6886 // In addition, if [[Extensible]] is false the value of the [[Class]] and
6887 // [[Prototype]] internal properties of the object may not be modified.
6888 // ...
6889 // Implementation specific extensions that modify [[Class]], [[Prototype]]
6890 // or [[Extensible]] must not violate the invariants defined in the preceding
6891 // paragraph.
6892 if (!this->map()->is_extensible()) {
6893 HandleScope scope;
6894 Handle<Object> handle(this, heap->isolate());
6895 return heap->isolate()->Throw(
6896 *FACTORY->NewTypeError("non_extensible_proto",
6897 HandleVector<Object>(&handle, 1)));
6898 }
6899
Andrei Popescu402d9372010-02-26 13:31:12 +00006900 // Before we can set the prototype we need to be sure
6901 // prototype cycles are prevented.
6902 // It is sufficient to validate that the receiver is not in the new prototype
6903 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01006904 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006905 if (JSObject::cast(pt) == this) {
6906 // Cycle detected.
6907 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006908 return heap->isolate()->Throw(
6909 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00006910 }
6911 }
6912
6913 JSObject* real_receiver = this;
6914
6915 if (skip_hidden_prototypes) {
6916 // Find the first object in the chain whose prototype object is not
6917 // hidden and set the new prototype on that object.
6918 Object* current_proto = real_receiver->GetPrototype();
6919 while (current_proto->IsJSObject() &&
6920 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
6921 real_receiver = JSObject::cast(current_proto);
6922 current_proto = current_proto->GetPrototype();
6923 }
6924 }
6925
6926 // Set the new prototype of the object.
John Reck59135872010-11-02 12:39:01 -07006927 Object* new_map;
6928 { MaybeObject* maybe_new_map = real_receiver->map()->CopyDropTransitions();
6929 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
6930 }
Andrei Popescu402d9372010-02-26 13:31:12 +00006931 Map::cast(new_map)->set_prototype(value);
6932 real_receiver->set_map(Map::cast(new_map));
6933
Steve Block44f0eee2011-05-26 01:26:41 +01006934 heap->ClearInstanceofCache();
Kristian Monsen25f61362010-05-21 11:50:48 +01006935
Andrei Popescu402d9372010-02-26 13:31:12 +00006936 return value;
6937}
6938
6939
Steve Blocka7e24c12009-10-30 11:49:00 +00006940bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
6941 switch (GetElementsKind()) {
6942 case FAST_ELEMENTS: {
6943 uint32_t length = IsJSArray() ?
6944 static_cast<uint32_t>
6945 (Smi::cast(JSArray::cast(this)->length())->value()) :
6946 static_cast<uint32_t>(FixedArray::cast(elements())->length());
6947 if ((index < length) &&
6948 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
6949 return true;
6950 }
6951 break;
6952 }
Steve Block44f0eee2011-05-26 01:26:41 +01006953 case EXTERNAL_PIXEL_ELEMENTS: {
6954 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00006955 if (index < static_cast<uint32_t>(pixels->length())) {
6956 return true;
6957 }
6958 break;
6959 }
Steve Block3ce2e202009-11-05 08:53:23 +00006960 case EXTERNAL_BYTE_ELEMENTS:
6961 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6962 case EXTERNAL_SHORT_ELEMENTS:
6963 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6964 case EXTERNAL_INT_ELEMENTS:
6965 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6966 case EXTERNAL_FLOAT_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00006967 ExternalArray* array = ExternalArray::cast(elements());
6968 if (index < static_cast<uint32_t>(array->length())) {
6969 return true;
6970 }
6971 break;
6972 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006973 case DICTIONARY_ELEMENTS: {
6974 if (element_dictionary()->FindEntry(index)
6975 != NumberDictionary::kNotFound) {
6976 return true;
6977 }
6978 break;
6979 }
6980 default:
6981 UNREACHABLE();
6982 break;
6983 }
6984
6985 // Handle [] on String objects.
6986 if (this->IsStringObjectWithCharacterAt(index)) return true;
6987
6988 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01006989 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00006990 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
6991}
6992
6993
6994bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01006995 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006996 // Make sure that the top context does not change when doing
6997 // callbacks or interceptor calls.
6998 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01006999 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007000 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7001 Handle<JSObject> receiver_handle(receiver);
7002 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007003 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007004 v8::AccessorInfo info(args.end());
7005 if (!interceptor->query()->IsUndefined()) {
7006 v8::IndexedPropertyQuery query =
7007 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007008 LOG(isolate,
7009 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007010 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007011 {
7012 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007013 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007014 result = query(index, info);
7015 }
Iain Merrick75681382010-08-19 15:07:18 +01007016 if (!result.IsEmpty()) {
7017 ASSERT(result->IsInt32());
7018 return true; // absence of property is signaled by empty handle.
7019 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007020 } else if (!interceptor->getter()->IsUndefined()) {
7021 v8::IndexedPropertyGetter getter =
7022 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007023 LOG(isolate,
7024 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007025 v8::Handle<v8::Value> result;
7026 {
7027 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007028 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007029 result = getter(index, info);
7030 }
7031 if (!result.IsEmpty()) return true;
7032 }
7033 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7034}
7035
7036
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007037JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007038 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007039 if (IsAccessCheckNeeded()) {
7040 Heap* heap = GetHeap();
7041 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7042 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7043 return UNDEFINED_ELEMENT;
7044 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007045 }
7046
Steve Block1e0659c2011-05-24 12:43:12 +01007047 if (IsJSGlobalProxy()) {
7048 Object* proto = GetPrototype();
7049 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7050 ASSERT(proto->IsJSGlobalObject());
7051 return JSObject::cast(proto)->HasLocalElement(index);
7052 }
7053
Steve Blocka7e24c12009-10-30 11:49:00 +00007054 // Check for lookup interceptor
7055 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007056 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7057 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007058 }
7059
7060 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007061 if (this->IsStringObjectWithCharacterAt(index)) {
7062 return STRING_CHARACTER_ELEMENT;
7063 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007064
7065 switch (GetElementsKind()) {
7066 case FAST_ELEMENTS: {
7067 uint32_t length = IsJSArray() ?
7068 static_cast<uint32_t>
7069 (Smi::cast(JSArray::cast(this)->length())->value()) :
7070 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007071 if ((index < length) &&
7072 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7073 return FAST_ELEMENT;
7074 }
7075 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007076 }
Steve Block44f0eee2011-05-26 01:26:41 +01007077 case EXTERNAL_PIXEL_ELEMENTS: {
7078 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007079 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7080 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007081 }
Steve Block3ce2e202009-11-05 08:53:23 +00007082 case EXTERNAL_BYTE_ELEMENTS:
7083 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7084 case EXTERNAL_SHORT_ELEMENTS:
7085 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7086 case EXTERNAL_INT_ELEMENTS:
7087 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7088 case EXTERNAL_FLOAT_ELEMENTS: {
7089 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007090 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7091 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007092 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007093 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007094 if (element_dictionary()->FindEntry(index) !=
7095 NumberDictionary::kNotFound) {
7096 return DICTIONARY_ELEMENT;
7097 }
7098 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007099 }
7100 default:
7101 UNREACHABLE();
7102 break;
7103 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007104
7105 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007106}
7107
7108
7109bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
7110 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007111 if (IsAccessCheckNeeded()) {
7112 Heap* heap = GetHeap();
7113 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7114 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7115 return false;
7116 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007117 }
7118
7119 // Check for lookup interceptor
7120 if (HasIndexedInterceptor()) {
7121 return HasElementWithInterceptor(receiver, index);
7122 }
7123
7124 switch (GetElementsKind()) {
7125 case FAST_ELEMENTS: {
7126 uint32_t length = IsJSArray() ?
7127 static_cast<uint32_t>
7128 (Smi::cast(JSArray::cast(this)->length())->value()) :
7129 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7130 if ((index < length) &&
7131 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
7132 break;
7133 }
Steve Block44f0eee2011-05-26 01:26:41 +01007134 case EXTERNAL_PIXEL_ELEMENTS: {
7135 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007136 if (index < static_cast<uint32_t>(pixels->length())) {
7137 return true;
7138 }
7139 break;
7140 }
Steve Block3ce2e202009-11-05 08:53:23 +00007141 case EXTERNAL_BYTE_ELEMENTS:
7142 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7143 case EXTERNAL_SHORT_ELEMENTS:
7144 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7145 case EXTERNAL_INT_ELEMENTS:
7146 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7147 case EXTERNAL_FLOAT_ELEMENTS: {
7148 ExternalArray* array = ExternalArray::cast(elements());
7149 if (index < static_cast<uint32_t>(array->length())) {
7150 return true;
7151 }
7152 break;
7153 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007154 case DICTIONARY_ELEMENTS: {
7155 if (element_dictionary()->FindEntry(index)
7156 != NumberDictionary::kNotFound) {
7157 return true;
7158 }
7159 break;
7160 }
7161 default:
7162 UNREACHABLE();
7163 break;
7164 }
7165
7166 // Handle [] on String objects.
7167 if (this->IsStringObjectWithCharacterAt(index)) return true;
7168
7169 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007170 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007171 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7172}
7173
7174
John Reck59135872010-11-02 12:39:01 -07007175MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007176 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007177 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007178 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007179 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007180 // Make sure that the top context does not change when doing
7181 // callbacks or interceptor calls.
7182 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007183 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007184 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7185 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007186 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007187 if (!interceptor->setter()->IsUndefined()) {
7188 v8::IndexedPropertySetter setter =
7189 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01007190 LOG(isolate,
7191 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
7192 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007193 v8::AccessorInfo info(args.end());
7194 v8::Handle<v8::Value> result;
7195 {
7196 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007197 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007198 result = setter(index, v8::Utils::ToLocal(value_handle), info);
7199 }
Steve Block44f0eee2011-05-26 01:26:41 +01007200 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007201 if (!result.IsEmpty()) return *value_handle;
7202 }
John Reck59135872010-11-02 12:39:01 -07007203 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01007204 this_handle->SetElementWithoutInterceptor(index,
7205 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007206 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007207 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007208 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007209 return raw_result;
7210}
7211
7212
John Reck59135872010-11-02 12:39:01 -07007213MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
7214 Object* structure,
7215 uint32_t index,
7216 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007217 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01007218 ASSERT(!structure->IsProxy());
7219
7220 // api style callbacks.
7221 if (structure->IsAccessorInfo()) {
7222 AccessorInfo* data = AccessorInfo::cast(structure);
7223 Object* fun_obj = data->getter();
7224 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007225 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007226 Handle<JSObject> self(JSObject::cast(receiver));
7227 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01007228 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7229 Handle<String> key(isolate->factory()->NumberToString(number));
7230 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
7231 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01007232 v8::AccessorInfo info(args.end());
7233 v8::Handle<v8::Value> result;
7234 {
7235 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007236 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007237 result = call_fun(v8::Utils::ToLocal(key), info);
7238 }
Steve Block44f0eee2011-05-26 01:26:41 +01007239 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
7240 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007241 return *v8::Utils::OpenHandle(*result);
7242 }
7243
7244 // __defineGetter__ callback
7245 if (structure->IsFixedArray()) {
7246 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
7247 if (getter->IsJSFunction()) {
7248 return Object::GetPropertyWithDefinedGetter(receiver,
7249 JSFunction::cast(getter));
7250 }
7251 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01007252 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007253 }
7254
7255 UNREACHABLE();
7256 return NULL;
7257}
7258
7259
John Reck59135872010-11-02 12:39:01 -07007260MaybeObject* JSObject::SetElementWithCallback(Object* structure,
7261 uint32_t index,
7262 Object* value,
7263 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007264 Isolate* isolate = GetIsolate();
7265 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007266
7267 // We should never get here to initialize a const with the hole
7268 // value since a const declaration would conflict with the setter.
7269 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01007270 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007271
7272 // To accommodate both the old and the new api we switch on the
7273 // data structure used to store the callbacks. Eventually proxy
7274 // callbacks should be phased out.
7275 ASSERT(!structure->IsProxy());
7276
7277 if (structure->IsAccessorInfo()) {
7278 // api style callbacks
7279 AccessorInfo* data = AccessorInfo::cast(structure);
7280 Object* call_obj = data->setter();
7281 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
7282 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01007283 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7284 Handle<String> key(isolate->factory()->NumberToString(number));
7285 LOG(isolate, ApiNamedPropertyAccess("store", this, *key));
7286 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Leon Clarkef7060e22010-06-03 12:02:55 +01007287 v8::AccessorInfo info(args.end());
7288 {
7289 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007290 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007291 call_fun(v8::Utils::ToLocal(key),
7292 v8::Utils::ToLocal(value_handle),
7293 info);
7294 }
Steve Block44f0eee2011-05-26 01:26:41 +01007295 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007296 return *value_handle;
7297 }
7298
7299 if (structure->IsFixedArray()) {
7300 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
7301 if (setter->IsJSFunction()) {
7302 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
7303 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007304 Handle<Object> holder_handle(holder, isolate);
7305 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01007306 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01007307 return isolate->Throw(
7308 *isolate->factory()->NewTypeError("no_setter_in_callback",
7309 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01007310 }
7311 }
7312
7313 UNREACHABLE();
7314 return NULL;
7315}
7316
7317
Steve Blocka7e24c12009-10-30 11:49:00 +00007318// Adding n elements in fast case is O(n*n).
7319// Note: revisit design to have dual undefined values to capture absent
7320// elements.
Steve Block9fac8402011-05-12 15:51:54 +01007321MaybeObject* JSObject::SetFastElement(uint32_t index,
7322 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007323 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007324 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007325 ASSERT(HasFastElements());
7326
John Reck59135872010-11-02 12:39:01 -07007327 Object* elms_obj;
7328 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements();
7329 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
7330 }
Iain Merrick75681382010-08-19 15:07:18 +01007331 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007332 uint32_t elms_length = static_cast<uint32_t>(elms->length());
7333
Steve Block9fac8402011-05-12 15:51:54 +01007334 if (check_prototype &&
Steve Block1e0659c2011-05-24 12:43:12 +01007335 (index >= elms_length || elms->get(index)->IsTheHole())) {
7336 bool found;
7337 MaybeObject* result =
7338 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7339 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007340 }
7341
Steve Block9fac8402011-05-12 15:51:54 +01007342
Steve Blocka7e24c12009-10-30 11:49:00 +00007343 // Check whether there is extra space in fixed array..
7344 if (index < elms_length) {
7345 elms->set(index, value);
7346 if (IsJSArray()) {
7347 // Update the length of the array if needed.
7348 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007349 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007350 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00007351 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007352 }
7353 }
7354 return value;
7355 }
7356
7357 // Allow gap in fast case.
7358 if ((index - elms_length) < kMaxGap) {
7359 // Try allocating extra space.
7360 int new_capacity = NewElementsCapacity(index+1);
7361 if (new_capacity <= kMaxFastElementsLength ||
7362 !ShouldConvertToSlowElements(new_capacity)) {
7363 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07007364 Object* obj;
7365 { MaybeObject* maybe_obj =
7366 SetFastElementsCapacityAndLength(new_capacity, index + 1);
7367 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7368 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007369 FixedArray::cast(elements())->set(index, value);
7370 return value;
7371 }
7372 }
7373
7374 // Otherwise default to slow case.
John Reck59135872010-11-02 12:39:01 -07007375 Object* obj;
7376 { MaybeObject* maybe_obj = NormalizeElements();
7377 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7378 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007379 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007380 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007381}
7382
Iain Merrick75681382010-08-19 15:07:18 +01007383
Steve Block9fac8402011-05-12 15:51:54 +01007384MaybeObject* JSObject::SetElement(uint32_t index,
7385 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007386 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007387 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007388 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007389 if (IsAccessCheckNeeded()) {
7390 Heap* heap = GetHeap();
7391 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
7392 HandleScope scope;
7393 Handle<Object> value_handle(value);
7394 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
7395 return *value_handle;
7396 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007397 }
7398
7399 if (IsJSGlobalProxy()) {
7400 Object* proto = GetPrototype();
7401 if (proto->IsNull()) return value;
7402 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007403 return JSObject::cast(proto)->SetElement(index,
7404 value,
7405 strict_mode,
7406 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007407 }
7408
7409 // Check for lookup interceptor
7410 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007411 return SetElementWithInterceptor(index,
7412 value,
7413 strict_mode,
7414 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007415 }
7416
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007417 return SetElementWithoutInterceptor(index,
7418 value,
7419 strict_mode,
7420 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007421}
7422
7423
John Reck59135872010-11-02 12:39:01 -07007424MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007425 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007426 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007427 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007428 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007429 switch (GetElementsKind()) {
7430 case FAST_ELEMENTS:
7431 // Fast case.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007432 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007433 case EXTERNAL_PIXEL_ELEMENTS: {
7434 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007435 return pixels->SetValue(index, value);
7436 }
Steve Block3ce2e202009-11-05 08:53:23 +00007437 case EXTERNAL_BYTE_ELEMENTS: {
7438 ExternalByteArray* array = ExternalByteArray::cast(elements());
7439 return array->SetValue(index, value);
7440 }
7441 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7442 ExternalUnsignedByteArray* array =
7443 ExternalUnsignedByteArray::cast(elements());
7444 return array->SetValue(index, value);
7445 }
7446 case EXTERNAL_SHORT_ELEMENTS: {
7447 ExternalShortArray* array = ExternalShortArray::cast(elements());
7448 return array->SetValue(index, value);
7449 }
7450 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7451 ExternalUnsignedShortArray* array =
7452 ExternalUnsignedShortArray::cast(elements());
7453 return array->SetValue(index, value);
7454 }
7455 case EXTERNAL_INT_ELEMENTS: {
7456 ExternalIntArray* array = ExternalIntArray::cast(elements());
7457 return array->SetValue(index, value);
7458 }
7459 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7460 ExternalUnsignedIntArray* array =
7461 ExternalUnsignedIntArray::cast(elements());
7462 return array->SetValue(index, value);
7463 }
7464 case EXTERNAL_FLOAT_ELEMENTS: {
7465 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7466 return array->SetValue(index, value);
7467 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007468 case DICTIONARY_ELEMENTS: {
7469 // Insert element in the dictionary.
7470 FixedArray* elms = FixedArray::cast(elements());
7471 NumberDictionary* dictionary = NumberDictionary::cast(elms);
7472
7473 int entry = dictionary->FindEntry(index);
7474 if (entry != NumberDictionary::kNotFound) {
7475 Object* element = dictionary->ValueAt(entry);
7476 PropertyDetails details = dictionary->DetailsAt(entry);
7477 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007478 return SetElementWithCallback(element, index, value, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007479 } else {
7480 dictionary->UpdateMaxNumberKey(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007481 // If put fails instrict mode, throw exception.
7482 if (!dictionary->ValueAtPut(entry, value) &&
7483 strict_mode == kStrictMode) {
Steve Block44f0eee2011-05-26 01:26:41 +01007484 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007485 Handle<Object> holder(this);
7486 Handle<Object> args[2] = { number, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01007487 return isolate->Throw(
7488 *isolate->factory()->NewTypeError("strict_read_only_property",
7489 HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007490 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007491 }
7492 } else {
7493 // Index not already used. Look for an accessor in the prototype chain.
Steve Block1e0659c2011-05-24 12:43:12 +01007494 if (check_prototype) {
7495 bool found;
7496 MaybeObject* result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007497 // Strict mode not needed. No-setter case already handled.
Steve Block1e0659c2011-05-24 12:43:12 +01007498 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7499 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007500 }
Steve Block8defd9f2010-07-08 12:39:36 +01007501 // When we set the is_extensible flag to false we always force
7502 // the element into dictionary mode (and force them to stay there).
7503 if (!map()->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007504 if (strict_mode == kNonStrictMode) {
7505 return isolate->heap()->undefined_value();
7506 } else {
7507 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
7508 Handle<String> index_string(
7509 isolate->factory()->NumberToString(number));
7510 Handle<Object> args[1] = { index_string };
7511 return isolate->Throw(
7512 *isolate->factory()->NewTypeError("object_not_extensible",
7513 HandleVector(args, 1)));
7514 }
Steve Block8defd9f2010-07-08 12:39:36 +01007515 }
John Reck59135872010-11-02 12:39:01 -07007516 Object* result;
7517 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
7518 if (!maybe_result->ToObject(&result)) return maybe_result;
7519 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007520 if (elms != FixedArray::cast(result)) {
7521 set_elements(FixedArray::cast(result));
7522 }
7523 }
7524
7525 // Update the array length if this JSObject is an array.
7526 if (IsJSArray()) {
7527 JSArray* array = JSArray::cast(this);
John Reck59135872010-11-02 12:39:01 -07007528 Object* return_value;
7529 { MaybeObject* maybe_return_value =
7530 array->JSArrayUpdateLengthFromIndex(index, value);
7531 if (!maybe_return_value->ToObject(&return_value)) {
7532 return maybe_return_value;
7533 }
7534 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007535 }
7536
7537 // Attempt to put this object back in fast case.
7538 if (ShouldConvertToFastElements()) {
7539 uint32_t new_length = 0;
7540 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007541 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007542 } else {
7543 new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
7544 }
John Reck59135872010-11-02 12:39:01 -07007545 Object* obj;
7546 { MaybeObject* maybe_obj =
7547 SetFastElementsCapacityAndLength(new_length, new_length);
7548 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7549 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007550#ifdef DEBUG
7551 if (FLAG_trace_normalization) {
7552 PrintF("Object elements are fast case again:\n");
7553 Print();
7554 }
7555#endif
7556 }
7557
7558 return value;
7559 }
7560 default:
7561 UNREACHABLE();
7562 break;
7563 }
7564 // All possible cases have been handled above. Add a return to avoid the
7565 // complaints from the compiler.
7566 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01007567 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007568}
7569
7570
John Reck59135872010-11-02 12:39:01 -07007571MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
7572 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007573 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007574 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00007575 // Check to see if we need to update the length. For now, we make
7576 // sure that the length stays within 32-bits (unsigned).
7577 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07007578 Object* len;
7579 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01007580 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07007581 if (!maybe_len->ToObject(&len)) return maybe_len;
7582 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007583 set_length(len);
7584 }
7585 return value;
7586}
7587
7588
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007589MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007590 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007591 // Get element works for both JSObject and JSArray since
7592 // JSArray::length cannot change.
7593 switch (GetElementsKind()) {
7594 case FAST_ELEMENTS: {
7595 FixedArray* elms = FixedArray::cast(elements());
7596 if (index < static_cast<uint32_t>(elms->length())) {
7597 Object* value = elms->get(index);
7598 if (!value->IsTheHole()) return value;
7599 }
7600 break;
7601 }
Steve Block44f0eee2011-05-26 01:26:41 +01007602 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007603 case EXTERNAL_BYTE_ELEMENTS:
7604 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7605 case EXTERNAL_SHORT_ELEMENTS:
7606 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7607 case EXTERNAL_INT_ELEMENTS:
7608 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7609 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007610 MaybeObject* maybe_value = GetExternalElement(index);
7611 Object* value;
7612 if (!maybe_value->ToObject(&value)) return maybe_value;
7613 if (!value->IsUndefined()) return value;
Steve Block3ce2e202009-11-05 08:53:23 +00007614 break;
7615 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007616 case DICTIONARY_ELEMENTS: {
7617 NumberDictionary* dictionary = element_dictionary();
7618 int entry = dictionary->FindEntry(index);
7619 if (entry != NumberDictionary::kNotFound) {
7620 Object* element = dictionary->ValueAt(entry);
7621 PropertyDetails details = dictionary->DetailsAt(entry);
7622 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007623 return GetElementWithCallback(receiver,
7624 element,
7625 index,
7626 this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007627 }
7628 return element;
7629 }
7630 break;
7631 }
7632 default:
7633 UNREACHABLE();
7634 break;
7635 }
7636
7637 // Continue searching via the prototype chain.
7638 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007639 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007640 return pt->GetElementWithReceiver(receiver, index);
7641}
7642
7643
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007644MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007645 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007646 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007647 // Make sure that the top context does not change when doing
7648 // callbacks or interceptor calls.
7649 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007650 HandleScope scope(isolate);
7651 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
7652 Handle<Object> this_handle(receiver, isolate);
7653 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007654 if (!interceptor->getter()->IsUndefined()) {
7655 v8::IndexedPropertyGetter getter =
7656 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007657 LOG(isolate,
7658 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
7659 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007660 v8::AccessorInfo info(args.end());
7661 v8::Handle<v8::Value> result;
7662 {
7663 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007664 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007665 result = getter(index, info);
7666 }
Steve Block44f0eee2011-05-26 01:26:41 +01007667 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007668 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
7669 }
7670
John Reck59135872010-11-02 12:39:01 -07007671 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00007672 holder_handle->GetElementPostInterceptor(*this_handle, index);
Steve Block44f0eee2011-05-26 01:26:41 +01007673 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007674 return raw_result;
7675}
7676
7677
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007678MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007679 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007680 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007681 if (IsAccessCheckNeeded()) {
7682 Heap* heap = GetHeap();
7683 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
7684 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
7685 return heap->undefined_value();
7686 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007687 }
7688
7689 if (HasIndexedInterceptor()) {
7690 return GetElementWithInterceptor(receiver, index);
7691 }
7692
7693 // Get element works for both JSObject and JSArray since
7694 // JSArray::length cannot change.
7695 switch (GetElementsKind()) {
7696 case FAST_ELEMENTS: {
7697 FixedArray* elms = FixedArray::cast(elements());
7698 if (index < static_cast<uint32_t>(elms->length())) {
7699 Object* value = elms->get(index);
7700 if (!value->IsTheHole()) return value;
7701 }
7702 break;
7703 }
Steve Block44f0eee2011-05-26 01:26:41 +01007704 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007705 case EXTERNAL_BYTE_ELEMENTS:
7706 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7707 case EXTERNAL_SHORT_ELEMENTS:
7708 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7709 case EXTERNAL_INT_ELEMENTS:
7710 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7711 case EXTERNAL_FLOAT_ELEMENTS: {
7712 MaybeObject* maybe_value = GetExternalElement(index);
7713 Object* value;
7714 if (!maybe_value->ToObject(&value)) return maybe_value;
7715 if (!value->IsUndefined()) return value;
7716 break;
7717 }
7718 case DICTIONARY_ELEMENTS: {
7719 NumberDictionary* dictionary = element_dictionary();
7720 int entry = dictionary->FindEntry(index);
7721 if (entry != NumberDictionary::kNotFound) {
7722 Object* element = dictionary->ValueAt(entry);
7723 PropertyDetails details = dictionary->DetailsAt(entry);
7724 if (details.type() == CALLBACKS) {
7725 return GetElementWithCallback(receiver,
7726 element,
7727 index,
7728 this);
7729 }
7730 return element;
7731 }
7732 break;
7733 }
7734 }
7735
7736 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007737 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007738 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007739 return pt->GetElementWithReceiver(receiver, index);
7740}
7741
7742
7743MaybeObject* JSObject::GetExternalElement(uint32_t index) {
7744 // Get element works for both JSObject and JSArray since
7745 // JSArray::length cannot change.
7746 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007747 case EXTERNAL_PIXEL_ELEMENTS: {
7748 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007749 if (index < static_cast<uint32_t>(pixels->length())) {
7750 uint8_t value = pixels->get(index);
7751 return Smi::FromInt(value);
7752 }
7753 break;
7754 }
Steve Block3ce2e202009-11-05 08:53:23 +00007755 case EXTERNAL_BYTE_ELEMENTS: {
7756 ExternalByteArray* array = ExternalByteArray::cast(elements());
7757 if (index < static_cast<uint32_t>(array->length())) {
7758 int8_t value = array->get(index);
7759 return Smi::FromInt(value);
7760 }
7761 break;
7762 }
7763 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7764 ExternalUnsignedByteArray* array =
7765 ExternalUnsignedByteArray::cast(elements());
7766 if (index < static_cast<uint32_t>(array->length())) {
7767 uint8_t value = array->get(index);
7768 return Smi::FromInt(value);
7769 }
7770 break;
7771 }
7772 case EXTERNAL_SHORT_ELEMENTS: {
7773 ExternalShortArray* array = ExternalShortArray::cast(elements());
7774 if (index < static_cast<uint32_t>(array->length())) {
7775 int16_t value = array->get(index);
7776 return Smi::FromInt(value);
7777 }
7778 break;
7779 }
7780 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7781 ExternalUnsignedShortArray* array =
7782 ExternalUnsignedShortArray::cast(elements());
7783 if (index < static_cast<uint32_t>(array->length())) {
7784 uint16_t value = array->get(index);
7785 return Smi::FromInt(value);
7786 }
7787 break;
7788 }
7789 case EXTERNAL_INT_ELEMENTS: {
7790 ExternalIntArray* array = ExternalIntArray::cast(elements());
7791 if (index < static_cast<uint32_t>(array->length())) {
7792 int32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007793 return GetHeap()->NumberFromInt32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007794 }
7795 break;
7796 }
7797 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7798 ExternalUnsignedIntArray* array =
7799 ExternalUnsignedIntArray::cast(elements());
7800 if (index < static_cast<uint32_t>(array->length())) {
7801 uint32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007802 return GetHeap()->NumberFromUint32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007803 }
7804 break;
7805 }
7806 case EXTERNAL_FLOAT_ELEMENTS: {
7807 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7808 if (index < static_cast<uint32_t>(array->length())) {
7809 float value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007810 return GetHeap()->AllocateHeapNumber(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007811 }
7812 break;
7813 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007814 case FAST_ELEMENTS:
7815 case DICTIONARY_ELEMENTS:
7816 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00007817 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007818 }
Steve Block44f0eee2011-05-26 01:26:41 +01007819 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007820}
7821
7822
7823bool JSObject::HasDenseElements() {
7824 int capacity = 0;
7825 int number_of_elements = 0;
7826
7827 switch (GetElementsKind()) {
7828 case FAST_ELEMENTS: {
7829 FixedArray* elms = FixedArray::cast(elements());
7830 capacity = elms->length();
7831 for (int i = 0; i < capacity; i++) {
7832 if (!elms->get(i)->IsTheHole()) number_of_elements++;
7833 }
7834 break;
7835 }
Steve Block44f0eee2011-05-26 01:26:41 +01007836 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007837 case EXTERNAL_BYTE_ELEMENTS:
7838 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7839 case EXTERNAL_SHORT_ELEMENTS:
7840 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7841 case EXTERNAL_INT_ELEMENTS:
7842 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7843 case EXTERNAL_FLOAT_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +00007844 return true;
7845 }
7846 case DICTIONARY_ELEMENTS: {
7847 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7848 capacity = dictionary->Capacity();
7849 number_of_elements = dictionary->NumberOfElements();
7850 break;
7851 }
7852 default:
7853 UNREACHABLE();
7854 break;
7855 }
7856
7857 if (capacity == 0) return true;
7858 return (number_of_elements > (capacity / 2));
7859}
7860
7861
7862bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
7863 ASSERT(HasFastElements());
7864 // Keep the array in fast case if the current backing storage is
7865 // almost filled and if the new capacity is no more than twice the
7866 // old capacity.
7867 int elements_length = FixedArray::cast(elements())->length();
7868 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
7869}
7870
7871
7872bool JSObject::ShouldConvertToFastElements() {
7873 ASSERT(HasDictionaryElements());
7874 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7875 // If the elements are sparse, we should not go back to fast case.
7876 if (!HasDenseElements()) return false;
7877 // If an element has been added at a very high index in the elements
7878 // dictionary, we cannot go back to fast case.
7879 if (dictionary->requires_slow_elements()) return false;
7880 // An object requiring access checks is never allowed to have fast
7881 // elements. If it had fast elements we would skip security checks.
7882 if (IsAccessCheckNeeded()) return false;
7883 // If the dictionary backing storage takes up roughly half as much
7884 // space as a fast-case backing storage would the array should have
7885 // fast elements.
7886 uint32_t length = 0;
7887 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007888 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007889 } else {
7890 length = dictionary->max_number_key();
7891 }
7892 return static_cast<uint32_t>(dictionary->Capacity()) >=
7893 (length / (2 * NumberDictionary::kEntrySize));
7894}
7895
7896
7897// Certain compilers request function template instantiation when they
7898// see the definition of the other template functions in the
7899// class. This requires us to have the template functions put
7900// together, so even though this function belongs in objects-debug.cc,
7901// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007902#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00007903template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01007904void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007905 int capacity = HashTable<Shape, Key>::Capacity();
7906 for (int i = 0; i < capacity; i++) {
7907 Object* k = HashTable<Shape, Key>::KeyAt(i);
7908 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007909 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00007910 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007911 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00007912 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007913 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00007914 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007915 PrintF(out, ": ");
7916 ValueAt(i)->ShortPrint(out);
7917 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007918 }
7919 }
7920}
7921#endif
7922
7923
7924template<typename Shape, typename Key>
7925void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
7926 int pos = 0;
7927 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00007928 AssertNoAllocation no_gc;
7929 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00007930 for (int i = 0; i < capacity; i++) {
7931 Object* k = Dictionary<Shape, Key>::KeyAt(i);
7932 if (Dictionary<Shape, Key>::IsKey(k)) {
7933 elements->set(pos++, ValueAt(i), mode);
7934 }
7935 }
7936 ASSERT(pos == elements->length());
7937}
7938
7939
7940InterceptorInfo* JSObject::GetNamedInterceptor() {
7941 ASSERT(map()->has_named_interceptor());
7942 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01007943 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00007944 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01007945 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00007946 return InterceptorInfo::cast(result);
7947}
7948
7949
7950InterceptorInfo* JSObject::GetIndexedInterceptor() {
7951 ASSERT(map()->has_indexed_interceptor());
7952 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01007953 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00007954 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01007955 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00007956 return InterceptorInfo::cast(result);
7957}
7958
7959
John Reck59135872010-11-02 12:39:01 -07007960MaybeObject* JSObject::GetPropertyPostInterceptor(
7961 JSObject* receiver,
7962 String* name,
7963 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007964 // Check local property in holder, ignore interceptor.
7965 LookupResult result;
7966 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00007967 if (result.IsProperty()) {
7968 return GetProperty(receiver, &result, name, attributes);
7969 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007970 // Continue searching via the prototype chain.
7971 Object* pt = GetPrototype();
7972 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007973 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007974 return pt->GetPropertyWithReceiver(receiver, name, attributes);
7975}
7976
7977
John Reck59135872010-11-02 12:39:01 -07007978MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Steve Blockd0582a62009-12-15 09:54:21 +00007979 JSObject* receiver,
7980 String* name,
7981 PropertyAttributes* attributes) {
7982 // Check local property in holder, ignore interceptor.
7983 LookupResult result;
7984 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00007985 if (result.IsProperty()) {
7986 return GetProperty(receiver, &result, name, attributes);
7987 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01007988 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00007989}
7990
7991
John Reck59135872010-11-02 12:39:01 -07007992MaybeObject* JSObject::GetPropertyWithInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00007993 JSObject* receiver,
7994 String* name,
7995 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01007996 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007997 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01007998 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007999 Handle<JSObject> receiver_handle(receiver);
8000 Handle<JSObject> holder_handle(this);
8001 Handle<String> name_handle(name);
8002
8003 if (!interceptor->getter()->IsUndefined()) {
8004 v8::NamedPropertyGetter getter =
8005 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008006 LOG(isolate,
8007 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8008 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008009 v8::AccessorInfo info(args.end());
8010 v8::Handle<v8::Value> result;
8011 {
8012 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008013 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008014 result = getter(v8::Utils::ToLocal(name_handle), info);
8015 }
Steve Block44f0eee2011-05-26 01:26:41 +01008016 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008017 if (!result.IsEmpty()) {
8018 *attributes = NONE;
8019 return *v8::Utils::OpenHandle(*result);
8020 }
8021 }
8022
John Reck59135872010-11-02 12:39:01 -07008023 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00008024 *receiver_handle,
8025 *name_handle,
8026 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01008027 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008028 return result;
8029}
8030
8031
8032bool JSObject::HasRealNamedProperty(String* key) {
8033 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008034 if (IsAccessCheckNeeded()) {
8035 Heap* heap = GetHeap();
8036 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8037 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8038 return false;
8039 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008040 }
8041
8042 LookupResult result;
8043 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008044 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00008045}
8046
8047
8048bool JSObject::HasRealElementProperty(uint32_t index) {
8049 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008050 if (IsAccessCheckNeeded()) {
8051 Heap* heap = GetHeap();
8052 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8053 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8054 return false;
8055 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008056 }
8057
8058 // Handle [] on String objects.
8059 if (this->IsStringObjectWithCharacterAt(index)) return true;
8060
8061 switch (GetElementsKind()) {
8062 case FAST_ELEMENTS: {
8063 uint32_t length = IsJSArray() ?
8064 static_cast<uint32_t>(
8065 Smi::cast(JSArray::cast(this)->length())->value()) :
8066 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8067 return (index < length) &&
8068 !FixedArray::cast(elements())->get(index)->IsTheHole();
8069 }
Steve Block44f0eee2011-05-26 01:26:41 +01008070 case EXTERNAL_PIXEL_ELEMENTS: {
8071 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008072 return index < static_cast<uint32_t>(pixels->length());
8073 }
Steve Block3ce2e202009-11-05 08:53:23 +00008074 case EXTERNAL_BYTE_ELEMENTS:
8075 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8076 case EXTERNAL_SHORT_ELEMENTS:
8077 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8078 case EXTERNAL_INT_ELEMENTS:
8079 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8080 case EXTERNAL_FLOAT_ELEMENTS: {
8081 ExternalArray* array = ExternalArray::cast(elements());
8082 return index < static_cast<uint32_t>(array->length());
8083 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008084 case DICTIONARY_ELEMENTS: {
8085 return element_dictionary()->FindEntry(index)
8086 != NumberDictionary::kNotFound;
8087 }
8088 default:
8089 UNREACHABLE();
8090 break;
8091 }
8092 // All possibilities have been handled above already.
8093 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008094 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008095}
8096
8097
8098bool JSObject::HasRealNamedCallbackProperty(String* key) {
8099 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008100 if (IsAccessCheckNeeded()) {
8101 Heap* heap = GetHeap();
8102 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8103 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8104 return false;
8105 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008106 }
8107
8108 LookupResult result;
8109 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008110 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00008111}
8112
8113
8114int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
8115 if (HasFastProperties()) {
8116 DescriptorArray* descs = map()->instance_descriptors();
8117 int result = 0;
8118 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01008119 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008120 if (details.IsProperty() && (details.attributes() & filter) == 0) {
8121 result++;
8122 }
8123 }
8124 return result;
8125 } else {
8126 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
8127 }
8128}
8129
8130
8131int JSObject::NumberOfEnumProperties() {
8132 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
8133}
8134
8135
8136void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
8137 Object* temp = get(i);
8138 set(i, get(j));
8139 set(j, temp);
8140 if (this != numbers) {
8141 temp = numbers->get(i);
8142 numbers->set(i, numbers->get(j));
8143 numbers->set(j, temp);
8144 }
8145}
8146
8147
8148static void InsertionSortPairs(FixedArray* content,
8149 FixedArray* numbers,
8150 int len) {
8151 for (int i = 1; i < len; i++) {
8152 int j = i;
8153 while (j > 0 &&
8154 (NumberToUint32(numbers->get(j - 1)) >
8155 NumberToUint32(numbers->get(j)))) {
8156 content->SwapPairs(numbers, j - 1, j);
8157 j--;
8158 }
8159 }
8160}
8161
8162
8163void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
8164 // In-place heap sort.
8165 ASSERT(content->length() == numbers->length());
8166
8167 // Bottom-up max-heap construction.
8168 for (int i = 1; i < len; ++i) {
8169 int child_index = i;
8170 while (child_index > 0) {
8171 int parent_index = ((child_index + 1) >> 1) - 1;
8172 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8173 uint32_t child_value = NumberToUint32(numbers->get(child_index));
8174 if (parent_value < child_value) {
8175 content->SwapPairs(numbers, parent_index, child_index);
8176 } else {
8177 break;
8178 }
8179 child_index = parent_index;
8180 }
8181 }
8182
8183 // Extract elements and create sorted array.
8184 for (int i = len - 1; i > 0; --i) {
8185 // Put max element at the back of the array.
8186 content->SwapPairs(numbers, 0, i);
8187 // Sift down the new top element.
8188 int parent_index = 0;
8189 while (true) {
8190 int child_index = ((parent_index + 1) << 1) - 1;
8191 if (child_index >= i) break;
8192 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
8193 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
8194 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8195 if (child_index + 1 >= i || child1_value > child2_value) {
8196 if (parent_value > child1_value) break;
8197 content->SwapPairs(numbers, parent_index, child_index);
8198 parent_index = child_index;
8199 } else {
8200 if (parent_value > child2_value) break;
8201 content->SwapPairs(numbers, parent_index, child_index + 1);
8202 parent_index = child_index + 1;
8203 }
8204 }
8205 }
8206}
8207
8208
8209// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
8210void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
8211 ASSERT(this->length() == numbers->length());
8212 // For small arrays, simply use insertion sort.
8213 if (len <= 10) {
8214 InsertionSortPairs(this, numbers, len);
8215 return;
8216 }
8217 // Check the range of indices.
8218 uint32_t min_index = NumberToUint32(numbers->get(0));
8219 uint32_t max_index = min_index;
8220 uint32_t i;
8221 for (i = 1; i < len; i++) {
8222 if (NumberToUint32(numbers->get(i)) < min_index) {
8223 min_index = NumberToUint32(numbers->get(i));
8224 } else if (NumberToUint32(numbers->get(i)) > max_index) {
8225 max_index = NumberToUint32(numbers->get(i));
8226 }
8227 }
8228 if (max_index - min_index + 1 == len) {
8229 // Indices form a contiguous range, unless there are duplicates.
8230 // Do an in-place linear time sort assuming distinct numbers, but
8231 // avoid hanging in case they are not.
8232 for (i = 0; i < len; i++) {
8233 uint32_t p;
8234 uint32_t j = 0;
8235 // While the current element at i is not at its correct position p,
8236 // swap the elements at these two positions.
8237 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
8238 j++ < len) {
8239 SwapPairs(numbers, i, p);
8240 }
8241 }
8242 } else {
8243 HeapSortPairs(this, numbers, len);
8244 return;
8245 }
8246}
8247
8248
8249// Fill in the names of local properties into the supplied storage. The main
8250// purpose of this function is to provide reflection information for the object
8251// mirrors.
8252void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
8253 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
8254 if (HasFastProperties()) {
8255 DescriptorArray* descs = map()->instance_descriptors();
8256 for (int i = 0; i < descs->number_of_descriptors(); i++) {
8257 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
8258 }
8259 ASSERT(storage->length() >= index);
8260 } else {
8261 property_dictionary()->CopyKeysTo(storage);
8262 }
8263}
8264
8265
8266int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
8267 return GetLocalElementKeys(NULL, filter);
8268}
8269
8270
8271int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00008272 // Fast case for objects with no elements.
8273 if (!IsJSValue() && HasFastElements()) {
8274 uint32_t length = IsJSArray() ?
8275 static_cast<uint32_t>(
8276 Smi::cast(JSArray::cast(this)->length())->value()) :
8277 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8278 if (length == 0) return 0;
8279 }
8280 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00008281 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
8282}
8283
8284
8285int JSObject::GetLocalElementKeys(FixedArray* storage,
8286 PropertyAttributes filter) {
8287 int counter = 0;
8288 switch (GetElementsKind()) {
8289 case FAST_ELEMENTS: {
8290 int length = IsJSArray() ?
8291 Smi::cast(JSArray::cast(this)->length())->value() :
8292 FixedArray::cast(elements())->length();
8293 for (int i = 0; i < length; i++) {
8294 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
8295 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008296 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008297 }
8298 counter++;
8299 }
8300 }
8301 ASSERT(!storage || storage->length() >= counter);
8302 break;
8303 }
Steve Block44f0eee2011-05-26 01:26:41 +01008304 case EXTERNAL_PIXEL_ELEMENTS: {
8305 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008306 while (counter < length) {
8307 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008308 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00008309 }
8310 counter++;
8311 }
8312 ASSERT(!storage || storage->length() >= counter);
8313 break;
8314 }
Steve Block3ce2e202009-11-05 08:53:23 +00008315 case EXTERNAL_BYTE_ELEMENTS:
8316 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8317 case EXTERNAL_SHORT_ELEMENTS:
8318 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8319 case EXTERNAL_INT_ELEMENTS:
8320 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8321 case EXTERNAL_FLOAT_ELEMENTS: {
8322 int length = ExternalArray::cast(elements())->length();
8323 while (counter < length) {
8324 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008325 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00008326 }
8327 counter++;
8328 }
8329 ASSERT(!storage || storage->length() >= counter);
8330 break;
8331 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008332 case DICTIONARY_ELEMENTS: {
8333 if (storage != NULL) {
8334 element_dictionary()->CopyKeysTo(storage, filter);
8335 }
8336 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
8337 break;
8338 }
8339 default:
8340 UNREACHABLE();
8341 break;
8342 }
8343
8344 if (this->IsJSValue()) {
8345 Object* val = JSValue::cast(this)->value();
8346 if (val->IsString()) {
8347 String* str = String::cast(val);
8348 if (storage) {
8349 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00008350 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008351 }
8352 }
8353 counter += str->length();
8354 }
8355 }
8356 ASSERT(!storage || storage->length() == counter);
8357 return counter;
8358}
8359
8360
8361int JSObject::GetEnumElementKeys(FixedArray* storage) {
8362 return GetLocalElementKeys(storage,
8363 static_cast<PropertyAttributes>(DONT_ENUM));
8364}
8365
8366
Steve Blocka7e24c12009-10-30 11:49:00 +00008367// StringKey simply carries a string object as key.
8368class StringKey : public HashTableKey {
8369 public:
8370 explicit StringKey(String* string) :
8371 string_(string),
8372 hash_(HashForObject(string)) { }
8373
8374 bool IsMatch(Object* string) {
8375 // We know that all entries in a hash table had their hash keys created.
8376 // Use that knowledge to have fast failure.
8377 if (hash_ != HashForObject(string)) {
8378 return false;
8379 }
8380 return string_->Equals(String::cast(string));
8381 }
8382
8383 uint32_t Hash() { return hash_; }
8384
8385 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
8386
8387 Object* AsObject() { return string_; }
8388
8389 String* string_;
8390 uint32_t hash_;
8391};
8392
8393
8394// StringSharedKeys are used as keys in the eval cache.
8395class StringSharedKey : public HashTableKey {
8396 public:
Steve Block1e0659c2011-05-24 12:43:12 +01008397 StringSharedKey(String* source,
8398 SharedFunctionInfo* shared,
8399 StrictModeFlag strict_mode)
8400 : source_(source),
8401 shared_(shared),
8402 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008403
8404 bool IsMatch(Object* other) {
8405 if (!other->IsFixedArray()) return false;
8406 FixedArray* pair = FixedArray::cast(other);
8407 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8408 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01008409 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8410 Smi::cast(pair->get(2))->value());
8411 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008412 String* source = String::cast(pair->get(1));
8413 return source->Equals(source_);
8414 }
8415
8416 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01008417 SharedFunctionInfo* shared,
8418 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008419 uint32_t hash = source->Hash();
8420 if (shared->HasSourceCode()) {
8421 // Instead of using the SharedFunctionInfo pointer in the hash
8422 // code computation, we use a combination of the hash of the
8423 // script source code and the start and end positions. We do
8424 // this to ensure that the cache entries can survive garbage
8425 // collection.
8426 Script* script = Script::cast(shared->script());
8427 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01008428 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00008429 hash += shared->start_position();
8430 }
8431 return hash;
8432 }
8433
8434 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01008435 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008436 }
8437
8438 uint32_t HashForObject(Object* obj) {
8439 FixedArray* pair = FixedArray::cast(obj);
8440 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8441 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01008442 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8443 Smi::cast(pair->get(2))->value());
8444 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00008445 }
8446
John Reck59135872010-11-02 12:39:01 -07008447 MUST_USE_RESULT MaybeObject* AsObject() {
8448 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008449 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07008450 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8451 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008452 FixedArray* pair = FixedArray::cast(obj);
8453 pair->set(0, shared_);
8454 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01008455 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00008456 return pair;
8457 }
8458
8459 private:
8460 String* source_;
8461 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01008462 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008463};
8464
8465
8466// RegExpKey carries the source and flags of a regular expression as key.
8467class RegExpKey : public HashTableKey {
8468 public:
8469 RegExpKey(String* string, JSRegExp::Flags flags)
8470 : string_(string),
8471 flags_(Smi::FromInt(flags.value())) { }
8472
Steve Block3ce2e202009-11-05 08:53:23 +00008473 // Rather than storing the key in the hash table, a pointer to the
8474 // stored value is stored where the key should be. IsMatch then
8475 // compares the search key to the found object, rather than comparing
8476 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00008477 bool IsMatch(Object* obj) {
8478 FixedArray* val = FixedArray::cast(obj);
8479 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
8480 && (flags_ == val->get(JSRegExp::kFlagsIndex));
8481 }
8482
8483 uint32_t Hash() { return RegExpHash(string_, flags_); }
8484
8485 Object* AsObject() {
8486 // Plain hash maps, which is where regexp keys are used, don't
8487 // use this function.
8488 UNREACHABLE();
8489 return NULL;
8490 }
8491
8492 uint32_t HashForObject(Object* obj) {
8493 FixedArray* val = FixedArray::cast(obj);
8494 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
8495 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
8496 }
8497
8498 static uint32_t RegExpHash(String* string, Smi* flags) {
8499 return string->Hash() + flags->value();
8500 }
8501
8502 String* string_;
8503 Smi* flags_;
8504};
8505
8506// Utf8SymbolKey carries a vector of chars as key.
8507class Utf8SymbolKey : public HashTableKey {
8508 public:
8509 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00008510 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008511
8512 bool IsMatch(Object* string) {
8513 return String::cast(string)->IsEqualTo(string_);
8514 }
8515
8516 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00008517 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008518 unibrow::Utf8InputBuffer<> buffer(string_.start(),
8519 static_cast<unsigned>(string_.length()));
8520 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00008521 hash_field_ = String::ComputeHashField(&buffer, chars_);
8522 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008523 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8524 return result;
8525 }
8526
8527 uint32_t HashForObject(Object* other) {
8528 return String::cast(other)->Hash();
8529 }
8530
John Reck59135872010-11-02 12:39:01 -07008531 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00008532 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008533 return Isolate::Current()->heap()->AllocateSymbol(
8534 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008535 }
8536
8537 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00008538 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008539 int chars_; // Caches the number of characters when computing the hash code.
8540};
8541
8542
Steve Block9fac8402011-05-12 15:51:54 +01008543template <typename Char>
8544class SequentialSymbolKey : public HashTableKey {
8545 public:
8546 explicit SequentialSymbolKey(Vector<const Char> string)
8547 : string_(string), hash_field_(0) { }
8548
8549 uint32_t Hash() {
8550 StringHasher hasher(string_.length());
8551
8552 // Very long strings have a trivial hash that doesn't inspect the
8553 // string contents.
8554 if (hasher.has_trivial_hash()) {
8555 hash_field_ = hasher.GetHashField();
8556 } else {
8557 int i = 0;
8558 // Do the iterative array index computation as long as there is a
8559 // chance this is an array index.
8560 while (i < string_.length() && hasher.is_array_index()) {
8561 hasher.AddCharacter(static_cast<uc32>(string_[i]));
8562 i++;
8563 }
8564
8565 // Process the remaining characters without updating the array
8566 // index.
8567 while (i < string_.length()) {
8568 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
8569 i++;
8570 }
8571 hash_field_ = hasher.GetHashField();
8572 }
8573
8574 uint32_t result = hash_field_ >> String::kHashShift;
8575 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8576 return result;
8577 }
8578
8579
8580 uint32_t HashForObject(Object* other) {
8581 return String::cast(other)->Hash();
8582 }
8583
8584 Vector<const Char> string_;
8585 uint32_t hash_field_;
8586};
8587
8588
8589
8590class AsciiSymbolKey : public SequentialSymbolKey<char> {
8591 public:
8592 explicit AsciiSymbolKey(Vector<const char> str)
8593 : SequentialSymbolKey<char>(str) { }
8594
8595 bool IsMatch(Object* string) {
8596 return String::cast(string)->IsAsciiEqualTo(string_);
8597 }
8598
8599 MaybeObject* AsObject() {
8600 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008601 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008602 }
8603};
8604
8605
8606class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
8607 public:
8608 explicit TwoByteSymbolKey(Vector<const uc16> str)
8609 : SequentialSymbolKey<uc16>(str) { }
8610
8611 bool IsMatch(Object* string) {
8612 return String::cast(string)->IsTwoByteEqualTo(string_);
8613 }
8614
8615 MaybeObject* AsObject() {
8616 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008617 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008618 }
8619};
8620
8621
Steve Blocka7e24c12009-10-30 11:49:00 +00008622// SymbolKey carries a string/symbol object as key.
8623class SymbolKey : public HashTableKey {
8624 public:
Steve Block44f0eee2011-05-26 01:26:41 +01008625 explicit SymbolKey(String* string)
8626 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008627
8628 bool IsMatch(Object* string) {
8629 return String::cast(string)->Equals(string_);
8630 }
8631
8632 uint32_t Hash() { return string_->Hash(); }
8633
8634 uint32_t HashForObject(Object* other) {
8635 return String::cast(other)->Hash();
8636 }
8637
John Reck59135872010-11-02 12:39:01 -07008638 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01008639 // Attempt to flatten the string, so that symbols will most often
8640 // be flat strings.
8641 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01008642 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008643 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01008644 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008645 if (map != NULL) {
8646 string_->set_map(map);
8647 ASSERT(string_->IsSymbol());
8648 return string_;
8649 }
8650 // Otherwise allocate a new symbol.
8651 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01008652 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00008653 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00008654 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00008655 }
8656
8657 static uint32_t StringHash(Object* obj) {
8658 return String::cast(obj)->Hash();
8659 }
8660
8661 String* string_;
8662};
8663
8664
8665template<typename Shape, typename Key>
8666void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
8667 IteratePointers(v, 0, kElementsStartOffset);
8668}
8669
8670
8671template<typename Shape, typename Key>
8672void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
8673 IteratePointers(v,
8674 kElementsStartOffset,
8675 kHeaderSize + length() * kPointerSize);
8676}
8677
8678
8679template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008680MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
8681 PretenureFlag pretenure) {
Steve Block6ded16b2010-05-10 14:33:55 +01008682 const int kMinCapacity = 32;
8683 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
8684 if (capacity < kMinCapacity) {
8685 capacity = kMinCapacity; // Guarantee min capacity.
Leon Clarkee46be812010-01-19 14:06:41 +00008686 } else if (capacity > HashTable::kMaxCapacity) {
8687 return Failure::OutOfMemoryException();
8688 }
8689
John Reck59135872010-11-02 12:39:01 -07008690 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008691 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
8692 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07008693 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00008694 }
John Reck59135872010-11-02 12:39:01 -07008695 HashTable::cast(obj)->SetNumberOfElements(0);
8696 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
8697 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008698 return obj;
8699}
8700
8701
Leon Clarkee46be812010-01-19 14:06:41 +00008702// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008703int StringDictionary::FindEntry(String* key) {
8704 if (!key->IsSymbol()) {
8705 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
8706 }
8707
8708 // Optimized for symbol key. Knowledge of the key type allows:
8709 // 1. Move the check if the key is a symbol out of the loop.
8710 // 2. Avoid comparing hash codes in symbol to symbol comparision.
8711 // 3. Detect a case when a dictionary key is not a symbol but the key is.
8712 // In case of positive result the dictionary key may be replaced by
8713 // the symbol with minimal performance penalty. It gives a chance to
8714 // perform further lookups in code stubs (and significant performance boost
8715 // a certain style of code).
8716
8717 // EnsureCapacity will guarantee the hash table is never full.
8718 uint32_t capacity = Capacity();
8719 uint32_t entry = FirstProbe(key->Hash(), capacity);
8720 uint32_t count = 1;
8721
8722 while (true) {
8723 int index = EntryToIndex(entry);
8724 Object* element = get(index);
8725 if (element->IsUndefined()) break; // Empty entry.
8726 if (key == element) return entry;
8727 if (!element->IsSymbol() &&
8728 !element->IsNull() &&
8729 String::cast(element)->Equals(key)) {
8730 // Replace a non-symbol key by the equivalent symbol for faster further
8731 // lookups.
8732 set(index, key);
8733 return entry;
8734 }
8735 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
8736 entry = NextProbe(entry, count++, capacity);
8737 }
8738 return kNotFound;
8739}
8740
8741
Steve Blocka7e24c12009-10-30 11:49:00 +00008742template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008743MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008744 int capacity = Capacity();
8745 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00008746 int nod = NumberOfDeletedElements();
8747 // Return if:
8748 // 50% is still free after adding n elements and
8749 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01008750 if (nod <= (capacity - nof) >> 1) {
8751 int needed_free = nof >> 1;
8752 if (nof + needed_free <= capacity) return this;
8753 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008754
Steve Block6ded16b2010-05-10 14:33:55 +01008755 const int kMinCapacityForPretenure = 256;
8756 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +01008757 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07008758 Object* obj;
8759 { MaybeObject* maybe_obj =
8760 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
8761 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8762 }
Leon Clarke4515c472010-02-03 11:58:03 +00008763
8764 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00008765 HashTable* table = HashTable::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00008766 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008767
8768 // Copy prefix to new array.
8769 for (int i = kPrefixStartIndex;
8770 i < kPrefixStartIndex + Shape::kPrefixSize;
8771 i++) {
8772 table->set(i, get(i), mode);
8773 }
8774 // Rehash the elements.
8775 for (int i = 0; i < capacity; i++) {
8776 uint32_t from_index = EntryToIndex(i);
8777 Object* k = get(from_index);
8778 if (IsKey(k)) {
8779 uint32_t hash = Shape::HashForObject(key, k);
8780 uint32_t insertion_index =
8781 EntryToIndex(table->FindInsertionEntry(hash));
8782 for (int j = 0; j < Shape::kEntrySize; j++) {
8783 table->set(insertion_index + j, get(from_index + j), mode);
8784 }
8785 }
8786 }
8787 table->SetNumberOfElements(NumberOfElements());
Leon Clarkee46be812010-01-19 14:06:41 +00008788 table->SetNumberOfDeletedElements(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008789 return table;
8790}
8791
8792
8793template<typename Shape, typename Key>
8794uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
8795 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00008796 uint32_t entry = FirstProbe(hash, capacity);
8797 uint32_t count = 1;
8798 // EnsureCapacity will guarantee the hash table is never full.
8799 while (true) {
8800 Object* element = KeyAt(entry);
8801 if (element->IsUndefined() || element->IsNull()) break;
8802 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008803 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008804 return entry;
8805}
8806
8807// Force instantiation of template instances class.
8808// Please note this list is compiler dependent.
8809
8810template class HashTable<SymbolTableShape, HashTableKey*>;
8811
8812template class HashTable<CompilationCacheShape, HashTableKey*>;
8813
8814template class HashTable<MapCacheShape, HashTableKey*>;
8815
8816template class Dictionary<StringDictionaryShape, String*>;
8817
8818template class Dictionary<NumberDictionaryShape, uint32_t>;
8819
John Reck59135872010-11-02 12:39:01 -07008820template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00008821 int);
8822
John Reck59135872010-11-02 12:39:01 -07008823template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00008824 int);
8825
John Reck59135872010-11-02 12:39:01 -07008826template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +00008827 uint32_t, Object*);
8828
8829template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
8830 Object*);
8831
8832template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
8833 Object*);
8834
8835template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
8836 FixedArray*, PropertyAttributes);
8837
8838template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
8839 int, JSObject::DeleteMode);
8840
8841template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
8842 int, JSObject::DeleteMode);
8843
8844template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
8845 FixedArray*);
8846
8847template int
8848Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
8849 PropertyAttributes);
8850
John Reck59135872010-11-02 12:39:01 -07008851template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00008852 String*, Object*, PropertyDetails);
8853
John Reck59135872010-11-02 12:39:01 -07008854template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +00008855Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
8856
8857template int
8858Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
8859 PropertyAttributes);
8860
John Reck59135872010-11-02 12:39:01 -07008861template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00008862 uint32_t, Object*, PropertyDetails);
8863
John Reck59135872010-11-02 12:39:01 -07008864template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
8865 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00008866
John Reck59135872010-11-02 12:39:01 -07008867template MaybeObject* Dictionary<StringDictionaryShape, String*>::
8868 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +00008869
John Reck59135872010-11-02 12:39:01 -07008870template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00008871 uint32_t, Object*, PropertyDetails, uint32_t);
8872
John Reck59135872010-11-02 12:39:01 -07008873template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00008874 String*, Object*, PropertyDetails, uint32_t);
8875
8876template
8877int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
8878
8879template
8880int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
8881
Leon Clarkee46be812010-01-19 14:06:41 +00008882template
8883int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
8884
8885
Steve Blocka7e24c12009-10-30 11:49:00 +00008886// Collates undefined and unexisting elements below limit from position
8887// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -07008888MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008889 ASSERT(HasDictionaryElements());
8890 // Must stay in dictionary mode, either because of requires_slow_elements,
8891 // or because we are not going to sort (and therefore compact) all of the
8892 // elements.
8893 NumberDictionary* dict = element_dictionary();
8894 HeapNumber* result_double = NULL;
8895 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
8896 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -07008897 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008898 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07008899 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
8900 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008901 result_double = HeapNumber::cast(new_double);
8902 }
8903
John Reck59135872010-11-02 12:39:01 -07008904 Object* obj;
8905 { MaybeObject* maybe_obj =
8906 NumberDictionary::Allocate(dict->NumberOfElements());
8907 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8908 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008909 NumberDictionary* new_dict = NumberDictionary::cast(obj);
8910
8911 AssertNoAllocation no_alloc;
8912
8913 uint32_t pos = 0;
8914 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01008915 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +00008916 for (int i = 0; i < capacity; i++) {
8917 Object* k = dict->KeyAt(i);
8918 if (dict->IsKey(k)) {
8919 ASSERT(k->IsNumber());
8920 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
8921 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
8922 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
8923 Object* value = dict->ValueAt(i);
8924 PropertyDetails details = dict->DetailsAt(i);
8925 if (details.type() == CALLBACKS) {
8926 // Bail out and do the sorting of undefineds and array holes in JS.
8927 return Smi::FromInt(-1);
8928 }
8929 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -07008930 // In the following we assert that adding the entry to the new dictionary
8931 // does not cause GC. This is the case because we made sure to allocate
8932 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +00008933 if (key < limit) {
8934 if (value->IsUndefined()) {
8935 undefs++;
8936 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01008937 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
8938 // Adding an entry with the key beyond smi-range requires
8939 // allocation. Bailout.
8940 return Smi::FromInt(-1);
8941 }
John Reck59135872010-11-02 12:39:01 -07008942 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008943 pos++;
8944 }
8945 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01008946 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
8947 // Adding an entry with the key beyond smi-range requires
8948 // allocation. Bailout.
8949 return Smi::FromInt(-1);
8950 }
John Reck59135872010-11-02 12:39:01 -07008951 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008952 }
8953 }
8954 }
8955
8956 uint32_t result = pos;
8957 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +01008958 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008959 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01008960 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
8961 // Adding an entry with the key beyond smi-range requires
8962 // allocation. Bailout.
8963 return Smi::FromInt(-1);
8964 }
Steve Block44f0eee2011-05-26 01:26:41 +01008965 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -07008966 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008967 pos++;
8968 undefs--;
8969 }
8970
8971 set_elements(new_dict);
8972
8973 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
8974 return Smi::FromInt(static_cast<int>(result));
8975 }
8976
8977 ASSERT_NE(NULL, result_double);
8978 result_double->set_value(static_cast<double>(result));
8979 return result_double;
8980}
8981
8982
8983// Collects all defined (non-hole) and non-undefined (array) elements at
8984// the start of the elements array.
8985// If the object is in dictionary mode, it is converted to fast elements
8986// mode.
John Reck59135872010-11-02 12:39:01 -07008987MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Steve Block44f0eee2011-05-26 01:26:41 +01008988 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008989
Ben Murdoch8b112d22011-06-08 16:22:53 +01008990 Heap* heap = GetHeap();
8991
Steve Blocka7e24c12009-10-30 11:49:00 +00008992 if (HasDictionaryElements()) {
8993 // Convert to fast elements containing only the existing properties.
8994 // Ordering is irrelevant, since we are going to sort anyway.
8995 NumberDictionary* dict = element_dictionary();
8996 if (IsJSArray() || dict->requires_slow_elements() ||
8997 dict->max_number_key() >= limit) {
8998 return PrepareSlowElementsForSort(limit);
8999 }
9000 // Convert to fast elements.
9001
John Reck59135872010-11-02 12:39:01 -07009002 Object* obj;
9003 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
9004 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9005 }
Steve Block8defd9f2010-07-08 12:39:36 +01009006 Map* new_map = Map::cast(obj);
9007
Steve Block44f0eee2011-05-26 01:26:41 +01009008 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -07009009 Object* new_array;
9010 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +01009011 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -07009012 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
9013 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009014 FixedArray* fast_elements = FixedArray::cast(new_array);
9015 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +01009016
9017 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00009018 set_elements(fast_elements);
Iain Merrick75681382010-08-19 15:07:18 +01009019 } else {
John Reck59135872010-11-02 12:39:01 -07009020 Object* obj;
9021 { MaybeObject* maybe_obj = EnsureWritableFastElements();
9022 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9023 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009024 }
9025 ASSERT(HasFastElements());
9026
9027 // Collect holes at the end, undefined before that and the rest at the
9028 // start, and return the number of non-hole, non-undefined values.
9029
9030 FixedArray* elements = FixedArray::cast(this->elements());
9031 uint32_t elements_length = static_cast<uint32_t>(elements->length());
9032 if (limit > elements_length) {
9033 limit = elements_length ;
9034 }
9035 if (limit == 0) {
9036 return Smi::FromInt(0);
9037 }
9038
9039 HeapNumber* result_double = NULL;
9040 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9041 // Pessimistically allocate space for return value before
9042 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -07009043 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +01009044 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07009045 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9046 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009047 result_double = HeapNumber::cast(new_double);
9048 }
9049
9050 AssertNoAllocation no_alloc;
9051
9052 // Split elements into defined, undefined and the_hole, in that order.
9053 // Only count locations for undefined and the hole, and fill them afterwards.
Leon Clarke4515c472010-02-03 11:58:03 +00009054 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009055 unsigned int undefs = limit;
9056 unsigned int holes = limit;
9057 // Assume most arrays contain no holes and undefined values, so minimize the
9058 // number of stores of non-undefined, non-the-hole values.
9059 for (unsigned int i = 0; i < undefs; i++) {
9060 Object* current = elements->get(i);
9061 if (current->IsTheHole()) {
9062 holes--;
9063 undefs--;
9064 } else if (current->IsUndefined()) {
9065 undefs--;
9066 } else {
9067 continue;
9068 }
9069 // Position i needs to be filled.
9070 while (undefs > i) {
9071 current = elements->get(undefs);
9072 if (current->IsTheHole()) {
9073 holes--;
9074 undefs--;
9075 } else if (current->IsUndefined()) {
9076 undefs--;
9077 } else {
9078 elements->set(i, current, write_barrier);
9079 break;
9080 }
9081 }
9082 }
9083 uint32_t result = undefs;
9084 while (undefs < holes) {
9085 elements->set_undefined(undefs);
9086 undefs++;
9087 }
9088 while (holes < limit) {
9089 elements->set_the_hole(holes);
9090 holes++;
9091 }
9092
9093 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9094 return Smi::FromInt(static_cast<int>(result));
9095 }
9096 ASSERT_NE(NULL, result_double);
9097 result_double->set_value(static_cast<double>(result));
9098 return result_double;
9099}
9100
9101
Steve Block44f0eee2011-05-26 01:26:41 +01009102Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009103 uint8_t clamped_value = 0;
9104 if (index < static_cast<uint32_t>(length())) {
9105 if (value->IsSmi()) {
9106 int int_value = Smi::cast(value)->value();
9107 if (int_value < 0) {
9108 clamped_value = 0;
9109 } else if (int_value > 255) {
9110 clamped_value = 255;
9111 } else {
9112 clamped_value = static_cast<uint8_t>(int_value);
9113 }
9114 } else if (value->IsHeapNumber()) {
9115 double double_value = HeapNumber::cast(value)->value();
9116 if (!(double_value > 0)) {
9117 // NaN and less than zero clamp to zero.
9118 clamped_value = 0;
9119 } else if (double_value > 255) {
9120 // Greater than 255 clamp to 255.
9121 clamped_value = 255;
9122 } else {
9123 // Other doubles are rounded to the nearest integer.
9124 clamped_value = static_cast<uint8_t>(double_value + 0.5);
9125 }
9126 } else {
9127 // Clamp undefined to zero (default). All other types have been
9128 // converted to a number type further up in the call chain.
9129 ASSERT(value->IsUndefined());
9130 }
9131 set(index, clamped_value);
9132 }
9133 return Smi::FromInt(clamped_value);
9134}
9135
9136
Steve Block3ce2e202009-11-05 08:53:23 +00009137template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +01009138static MaybeObject* ExternalArrayIntSetter(Heap* heap,
9139 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -07009140 uint32_t index,
9141 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009142 ValueType cast_value = 0;
9143 if (index < static_cast<uint32_t>(receiver->length())) {
9144 if (value->IsSmi()) {
9145 int int_value = Smi::cast(value)->value();
9146 cast_value = static_cast<ValueType>(int_value);
9147 } else if (value->IsHeapNumber()) {
9148 double double_value = HeapNumber::cast(value)->value();
9149 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
9150 } else {
9151 // Clamp undefined to zero (default). All other types have been
9152 // converted to a number type further up in the call chain.
9153 ASSERT(value->IsUndefined());
9154 }
9155 receiver->set(index, cast_value);
9156 }
Steve Block44f0eee2011-05-26 01:26:41 +01009157 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009158}
9159
9160
John Reck59135872010-11-02 12:39:01 -07009161MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009162 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009163 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009164}
9165
9166
John Reck59135872010-11-02 12:39:01 -07009167MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
9168 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009169 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009170 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009171}
9172
9173
John Reck59135872010-11-02 12:39:01 -07009174MaybeObject* ExternalShortArray::SetValue(uint32_t index,
9175 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009176 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009177 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009178}
9179
9180
John Reck59135872010-11-02 12:39:01 -07009181MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
9182 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009183 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009184 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009185}
9186
9187
John Reck59135872010-11-02 12:39:01 -07009188MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009189 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009190 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009191}
9192
9193
John Reck59135872010-11-02 12:39:01 -07009194MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009195 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009196 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009197 if (index < static_cast<uint32_t>(length())) {
9198 if (value->IsSmi()) {
9199 int int_value = Smi::cast(value)->value();
9200 cast_value = static_cast<uint32_t>(int_value);
9201 } else if (value->IsHeapNumber()) {
9202 double double_value = HeapNumber::cast(value)->value();
9203 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
9204 } else {
9205 // Clamp undefined to zero (default). All other types have been
9206 // converted to a number type further up in the call chain.
9207 ASSERT(value->IsUndefined());
9208 }
9209 set(index, cast_value);
9210 }
Steve Block44f0eee2011-05-26 01:26:41 +01009211 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009212}
9213
9214
John Reck59135872010-11-02 12:39:01 -07009215MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009216 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009217 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009218 if (index < static_cast<uint32_t>(length())) {
9219 if (value->IsSmi()) {
9220 int int_value = Smi::cast(value)->value();
9221 cast_value = static_cast<float>(int_value);
9222 } else if (value->IsHeapNumber()) {
9223 double double_value = HeapNumber::cast(value)->value();
9224 cast_value = static_cast<float>(double_value);
9225 } else {
9226 // Clamp undefined to zero (default). All other types have been
9227 // converted to a number type further up in the call chain.
9228 ASSERT(value->IsUndefined());
9229 }
9230 set(index, cast_value);
9231 }
Steve Block44f0eee2011-05-26 01:26:41 +01009232 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009233}
9234
9235
Ben Murdochb0fe1622011-05-05 13:52:32 +01009236JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009237 ASSERT(!HasFastProperties());
9238 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009239 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009240}
9241
9242
John Reck59135872010-11-02 12:39:01 -07009243MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009244 ASSERT(!HasFastProperties());
9245 int entry = property_dictionary()->FindEntry(name);
9246 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009247 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07009248 Object* cell;
9249 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +01009250 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -07009251 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
9252 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009253 PropertyDetails details(NONE, NORMAL);
9254 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -07009255 Object* dictionary;
9256 { MaybeObject* maybe_dictionary =
9257 property_dictionary()->Add(name, cell, details);
9258 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
9259 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009260 set_properties(StringDictionary::cast(dictionary));
9261 return cell;
9262 } else {
9263 Object* value = property_dictionary()->ValueAt(entry);
9264 ASSERT(value->IsJSGlobalPropertyCell());
9265 return value;
9266 }
9267}
9268
9269
John Reck59135872010-11-02 12:39:01 -07009270MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009271 SymbolKey key(string);
9272 return LookupKey(&key, s);
9273}
9274
9275
Steve Blockd0582a62009-12-15 09:54:21 +00009276// This class is used for looking up two character strings in the symbol table.
9277// If we don't have a hit we don't want to waste much time so we unroll the
9278// string hash calculation loop here for speed. Doesn't work if the two
9279// characters form a decimal integer, since such strings have a different hash
9280// algorithm.
9281class TwoCharHashTableKey : public HashTableKey {
9282 public:
9283 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
9284 : c1_(c1), c2_(c2) {
9285 // Char 1.
9286 uint32_t hash = c1 + (c1 << 10);
9287 hash ^= hash >> 6;
9288 // Char 2.
9289 hash += c2;
9290 hash += hash << 10;
9291 hash ^= hash >> 6;
9292 // GetHash.
9293 hash += hash << 3;
9294 hash ^= hash >> 11;
9295 hash += hash << 15;
9296 if (hash == 0) hash = 27;
9297#ifdef DEBUG
9298 StringHasher hasher(2);
9299 hasher.AddCharacter(c1);
9300 hasher.AddCharacter(c2);
9301 // If this assert fails then we failed to reproduce the two-character
9302 // version of the string hashing algorithm above. One reason could be
9303 // that we were passed two digits as characters, since the hash
9304 // algorithm is different in that case.
9305 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
9306#endif
9307 hash_ = hash;
9308 }
9309
9310 bool IsMatch(Object* o) {
9311 if (!o->IsString()) return false;
9312 String* other = String::cast(o);
9313 if (other->length() != 2) return false;
9314 if (other->Get(0) != c1_) return false;
9315 return other->Get(1) == c2_;
9316 }
9317
9318 uint32_t Hash() { return hash_; }
9319 uint32_t HashForObject(Object* key) {
9320 if (!key->IsString()) return 0;
9321 return String::cast(key)->Hash();
9322 }
9323
9324 Object* AsObject() {
9325 // The TwoCharHashTableKey is only used for looking in the symbol
9326 // table, not for adding to it.
9327 UNREACHABLE();
9328 return NULL;
9329 }
9330 private:
9331 uint32_t c1_;
9332 uint32_t c2_;
9333 uint32_t hash_;
9334};
9335
9336
Steve Blocka7e24c12009-10-30 11:49:00 +00009337bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
9338 SymbolKey key(string);
9339 int entry = FindEntry(&key);
9340 if (entry == kNotFound) {
9341 return false;
9342 } else {
9343 String* result = String::cast(KeyAt(entry));
9344 ASSERT(StringShape(result).IsSymbol());
9345 *symbol = result;
9346 return true;
9347 }
9348}
9349
9350
Steve Blockd0582a62009-12-15 09:54:21 +00009351bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
9352 uint32_t c2,
9353 String** symbol) {
9354 TwoCharHashTableKey key(c1, c2);
9355 int entry = FindEntry(&key);
9356 if (entry == kNotFound) {
9357 return false;
9358 } else {
9359 String* result = String::cast(KeyAt(entry));
9360 ASSERT(StringShape(result).IsSymbol());
9361 *symbol = result;
9362 return true;
9363 }
9364}
9365
9366
John Reck59135872010-11-02 12:39:01 -07009367MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009368 Utf8SymbolKey key(str);
9369 return LookupKey(&key, s);
9370}
9371
9372
Steve Block9fac8402011-05-12 15:51:54 +01009373MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
9374 Object** s) {
9375 AsciiSymbolKey key(str);
9376 return LookupKey(&key, s);
9377}
9378
9379
9380MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
9381 Object** s) {
9382 TwoByteSymbolKey key(str);
9383 return LookupKey(&key, s);
9384}
9385
John Reck59135872010-11-02 12:39:01 -07009386MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009387 int entry = FindEntry(key);
9388
9389 // Symbol already in table.
9390 if (entry != kNotFound) {
9391 *s = KeyAt(entry);
9392 return this;
9393 }
9394
9395 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -07009396 Object* obj;
9397 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9398 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9399 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009400
9401 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -07009402 Object* symbol;
9403 { MaybeObject* maybe_symbol = key->AsObject();
9404 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
9405 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009406
9407 // If the symbol table grew as part of EnsureCapacity, obj is not
9408 // the current symbol table and therefore we cannot use
9409 // SymbolTable::cast here.
9410 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
9411
9412 // Add the new symbol and return it along with the symbol table.
9413 entry = table->FindInsertionEntry(key->Hash());
9414 table->set(EntryToIndex(entry), symbol);
9415 table->ElementAdded();
9416 *s = symbol;
9417 return table;
9418}
9419
9420
9421Object* CompilationCacheTable::Lookup(String* src) {
9422 StringKey key(src);
9423 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009424 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009425 return get(EntryToIndex(entry) + 1);
9426}
9427
9428
Steve Block1e0659c2011-05-24 12:43:12 +01009429Object* CompilationCacheTable::LookupEval(String* src,
9430 Context* context,
9431 StrictModeFlag strict_mode) {
9432 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009433 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009434 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009435 return get(EntryToIndex(entry) + 1);
9436}
9437
9438
9439Object* CompilationCacheTable::LookupRegExp(String* src,
9440 JSRegExp::Flags flags) {
9441 RegExpKey key(src, flags);
9442 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009443 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009444 return get(EntryToIndex(entry) + 1);
9445}
9446
9447
John Reck59135872010-11-02 12:39:01 -07009448MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009449 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -07009450 Object* obj;
9451 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9452 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9453 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009454
9455 CompilationCacheTable* cache =
9456 reinterpret_cast<CompilationCacheTable*>(obj);
9457 int entry = cache->FindInsertionEntry(key.Hash());
9458 cache->set(EntryToIndex(entry), src);
9459 cache->set(EntryToIndex(entry) + 1, value);
9460 cache->ElementAdded();
9461 return cache;
9462}
9463
9464
John Reck59135872010-11-02 12:39:01 -07009465MaybeObject* CompilationCacheTable::PutEval(String* src,
9466 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +01009467 SharedFunctionInfo* value) {
9468 StringSharedKey key(src,
9469 context->closure()->shared(),
9470 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -07009471 Object* obj;
9472 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9473 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9474 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009475
9476 CompilationCacheTable* cache =
9477 reinterpret_cast<CompilationCacheTable*>(obj);
9478 int entry = cache->FindInsertionEntry(key.Hash());
9479
John Reck59135872010-11-02 12:39:01 -07009480 Object* k;
9481 { MaybeObject* maybe_k = key.AsObject();
9482 if (!maybe_k->ToObject(&k)) return maybe_k;
9483 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009484
9485 cache->set(EntryToIndex(entry), k);
9486 cache->set(EntryToIndex(entry) + 1, value);
9487 cache->ElementAdded();
9488 return cache;
9489}
9490
9491
John Reck59135872010-11-02 12:39:01 -07009492MaybeObject* CompilationCacheTable::PutRegExp(String* src,
9493 JSRegExp::Flags flags,
9494 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009495 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -07009496 Object* obj;
9497 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9498 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9499 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009500
9501 CompilationCacheTable* cache =
9502 reinterpret_cast<CompilationCacheTable*>(obj);
9503 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +00009504 // We store the value in the key slot, and compare the search key
9505 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +00009506 cache->set(EntryToIndex(entry), value);
9507 cache->set(EntryToIndex(entry) + 1, value);
9508 cache->ElementAdded();
9509 return cache;
9510}
9511
9512
Ben Murdochb0fe1622011-05-05 13:52:32 +01009513void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009514 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01009515 for (int entry = 0, size = Capacity(); entry < size; entry++) {
9516 int entry_index = EntryToIndex(entry);
9517 int value_index = entry_index + 1;
9518 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009519 fast_set(this, entry_index, null_value);
9520 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009521 ElementRemoved();
9522 }
9523 }
9524 return;
9525}
9526
9527
Steve Blocka7e24c12009-10-30 11:49:00 +00009528// SymbolsKey used for HashTable where key is array of symbols.
9529class SymbolsKey : public HashTableKey {
9530 public:
9531 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
9532
9533 bool IsMatch(Object* symbols) {
9534 FixedArray* o = FixedArray::cast(symbols);
9535 int len = symbols_->length();
9536 if (o->length() != len) return false;
9537 for (int i = 0; i < len; i++) {
9538 if (o->get(i) != symbols_->get(i)) return false;
9539 }
9540 return true;
9541 }
9542
9543 uint32_t Hash() { return HashForObject(symbols_); }
9544
9545 uint32_t HashForObject(Object* obj) {
9546 FixedArray* symbols = FixedArray::cast(obj);
9547 int len = symbols->length();
9548 uint32_t hash = 0;
9549 for (int i = 0; i < len; i++) {
9550 hash ^= String::cast(symbols->get(i))->Hash();
9551 }
9552 return hash;
9553 }
9554
9555 Object* AsObject() { return symbols_; }
9556
9557 private:
9558 FixedArray* symbols_;
9559};
9560
9561
9562Object* MapCache::Lookup(FixedArray* array) {
9563 SymbolsKey key(array);
9564 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009565 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009566 return get(EntryToIndex(entry) + 1);
9567}
9568
9569
John Reck59135872010-11-02 12:39:01 -07009570MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009571 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -07009572 Object* obj;
9573 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9574 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9575 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009576
9577 MapCache* cache = reinterpret_cast<MapCache*>(obj);
9578 int entry = cache->FindInsertionEntry(key.Hash());
9579 cache->set(EntryToIndex(entry), array);
9580 cache->set(EntryToIndex(entry) + 1, value);
9581 cache->ElementAdded();
9582 return cache;
9583}
9584
9585
9586template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009587MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
9588 Object* obj;
9589 { MaybeObject* maybe_obj =
9590 HashTable<Shape, Key>::Allocate(at_least_space_for);
9591 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009592 }
John Reck59135872010-11-02 12:39:01 -07009593 // Initialize the next enumeration index.
9594 Dictionary<Shape, Key>::cast(obj)->
9595 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +00009596 return obj;
9597}
9598
9599
9600template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009601MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +01009602 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009603 int length = HashTable<Shape, Key>::NumberOfElements();
9604
9605 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -07009606 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009607 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009608 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9609 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009610 FixedArray* iteration_order = FixedArray::cast(obj);
9611 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009612 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009613 }
9614
9615 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +01009616 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009617 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9618 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009619 FixedArray* enumeration_order = FixedArray::cast(obj);
9620
9621 // Fill the enumeration order array with property details.
9622 int capacity = HashTable<Shape, Key>::Capacity();
9623 int pos = 0;
9624 for (int i = 0; i < capacity; i++) {
9625 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +00009626 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009627 }
9628 }
9629
9630 // Sort the arrays wrt. enumeration order.
9631 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
9632
9633 // Overwrite the enumeration_order with the enumeration indices.
9634 for (int i = 0; i < length; i++) {
9635 int index = Smi::cast(iteration_order->get(i))->value();
9636 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +00009637 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +00009638 }
9639
9640 // Update the dictionary with new indices.
9641 capacity = HashTable<Shape, Key>::Capacity();
9642 pos = 0;
9643 for (int i = 0; i < capacity; i++) {
9644 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
9645 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
9646 PropertyDetails details = DetailsAt(i);
9647 PropertyDetails new_details =
9648 PropertyDetails(details.attributes(), details.type(), enum_index);
9649 DetailsAtPut(i, new_details);
9650 }
9651 }
9652
9653 // Set the next enumeration index.
9654 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
9655 return this;
9656}
9657
9658template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009659MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009660 // Check whether there are enough enumeration indices to add n elements.
9661 if (Shape::kIsEnumerable &&
9662 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
9663 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -07009664 Object* result;
9665 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
9666 if (!maybe_result->ToObject(&result)) return maybe_result;
9667 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009668 }
9669 return HashTable<Shape, Key>::EnsureCapacity(n, key);
9670}
9671
9672
9673void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
9674 // Do nothing if the interval [from, to) is empty.
9675 if (from >= to) return;
9676
Steve Block44f0eee2011-05-26 01:26:41 +01009677 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009678 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009679 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009680 int capacity = Capacity();
9681 for (int i = 0; i < capacity; i++) {
9682 Object* key = KeyAt(i);
9683 if (key->IsNumber()) {
9684 uint32_t number = static_cast<uint32_t>(key->Number());
9685 if (from <= number && number < to) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009686 SetEntry(i, sentinel, sentinel);
Steve Blocka7e24c12009-10-30 11:49:00 +00009687 removed_entries++;
9688 }
9689 }
9690 }
9691
9692 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +00009693 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +00009694}
9695
9696
9697template<typename Shape, typename Key>
9698Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
9699 JSObject::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01009700 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009701 PropertyDetails details = DetailsAt(entry);
9702 // Ignore attributes if forcing a deletion.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009703 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +01009704 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009705 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009706 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00009707 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +01009708 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009709}
9710
9711
9712template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009713MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009714 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +00009715
9716 // If the entry is present set the value;
9717 if (entry != Dictionary<Shape, Key>::kNotFound) {
9718 ValueAtPut(entry, value);
9719 return this;
9720 }
9721
9722 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -07009723 Object* obj;
9724 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9725 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9726 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009727
John Reck59135872010-11-02 12:39:01 -07009728 Object* k;
9729 { MaybeObject* maybe_k = Shape::AsObject(key);
9730 if (!maybe_k->ToObject(&k)) return maybe_k;
9731 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009732 PropertyDetails details = PropertyDetails(NONE, NORMAL);
9733 return Dictionary<Shape, Key>::cast(obj)->
9734 AddEntry(key, value, details, Shape::Hash(key));
9735}
9736
9737
9738template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009739MaybeObject* Dictionary<Shape, Key>::Add(Key key,
9740 Object* value,
9741 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009742 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009743 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +00009744 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -07009745 Object* obj;
9746 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9747 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9748 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009749 return Dictionary<Shape, Key>::cast(obj)->
9750 AddEntry(key, value, details, Shape::Hash(key));
9751}
9752
9753
9754// Add a key, value pair to the dictionary.
9755template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009756MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
9757 Object* value,
9758 PropertyDetails details,
9759 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009760 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -07009761 Object* k;
9762 { MaybeObject* maybe_k = Shape::AsObject(key);
9763 if (!maybe_k->ToObject(&k)) return maybe_k;
9764 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009765
9766 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
9767 // Insert element at empty or deleted entry
9768 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
9769 // Assign an enumeration index to the property and update
9770 // SetNextEnumerationIndex.
9771 int index = NextEnumerationIndex();
9772 details = PropertyDetails(details.attributes(), details.type(), index);
9773 SetNextEnumerationIndex(index + 1);
9774 }
9775 SetEntry(entry, k, value, details);
9776 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
9777 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
9778 HashTable<Shape, Key>::ElementAdded();
9779 return this;
9780}
9781
9782
9783void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
9784 // If the dictionary requires slow elements an element has already
9785 // been added at a high index.
9786 if (requires_slow_elements()) return;
9787 // Check if this index is high enough that we should require slow
9788 // elements.
9789 if (key > kRequiresSlowElementsLimit) {
9790 set_requires_slow_elements();
9791 return;
9792 }
9793 // Update max key value.
9794 Object* max_index_object = get(kMaxNumberKeyIndex);
9795 if (!max_index_object->IsSmi() || max_number_key() < key) {
9796 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00009797 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00009798 }
9799}
9800
9801
John Reck59135872010-11-02 12:39:01 -07009802MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
9803 Object* value,
9804 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009805 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009806 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +00009807 return Add(key, value, details);
9808}
9809
9810
John Reck59135872010-11-02 12:39:01 -07009811MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009812 UpdateMaxNumberKey(key);
9813 return AtPut(key, value);
9814}
9815
9816
John Reck59135872010-11-02 12:39:01 -07009817MaybeObject* NumberDictionary::Set(uint32_t key,
9818 Object* value,
9819 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009820 int entry = FindEntry(key);
9821 if (entry == kNotFound) return AddNumberEntry(key, value, details);
9822 // Preserve enumeration index.
9823 details = PropertyDetails(details.attributes(),
9824 details.type(),
9825 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -07009826 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
9827 Object* object_key;
9828 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +01009829 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00009830 return this;
9831}
9832
9833
9834
9835template<typename Shape, typename Key>
9836int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
9837 PropertyAttributes filter) {
9838 int capacity = HashTable<Shape, Key>::Capacity();
9839 int result = 0;
9840 for (int i = 0; i < capacity; i++) {
9841 Object* k = HashTable<Shape, Key>::KeyAt(i);
9842 if (HashTable<Shape, Key>::IsKey(k)) {
9843 PropertyDetails details = DetailsAt(i);
9844 if (details.IsDeleted()) continue;
9845 PropertyAttributes attr = details.attributes();
9846 if ((attr & filter) == 0) result++;
9847 }
9848 }
9849 return result;
9850}
9851
9852
9853template<typename Shape, typename Key>
9854int Dictionary<Shape, Key>::NumberOfEnumElements() {
9855 return NumberOfElementsFilterAttributes(
9856 static_cast<PropertyAttributes>(DONT_ENUM));
9857}
9858
9859
9860template<typename Shape, typename Key>
9861void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
9862 PropertyAttributes filter) {
9863 ASSERT(storage->length() >= NumberOfEnumElements());
9864 int capacity = HashTable<Shape, Key>::Capacity();
9865 int index = 0;
9866 for (int i = 0; i < capacity; i++) {
9867 Object* k = HashTable<Shape, Key>::KeyAt(i);
9868 if (HashTable<Shape, Key>::IsKey(k)) {
9869 PropertyDetails details = DetailsAt(i);
9870 if (details.IsDeleted()) continue;
9871 PropertyAttributes attr = details.attributes();
9872 if ((attr & filter) == 0) storage->set(index++, k);
9873 }
9874 }
9875 storage->SortPairs(storage, index);
9876 ASSERT(storage->length() >= index);
9877}
9878
9879
9880void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
9881 FixedArray* sort_array) {
9882 ASSERT(storage->length() >= NumberOfEnumElements());
9883 int capacity = Capacity();
9884 int index = 0;
9885 for (int i = 0; i < capacity; i++) {
9886 Object* k = KeyAt(i);
9887 if (IsKey(k)) {
9888 PropertyDetails details = DetailsAt(i);
9889 if (details.IsDeleted() || details.IsDontEnum()) continue;
9890 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +00009891 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009892 index++;
9893 }
9894 }
9895 storage->SortPairs(sort_array, sort_array->length());
9896 ASSERT(storage->length() >= index);
9897}
9898
9899
9900template<typename Shape, typename Key>
9901void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
9902 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
9903 static_cast<PropertyAttributes>(NONE)));
9904 int capacity = HashTable<Shape, Key>::Capacity();
9905 int index = 0;
9906 for (int i = 0; i < capacity; i++) {
9907 Object* k = HashTable<Shape, Key>::KeyAt(i);
9908 if (HashTable<Shape, Key>::IsKey(k)) {
9909 PropertyDetails details = DetailsAt(i);
9910 if (details.IsDeleted()) continue;
9911 storage->set(index++, k);
9912 }
9913 }
9914 ASSERT(storage->length() >= index);
9915}
9916
9917
9918// Backwards lookup (slow).
9919template<typename Shape, typename Key>
9920Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
9921 int capacity = HashTable<Shape, Key>::Capacity();
9922 for (int i = 0; i < capacity; i++) {
9923 Object* k = HashTable<Shape, Key>::KeyAt(i);
9924 if (Dictionary<Shape, Key>::IsKey(k)) {
9925 Object* e = ValueAt(i);
9926 if (e->IsJSGlobalPropertyCell()) {
9927 e = JSGlobalPropertyCell::cast(e)->value();
9928 }
9929 if (e == value) return k;
9930 }
9931 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009932 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01009933 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009934}
9935
9936
John Reck59135872010-11-02 12:39:01 -07009937MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +00009938 JSObject* obj, int unused_property_fields) {
9939 // Make sure we preserve dictionary representation if there are too many
9940 // descriptors.
9941 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
9942
9943 // Figure out if it is necessary to generate new enumeration indices.
9944 int max_enumeration_index =
9945 NextEnumerationIndex() +
9946 (DescriptorArray::kMaxNumberOfDescriptors -
9947 NumberOfElements());
9948 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -07009949 Object* result;
9950 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
9951 if (!maybe_result->ToObject(&result)) return maybe_result;
9952 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009953 }
9954
9955 int instance_descriptor_length = 0;
9956 int number_of_fields = 0;
9957
Ben Murdoch8b112d22011-06-08 16:22:53 +01009958 Heap* heap = GetHeap();
9959
Steve Blocka7e24c12009-10-30 11:49:00 +00009960 // Compute the length of the instance descriptor.
9961 int capacity = Capacity();
9962 for (int i = 0; i < capacity; i++) {
9963 Object* k = KeyAt(i);
9964 if (IsKey(k)) {
9965 Object* value = ValueAt(i);
9966 PropertyType type = DetailsAt(i).type();
9967 ASSERT(type != FIELD);
9968 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +00009969 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +01009970 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +00009971 number_of_fields += 1;
9972 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009973 }
9974 }
9975
9976 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -07009977 Object* descriptors_unchecked;
9978 { MaybeObject* maybe_descriptors_unchecked =
9979 DescriptorArray::Allocate(instance_descriptor_length);
9980 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
9981 return maybe_descriptors_unchecked;
9982 }
9983 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009984 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
9985
9986 int inobject_props = obj->map()->inobject_properties();
9987 int number_of_allocated_fields =
9988 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +01009989 if (number_of_allocated_fields < 0) {
9990 // There is enough inobject space for all fields (including unused).
9991 number_of_allocated_fields = 0;
9992 unused_property_fields = inobject_props - number_of_fields;
9993 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009994
9995 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -07009996 Object* fields;
9997 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +01009998 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -07009999 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
10000 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010001
10002 // Fill in the instance descriptor and the fields.
10003 int next_descriptor = 0;
10004 int current_offset = 0;
10005 for (int i = 0; i < capacity; i++) {
10006 Object* k = KeyAt(i);
10007 if (IsKey(k)) {
10008 Object* value = ValueAt(i);
10009 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070010010 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010010011 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070010012 if (!maybe_key->ToObject(&key)) return maybe_key;
10013 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010014 PropertyDetails details = DetailsAt(i);
10015 PropertyType type = details.type();
10016
Steve Block44f0eee2011-05-26 01:26:41 +010010017 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010018 ConstantFunctionDescriptor d(String::cast(key),
10019 JSFunction::cast(value),
10020 details.attributes(),
10021 details.index());
10022 descriptors->Set(next_descriptor++, &d);
10023 } else if (type == NORMAL) {
10024 if (current_offset < inobject_props) {
10025 obj->InObjectPropertyAtPut(current_offset,
10026 value,
10027 UPDATE_WRITE_BARRIER);
10028 } else {
10029 int offset = current_offset - inobject_props;
10030 FixedArray::cast(fields)->set(offset, value);
10031 }
10032 FieldDescriptor d(String::cast(key),
10033 current_offset++,
10034 details.attributes(),
10035 details.index());
10036 descriptors->Set(next_descriptor++, &d);
10037 } else if (type == CALLBACKS) {
10038 CallbacksDescriptor d(String::cast(key),
10039 value,
10040 details.attributes(),
10041 details.index());
10042 descriptors->Set(next_descriptor++, &d);
10043 } else {
10044 UNREACHABLE();
10045 }
10046 }
10047 }
10048 ASSERT(current_offset == number_of_fields);
10049
10050 descriptors->Sort();
10051 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070010052 Object* new_map;
10053 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
10054 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10055 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010056
10057 // Transform the object.
10058 obj->set_map(Map::cast(new_map));
10059 obj->map()->set_instance_descriptors(descriptors);
10060 obj->map()->set_unused_property_fields(unused_property_fields);
10061
10062 obj->set_properties(FixedArray::cast(fields));
10063 ASSERT(obj->IsJSObject());
10064
10065 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
10066 // Check that it really works.
10067 ASSERT(obj->HasFastProperties());
10068
10069 return obj;
10070}
10071
10072
10073#ifdef ENABLE_DEBUGGER_SUPPORT
10074// Check if there is a break point at this code position.
10075bool DebugInfo::HasBreakPoint(int code_position) {
10076 // Get the break point info object for this code position.
10077 Object* break_point_info = GetBreakPointInfo(code_position);
10078
10079 // If there is no break point info object or no break points in the break
10080 // point info object there is no break point at this code position.
10081 if (break_point_info->IsUndefined()) return false;
10082 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
10083}
10084
10085
10086// Get the break point info object for this code position.
10087Object* DebugInfo::GetBreakPointInfo(int code_position) {
10088 // Find the index of the break point info object for this code position.
10089 int index = GetBreakPointInfoIndex(code_position);
10090
10091 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010092 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010093 return BreakPointInfo::cast(break_points()->get(index));
10094}
10095
10096
10097// Clear a break point at the specified code position.
10098void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
10099 int code_position,
10100 Handle<Object> break_point_object) {
10101 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10102 if (break_point_info->IsUndefined()) return;
10103 BreakPointInfo::ClearBreakPoint(
10104 Handle<BreakPointInfo>::cast(break_point_info),
10105 break_point_object);
10106}
10107
10108
10109void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
10110 int code_position,
10111 int source_position,
10112 int statement_position,
10113 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010114 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010115 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10116 if (!break_point_info->IsUndefined()) {
10117 BreakPointInfo::SetBreakPoint(
10118 Handle<BreakPointInfo>::cast(break_point_info),
10119 break_point_object);
10120 return;
10121 }
10122
10123 // Adding a new break point for a code position which did not have any
10124 // break points before. Try to find a free slot.
10125 int index = kNoBreakPointInfo;
10126 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10127 if (debug_info->break_points()->get(i)->IsUndefined()) {
10128 index = i;
10129 break;
10130 }
10131 }
10132 if (index == kNoBreakPointInfo) {
10133 // No free slot - extend break point info array.
10134 Handle<FixedArray> old_break_points =
10135 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010136 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010010137 isolate->factory()->NewFixedArray(
10138 old_break_points->length() +
10139 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010140
10141 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000010142 for (int i = 0; i < old_break_points->length(); i++) {
10143 new_break_points->set(i, old_break_points->get(i));
10144 }
10145 index = old_break_points->length();
10146 }
10147 ASSERT(index != kNoBreakPointInfo);
10148
10149 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010010150 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
10151 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000010152 new_break_point_info->set_code_position(Smi::FromInt(code_position));
10153 new_break_point_info->set_source_position(Smi::FromInt(source_position));
10154 new_break_point_info->
10155 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010010156 new_break_point_info->set_break_point_objects(
10157 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010158 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
10159 debug_info->break_points()->set(index, *new_break_point_info);
10160}
10161
10162
10163// Get the break point objects for a code position.
10164Object* DebugInfo::GetBreakPointObjects(int code_position) {
10165 Object* break_point_info = GetBreakPointInfo(code_position);
10166 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010167 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010168 }
10169 return BreakPointInfo::cast(break_point_info)->break_point_objects();
10170}
10171
10172
10173// Get the total number of break points.
10174int DebugInfo::GetBreakPointCount() {
10175 if (break_points()->IsUndefined()) return 0;
10176 int count = 0;
10177 for (int i = 0; i < break_points()->length(); i++) {
10178 if (!break_points()->get(i)->IsUndefined()) {
10179 BreakPointInfo* break_point_info =
10180 BreakPointInfo::cast(break_points()->get(i));
10181 count += break_point_info->GetBreakPointCount();
10182 }
10183 }
10184 return count;
10185}
10186
10187
10188Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
10189 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010190 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010010191 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010192 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10193 if (!debug_info->break_points()->get(i)->IsUndefined()) {
10194 Handle<BreakPointInfo> break_point_info =
10195 Handle<BreakPointInfo>(BreakPointInfo::cast(
10196 debug_info->break_points()->get(i)));
10197 if (BreakPointInfo::HasBreakPointObject(break_point_info,
10198 break_point_object)) {
10199 return *break_point_info;
10200 }
10201 }
10202 }
Steve Block44f0eee2011-05-26 01:26:41 +010010203 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010204}
10205
10206
10207// Find the index of the break point info object for the specified code
10208// position.
10209int DebugInfo::GetBreakPointInfoIndex(int code_position) {
10210 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
10211 for (int i = 0; i < break_points()->length(); i++) {
10212 if (!break_points()->get(i)->IsUndefined()) {
10213 BreakPointInfo* break_point_info =
10214 BreakPointInfo::cast(break_points()->get(i));
10215 if (break_point_info->code_position()->value() == code_position) {
10216 return i;
10217 }
10218 }
10219 }
10220 return kNoBreakPointInfo;
10221}
10222
10223
10224// Remove the specified break point object.
10225void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
10226 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010227 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010228 // If there are no break points just ignore.
10229 if (break_point_info->break_point_objects()->IsUndefined()) return;
10230 // If there is a single break point clear it if it is the same.
10231 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10232 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010233 break_point_info->set_break_point_objects(
10234 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010235 }
10236 return;
10237 }
10238 // If there are multiple break points shrink the array
10239 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
10240 Handle<FixedArray> old_array =
10241 Handle<FixedArray>(
10242 FixedArray::cast(break_point_info->break_point_objects()));
10243 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010244 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010245 int found_count = 0;
10246 for (int i = 0; i < old_array->length(); i++) {
10247 if (old_array->get(i) == *break_point_object) {
10248 ASSERT(found_count == 0);
10249 found_count++;
10250 } else {
10251 new_array->set(i - found_count, old_array->get(i));
10252 }
10253 }
10254 // If the break point was found in the list change it.
10255 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
10256}
10257
10258
10259// Add the specified break point object.
10260void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
10261 Handle<Object> break_point_object) {
10262 // If there was no break point objects before just set it.
10263 if (break_point_info->break_point_objects()->IsUndefined()) {
10264 break_point_info->set_break_point_objects(*break_point_object);
10265 return;
10266 }
10267 // If the break point object is the same as before just ignore.
10268 if (break_point_info->break_point_objects() == *break_point_object) return;
10269 // If there was one break point object before replace with array.
10270 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010271 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010272 array->set(0, break_point_info->break_point_objects());
10273 array->set(1, *break_point_object);
10274 break_point_info->set_break_point_objects(*array);
10275 return;
10276 }
10277 // If there was more than one break point before extend array.
10278 Handle<FixedArray> old_array =
10279 Handle<FixedArray>(
10280 FixedArray::cast(break_point_info->break_point_objects()));
10281 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010282 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010283 for (int i = 0; i < old_array->length(); i++) {
10284 // If the break point was there before just ignore.
10285 if (old_array->get(i) == *break_point_object) return;
10286 new_array->set(i, old_array->get(i));
10287 }
10288 // Add the new break point.
10289 new_array->set(old_array->length(), *break_point_object);
10290 break_point_info->set_break_point_objects(*new_array);
10291}
10292
10293
10294bool BreakPointInfo::HasBreakPointObject(
10295 Handle<BreakPointInfo> break_point_info,
10296 Handle<Object> break_point_object) {
10297 // No break point.
10298 if (break_point_info->break_point_objects()->IsUndefined()) return false;
10299 // Single beak point.
10300 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10301 return break_point_info->break_point_objects() == *break_point_object;
10302 }
10303 // Multiple break points.
10304 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
10305 for (int i = 0; i < array->length(); i++) {
10306 if (array->get(i) == *break_point_object) {
10307 return true;
10308 }
10309 }
10310 return false;
10311}
10312
10313
10314// Get the number of break points.
10315int BreakPointInfo::GetBreakPointCount() {
10316 // No break point.
10317 if (break_point_objects()->IsUndefined()) return 0;
10318 // Single beak point.
10319 if (!break_point_objects()->IsFixedArray()) return 1;
10320 // Multiple break points.
10321 return FixedArray::cast(break_point_objects())->length();
10322}
10323#endif
10324
10325
10326} } // namespace v8::internal