blob: 8cb36e91f9a7b07984c13a8913769e637272d3b7 [file] [log] [blame]
Ben Murdochf87a2032010-10-22 12:50:53 +01001// Copyright 2010 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 }
Steve Block44f0eee2011-05-26 01:26:41 +0100116 if (IsUndefined() || IsNull()) {
117 return HeapObject::cast(this)->GetHeap()->false_value();
118 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 // Undetectable object is false
120 if (IsUndetectableObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100121 return HeapObject::cast(this)->GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 }
123 if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100124 return HeapObject::cast(this)->GetHeap()->ToBoolean(
125 String::cast(this)->length() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 }
127 if (IsHeapNumber()) {
128 return HeapNumber::cast(this)->HeapNumberToBoolean();
129 }
Steve Block44f0eee2011-05-26 01:26:41 +0100130 return Isolate::Current()->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000131}
132
133
134void Object::Lookup(String* name, LookupResult* result) {
135 if (IsJSObject()) return JSObject::cast(this)->Lookup(name, result);
136 Object* holder = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100138 Heap* heap = HeapObject::cast(this)->GetHeap();
139 Context* global_context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 holder = global_context->string_function()->instance_prototype();
141 } else if (IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100142 Heap* heap = Isolate::Current()->heap();
143 Context* global_context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000144 holder = global_context->number_function()->instance_prototype();
145 } else if (IsBoolean()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100146 Heap* heap = HeapObject::cast(this)->GetHeap();
147 Context* global_context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000148 holder = global_context->boolean_function()->instance_prototype();
149 }
150 ASSERT(holder != NULL); // Cannot handle null or undefined.
151 JSObject::cast(holder)->Lookup(name, result);
152}
153
154
John Reck59135872010-11-02 12:39:01 -0700155MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
156 String* name,
157 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 LookupResult result;
159 Lookup(name, &result);
John Reck59135872010-11-02 12:39:01 -0700160 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000161 ASSERT(*attributes <= ABSENT);
162 return value;
163}
164
165
John Reck59135872010-11-02 12:39:01 -0700166MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
167 Object* structure,
168 String* name,
169 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +0100170 Isolate* isolate = name->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 // To accommodate both the old and the new api we switch on the
172 // data structure used to store the callbacks. Eventually proxy
173 // callbacks should be phased out.
174 if (structure->IsProxy()) {
175 AccessorDescriptor* callback =
176 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
John Reck59135872010-11-02 12:39:01 -0700177 MaybeObject* value = (callback->getter)(receiver, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +0100178 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 return value;
180 }
181
182 // api style callbacks.
183 if (structure->IsAccessorInfo()) {
184 AccessorInfo* data = AccessorInfo::cast(structure);
185 Object* fun_obj = data->getter();
186 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
187 HandleScope scope;
188 JSObject* self = JSObject::cast(receiver);
189 JSObject* holder_handle = JSObject::cast(holder);
190 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100191 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
192 CustomArguments args(isolate, data->data(), self, holder_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 v8::AccessorInfo info(args.end());
194 v8::Handle<v8::Value> result;
195 {
196 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +0100197 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 result = call_fun(v8::Utils::ToLocal(key), info);
199 }
Steve Block44f0eee2011-05-26 01:26:41 +0100200 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
201 if (result.IsEmpty()) {
202 return isolate->heap()->undefined_value();
203 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 return *v8::Utils::OpenHandle(*result);
205 }
206
207 // __defineGetter__ callback
208 if (structure->IsFixedArray()) {
209 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
210 if (getter->IsJSFunction()) {
211 return Object::GetPropertyWithDefinedGetter(receiver,
212 JSFunction::cast(getter));
213 }
214 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +0100215 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000216 }
217
218 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +0100219 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000220}
221
222
John Reck59135872010-11-02 12:39:01 -0700223MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
224 JSFunction* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000225 HandleScope scope;
226 Handle<JSFunction> fun(JSFunction::cast(getter));
227 Handle<Object> self(receiver);
228#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100229 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 // Handle stepping into a getter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +0100231 if (debug->StepInActive()) {
232 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 }
234#endif
235 bool has_pending_exception;
236 Handle<Object> result =
237 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
238 // Check for pending exception and return the result.
239 if (has_pending_exception) return Failure::Exception();
240 return *result;
241}
242
243
244// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700245MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000246 Object* receiver,
247 LookupResult* result,
248 String* name,
249 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +0100250 Heap* heap = name->GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +0000251 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000252 switch (result->type()) {
253 case CALLBACKS: {
254 // Only allow API accessors.
255 Object* obj = result->GetCallbackObject();
256 if (obj->IsAccessorInfo()) {
257 AccessorInfo* info = AccessorInfo::cast(obj);
258 if (info->all_can_read()) {
259 *attributes = result->GetAttributes();
260 return GetPropertyWithCallback(receiver,
261 result->GetCallbackObject(),
262 name,
263 result->holder());
264 }
265 }
266 break;
267 }
268 case NORMAL:
269 case FIELD:
270 case CONSTANT_FUNCTION: {
271 // Search ALL_CAN_READ accessors in prototype chain.
272 LookupResult r;
273 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000274 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000275 return GetPropertyWithFailedAccessCheck(receiver,
276 &r,
277 name,
278 attributes);
279 }
280 break;
281 }
282 case INTERCEPTOR: {
283 // If the object has an interceptor, try real named properties.
284 // No access check in GetPropertyAttributeWithInterceptor.
285 LookupResult r;
286 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000287 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 return GetPropertyWithFailedAccessCheck(receiver,
289 &r,
290 name,
291 attributes);
292 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000293 break;
294 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000295 default:
296 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000297 }
298 }
299
300 // No accessible property found.
301 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100302 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
303 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000304}
305
306
307PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
308 Object* receiver,
309 LookupResult* result,
310 String* name,
311 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +0100312 Heap* heap = name->GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +0000313 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 switch (result->type()) {
315 case CALLBACKS: {
316 // Only allow API accessors.
317 Object* obj = result->GetCallbackObject();
318 if (obj->IsAccessorInfo()) {
319 AccessorInfo* info = AccessorInfo::cast(obj);
320 if (info->all_can_read()) {
321 return result->GetAttributes();
322 }
323 }
324 break;
325 }
326
327 case NORMAL:
328 case FIELD:
329 case CONSTANT_FUNCTION: {
330 if (!continue_search) break;
331 // Search ALL_CAN_READ accessors in prototype chain.
332 LookupResult r;
333 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000334 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000335 return GetPropertyAttributeWithFailedAccessCheck(receiver,
336 &r,
337 name,
338 continue_search);
339 }
340 break;
341 }
342
343 case INTERCEPTOR: {
344 // If the object has an interceptor, try real named properties.
345 // No access check in GetPropertyAttributeWithInterceptor.
346 LookupResult r;
347 if (continue_search) {
348 result->holder()->LookupRealNamedProperty(name, &r);
349 } else {
350 result->holder()->LocalLookupRealNamedProperty(name, &r);
351 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000352 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000353 return GetPropertyAttributeWithFailedAccessCheck(receiver,
354 &r,
355 name,
356 continue_search);
357 }
358 break;
359 }
360
Andrei Popescu402d9372010-02-26 13:31:12 +0000361 default:
362 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 }
364 }
365
Steve Block44f0eee2011-05-26 01:26:41 +0100366 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000367 return ABSENT;
368}
369
370
Steve Blocka7e24c12009-10-30 11:49:00 +0000371Object* JSObject::GetNormalizedProperty(LookupResult* result) {
372 ASSERT(!HasFastProperties());
373 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
374 if (IsGlobalObject()) {
375 value = JSGlobalPropertyCell::cast(value)->value();
376 }
377 ASSERT(!value->IsJSGlobalPropertyCell());
378 return value;
379}
380
381
382Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
383 ASSERT(!HasFastProperties());
384 if (IsGlobalObject()) {
385 JSGlobalPropertyCell* cell =
386 JSGlobalPropertyCell::cast(
387 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
388 cell->set_value(value);
389 } else {
390 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
391 }
392 return value;
393}
394
395
John Reck59135872010-11-02 12:39:01 -0700396MaybeObject* JSObject::SetNormalizedProperty(String* name,
397 Object* value,
398 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 ASSERT(!HasFastProperties());
Steve Block44f0eee2011-05-26 01:26:41 +0100400 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 int entry = property_dictionary()->FindEntry(name);
402 if (entry == StringDictionary::kNotFound) {
403 Object* store_value = value;
404 if (IsGlobalObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100405 MaybeObject* maybe_store_value =
406 heap->AllocateJSGlobalPropertyCell(value);
407 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000408 }
John Reck59135872010-11-02 12:39:01 -0700409 Object* dict;
410 { MaybeObject* maybe_dict =
411 property_dictionary()->Add(name, store_value, details);
412 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
413 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000414 set_properties(StringDictionary::cast(dict));
415 return value;
416 }
417 // Preserve enumeration index.
418 details = PropertyDetails(details.attributes(),
419 details.type(),
420 property_dictionary()->DetailsAt(entry).index());
421 if (IsGlobalObject()) {
422 JSGlobalPropertyCell* cell =
423 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
424 cell->set_value(value);
425 // Please note we have to update the property details.
426 property_dictionary()->DetailsAtPut(entry, details);
427 } else {
428 property_dictionary()->SetEntry(entry, name, value, details);
429 }
430 return value;
431}
432
433
John Reck59135872010-11-02 12:39:01 -0700434MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000435 ASSERT(!HasFastProperties());
Steve Block44f0eee2011-05-26 01:26:41 +0100436 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000437 StringDictionary* dictionary = property_dictionary();
438 int entry = dictionary->FindEntry(name);
439 if (entry != StringDictionary::kNotFound) {
440 // If we have a global object set the cell to the hole.
441 if (IsGlobalObject()) {
442 PropertyDetails details = dictionary->DetailsAt(entry);
443 if (details.IsDontDelete()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100444 if (mode != FORCE_DELETION) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000445 // When forced to delete global properties, we have to make a
446 // map change to invalidate any ICs that think they can load
447 // from the DontDelete cell without checking if it contains
448 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700449 Object* new_map;
450 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
451 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
452 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000453 set_map(Map::cast(new_map));
454 }
455 JSGlobalPropertyCell* cell =
456 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Steve Block44f0eee2011-05-26 01:26:41 +0100457 cell->set_value(heap->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000458 dictionary->DetailsAtPut(entry, details.AsDeleted());
459 } else {
460 return dictionary->DeleteProperty(entry, mode);
461 }
462 }
Steve Block44f0eee2011-05-26 01:26:41 +0100463 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000464}
465
466
467bool JSObject::IsDirty() {
468 Object* cons_obj = map()->constructor();
469 if (!cons_obj->IsJSFunction())
470 return true;
471 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100472 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000473 return true;
474 // If the object is fully fast case and has the same map it was
475 // created with then no changes can have been made to it.
476 return map() != fun->initial_map()
477 || !HasFastElements()
478 || !HasFastProperties();
479}
480
481
John Reck59135872010-11-02 12:39:01 -0700482MaybeObject* Object::GetProperty(Object* receiver,
483 LookupResult* result,
484 String* name,
485 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000486 // Make sure that the top context does not change when doing
487 // callbacks or interceptor calls.
488 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100489 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000490
491 // Traverse the prototype chain from the current object (this) to
492 // the holder and check for access rights. This avoid traversing the
493 // objects more than once in case of interceptors, because the
494 // holder will always be the interceptor holder and the search may
495 // only continue with a current object just after the interceptor
496 // holder in the prototype chain.
Steve Block44f0eee2011-05-26 01:26:41 +0100497 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000498 for (Object* current = this; true; current = current->GetPrototype()) {
499 if (current->IsAccessCheckNeeded()) {
500 // Check if we're allowed to read from the current object. Note
501 // that even though we may not actually end up loading the named
502 // property from the current object, we still check that we have
503 // access to it.
504 JSObject* checked = JSObject::cast(current);
Steve Block44f0eee2011-05-26 01:26:41 +0100505 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000506 return checked->GetPropertyWithFailedAccessCheck(receiver,
507 result,
508 name,
509 attributes);
510 }
511 }
512 // Stop traversing the chain once we reach the last object in the
513 // chain; either the holder of the result or null in case of an
514 // absent property.
515 if (current == last) break;
516 }
517
518 if (!result->IsProperty()) {
519 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100520 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000521 }
522 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000523 Object* value;
524 JSObject* holder = result->holder();
525 switch (result->type()) {
526 case NORMAL:
527 value = holder->GetNormalizedProperty(result);
528 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100529 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000530 case FIELD:
531 value = holder->FastPropertyAt(result->GetFieldIndex());
532 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100533 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 case CONSTANT_FUNCTION:
535 return result->GetConstantFunction();
536 case CALLBACKS:
537 return GetPropertyWithCallback(receiver,
538 result->GetCallbackObject(),
539 name,
540 holder);
541 case INTERCEPTOR: {
542 JSObject* recvr = JSObject::cast(receiver);
543 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
544 }
545 default:
546 UNREACHABLE();
547 return NULL;
548 }
549}
550
551
John Reck59135872010-11-02 12:39:01 -0700552MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100553 if (IsJSObject()) {
554 return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
555 }
556
557 Object* holder = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +0100558 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100559 if (IsString()) {
560 holder = global_context->string_function()->instance_prototype();
561 } else if (IsNumber()) {
562 holder = global_context->number_function()->instance_prototype();
563 } else if (IsBoolean()) {
564 holder = global_context->boolean_function()->instance_prototype();
565 } else {
566 // Undefined and null have no indexed properties.
567 ASSERT(IsUndefined() || IsNull());
Steve Block44f0eee2011-05-26 01:26:41 +0100568 return HEAP->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100569 }
570
571 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000572}
573
574
575Object* Object::GetPrototype() {
576 // The object is either a number, a string, a boolean, or a real JS object.
577 if (IsJSObject()) return JSObject::cast(this)->map()->prototype();
Steve Block44f0eee2011-05-26 01:26:41 +0100578 Heap* heap = Isolate::Current()->heap();
579 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000580
581 if (IsNumber()) return context->number_function()->instance_prototype();
582 if (IsString()) return context->string_function()->instance_prototype();
583 if (IsBoolean()) {
584 return context->boolean_function()->instance_prototype();
585 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100586 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000587 }
588}
589
590
Ben Murdochb0fe1622011-05-05 13:52:32 +0100591void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 HeapStringAllocator allocator;
593 StringStream accumulator(&allocator);
594 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100595 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000596}
597
598
599void Object::ShortPrint(StringStream* accumulator) {
600 if (IsSmi()) {
601 Smi::cast(this)->SmiPrint(accumulator);
602 } else if (IsFailure()) {
603 Failure::cast(this)->FailurePrint(accumulator);
604 } else {
605 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
606 }
607}
608
609
Ben Murdochb0fe1622011-05-05 13:52:32 +0100610void Smi::SmiPrint(FILE* out) {
611 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000612}
613
614
615void Smi::SmiPrint(StringStream* accumulator) {
616 accumulator->Add("%d", value());
617}
618
619
620void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000621 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000622}
623
624
Ben Murdochb0fe1622011-05-05 13:52:32 +0100625void Failure::FailurePrint(FILE* out) {
626 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000627}
628
629
Steve Blocka7e24c12009-10-30 11:49:00 +0000630// Should a word be prefixed by 'a' or 'an' in order to read naturally in
631// English? Returns false for non-ASCII or words that don't start with
632// a capital letter. The a/an rule follows pronunciation in English.
633// We don't use the BBC's overcorrect "an historic occasion" though if
634// you speak a dialect you may well say "an 'istoric occasion".
635static bool AnWord(String* str) {
636 if (str->length() == 0) return false; // A nothing.
637 int c0 = str->Get(0);
638 int c1 = str->length() > 1 ? str->Get(1) : 0;
639 if (c0 == 'U') {
640 if (c1 > 'Z') {
641 return true; // An Umpire, but a UTF8String, a U.
642 }
643 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
644 return true; // An Ape, an ABCBook.
645 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
646 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
647 c0 == 'S' || c0 == 'X')) {
648 return true; // An MP3File, an M.
649 }
650 return false;
651}
652
653
John Reck59135872010-11-02 12:39:01 -0700654MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000655#ifdef DEBUG
656 // Do not attempt to flatten in debug mode when allocation is not
657 // allowed. This is to avoid an assertion failure when allocating.
658 // Flattening strings is the only case where we always allow
659 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100660 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000661#endif
662
Steve Block44f0eee2011-05-26 01:26:41 +0100663 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000664 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000665 case kConsStringTag: {
666 ConsString* cs = ConsString::cast(this);
667 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100668 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 }
670 // There's little point in putting the flat string in new space if the
671 // cons string is in old space. It can never get GCed until there is
672 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100673 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 int len = length();
675 Object* object;
676 String* result;
677 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100678 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700679 if (!maybe_object->ToObject(&object)) return maybe_object;
680 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000681 result = String::cast(object);
682 String* first = cs->first();
683 int first_length = first->length();
684 char* dest = SeqAsciiString::cast(result)->GetChars();
685 WriteToFlat(first, dest, 0, first_length);
686 String* second = cs->second();
687 WriteToFlat(second,
688 dest + first_length,
689 0,
690 len - first_length);
691 } else {
John Reck59135872010-11-02 12:39:01 -0700692 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100693 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700694 if (!maybe_object->ToObject(&object)) return maybe_object;
695 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000696 result = String::cast(object);
697 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
698 String* first = cs->first();
699 int first_length = first->length();
700 WriteToFlat(first, dest, 0, first_length);
701 String* second = cs->second();
702 WriteToFlat(second,
703 dest + first_length,
704 0,
705 len - first_length);
706 }
707 cs->set_first(result);
Steve Block44f0eee2011-05-26 01:26:41 +0100708 cs->set_second(heap->empty_string());
Leon Clarkef7060e22010-06-03 12:02:55 +0100709 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000710 }
711 default:
712 return this;
713 }
714}
715
716
717bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100718 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100719 // prohibited by the API.
720 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000721#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000722 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 // Assert that the resource and the string are equivalent.
724 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100725 ScopedVector<uc16> smart_chars(this->length());
726 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
727 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100729 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000730 }
731#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100732 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000733 int size = this->Size(); // Byte size of the original string.
734 if (size < ExternalString::kSize) {
735 // The string is too small to fit an external String in its place. This can
736 // only happen for zero length strings.
737 return false;
738 }
739 ASSERT(size >= ExternalString::kSize);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100740 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000741 bool is_symbol = this->IsSymbol();
742 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000743 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000744
745 // Morph the object to an external string by adjusting the map and
746 // reinitializing the fields.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100747 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100748 heap->external_string_with_ascii_data_map() :
749 heap->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000750 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
751 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000752 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 self->set_resource(resource);
754 // Additionally make the object into an external symbol if the original string
755 // was a symbol to start with.
756 if (is_symbol) {
757 self->Hash(); // Force regeneration of the hash value.
758 // Now morph this external string into a external symbol.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100759 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100760 heap->external_symbol_with_ascii_data_map() :
761 heap->external_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000762 }
763
764 // Fill the remainder of the string with dead wood.
765 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100766 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 return true;
768}
769
770
771bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
772#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000773 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000774 // Assert that the resource and the string are equivalent.
775 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100776 ScopedVector<char> smart_chars(this->length());
777 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
778 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100780 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 }
782#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100783 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000784 int size = this->Size(); // Byte size of the original string.
785 if (size < ExternalString::kSize) {
786 // The string is too small to fit an external String in its place. This can
787 // only happen for zero length strings.
788 return false;
789 }
790 ASSERT(size >= ExternalString::kSize);
791 bool is_symbol = this->IsSymbol();
792 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000793 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000794
795 // Morph the object to an external string by adjusting the map and
796 // reinitializing the fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100797 this->set_map(heap->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000798 ExternalAsciiString* self = ExternalAsciiString::cast(this);
799 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000800 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000801 self->set_resource(resource);
802 // Additionally make the object into an external symbol if the original string
803 // was a symbol to start with.
804 if (is_symbol) {
805 self->Hash(); // Force regeneration of the hash value.
806 // Now morph this external string into a external symbol.
Steve Block44f0eee2011-05-26 01:26:41 +0100807 this->set_map(heap->external_ascii_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 }
809
810 // Fill the remainder of the string with dead wood.
811 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100812 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 return true;
814}
815
816
817void String::StringShortPrint(StringStream* accumulator) {
818 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +0000819 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 accumulator->Add("<Very long string[%u]>", len);
821 return;
822 }
823
824 if (!LooksValid()) {
825 accumulator->Add("<Invalid String>");
826 return;
827 }
828
829 StringInputBuffer buf(this);
830
831 bool truncated = false;
832 if (len > kMaxShortPrintLength) {
833 len = kMaxShortPrintLength;
834 truncated = true;
835 }
836 bool ascii = true;
837 for (int i = 0; i < len; i++) {
838 int c = buf.GetNext();
839
840 if (c < 32 || c >= 127) {
841 ascii = false;
842 }
843 }
844 buf.Reset(this);
845 if (ascii) {
846 accumulator->Add("<String[%u]: ", length());
847 for (int i = 0; i < len; i++) {
848 accumulator->Put(buf.GetNext());
849 }
850 accumulator->Put('>');
851 } else {
852 // Backslash indicates that the string contains control
853 // characters and that backslashes are therefore escaped.
854 accumulator->Add("<String[%u]\\: ", length());
855 for (int i = 0; i < len; i++) {
856 int c = buf.GetNext();
857 if (c == '\n') {
858 accumulator->Add("\\n");
859 } else if (c == '\r') {
860 accumulator->Add("\\r");
861 } else if (c == '\\') {
862 accumulator->Add("\\\\");
863 } else if (c < 32 || c > 126) {
864 accumulator->Add("\\x%02x", c);
865 } else {
866 accumulator->Put(c);
867 }
868 }
869 if (truncated) {
870 accumulator->Put('.');
871 accumulator->Put('.');
872 accumulator->Put('.');
873 }
874 accumulator->Put('>');
875 }
876 return;
877}
878
879
880void JSObject::JSObjectShortPrint(StringStream* accumulator) {
881 switch (map()->instance_type()) {
882 case JS_ARRAY_TYPE: {
883 double length = JSArray::cast(this)->length()->Number();
884 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
885 break;
886 }
887 case JS_REGEXP_TYPE: {
888 accumulator->Add("<JS RegExp>");
889 break;
890 }
891 case JS_FUNCTION_TYPE: {
892 Object* fun_name = JSFunction::cast(this)->shared()->name();
893 bool printed = false;
894 if (fun_name->IsString()) {
895 String* str = String::cast(fun_name);
896 if (str->length() > 0) {
897 accumulator->Add("<JS Function ");
898 accumulator->Put(str);
899 accumulator->Put('>');
900 printed = true;
901 }
902 }
903 if (!printed) {
904 accumulator->Add("<JS Function>");
905 }
906 break;
907 }
908 // All other JSObjects are rather similar to each other (JSObject,
909 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
910 default: {
Steve Block44f0eee2011-05-26 01:26:41 +0100911 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 Object* constructor = map()->constructor();
913 bool printed = false;
914 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100915 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
917 } else {
918 bool global_object = IsJSGlobalProxy();
919 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100920 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
922 } else {
923 Object* constructor_name =
924 JSFunction::cast(constructor)->shared()->name();
925 if (constructor_name->IsString()) {
926 String* str = String::cast(constructor_name);
927 if (str->length() > 0) {
928 bool vowel = AnWord(str);
929 accumulator->Add("<%sa%s ",
930 global_object ? "Global Object: " : "",
931 vowel ? "n" : "");
932 accumulator->Put(str);
933 accumulator->Put('>');
934 printed = true;
935 }
936 }
937 }
938 }
939 if (!printed) {
940 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
941 }
942 }
943 if (IsJSValue()) {
944 accumulator->Add(" value = ");
945 JSValue::cast(this)->value()->ShortPrint(accumulator);
946 }
947 accumulator->Put('>');
948 break;
949 }
950 }
951}
952
953
954void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +0100955 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
956 Heap* heap = GetHeap();
957 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000958 accumulator->Add("!!!INVALID POINTER!!!");
959 return;
960 }
Steve Block44f0eee2011-05-26 01:26:41 +0100961 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000962 accumulator->Add("!!!INVALID MAP!!!");
963 return;
964 }
965
966 accumulator->Add("%p ", this);
967
968 if (IsString()) {
969 String::cast(this)->StringShortPrint(accumulator);
970 return;
971 }
972 if (IsJSObject()) {
973 JSObject::cast(this)->JSObjectShortPrint(accumulator);
974 return;
975 }
976 switch (map()->instance_type()) {
977 case MAP_TYPE:
978 accumulator->Add("<Map>");
979 break;
980 case FIXED_ARRAY_TYPE:
981 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
982 break;
983 case BYTE_ARRAY_TYPE:
984 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
985 break;
Steve Block44f0eee2011-05-26 01:26:41 +0100986 case EXTERNAL_PIXEL_ARRAY_TYPE:
987 accumulator->Add("<ExternalPixelArray[%u]>",
988 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000989 break;
Steve Block3ce2e202009-11-05 08:53:23 +0000990 case EXTERNAL_BYTE_ARRAY_TYPE:
991 accumulator->Add("<ExternalByteArray[%u]>",
992 ExternalByteArray::cast(this)->length());
993 break;
994 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
995 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
996 ExternalUnsignedByteArray::cast(this)->length());
997 break;
998 case EXTERNAL_SHORT_ARRAY_TYPE:
999 accumulator->Add("<ExternalShortArray[%u]>",
1000 ExternalShortArray::cast(this)->length());
1001 break;
1002 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1003 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1004 ExternalUnsignedShortArray::cast(this)->length());
1005 break;
1006 case EXTERNAL_INT_ARRAY_TYPE:
1007 accumulator->Add("<ExternalIntArray[%u]>",
1008 ExternalIntArray::cast(this)->length());
1009 break;
1010 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1011 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1012 ExternalUnsignedIntArray::cast(this)->length());
1013 break;
1014 case EXTERNAL_FLOAT_ARRAY_TYPE:
1015 accumulator->Add("<ExternalFloatArray[%u]>",
1016 ExternalFloatArray::cast(this)->length());
1017 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001018 case SHARED_FUNCTION_INFO_TYPE:
1019 accumulator->Add("<SharedFunctionInfo>");
1020 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001021 case JS_MESSAGE_OBJECT_TYPE:
1022 accumulator->Add("<JSMessageObject>");
1023 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001024#define MAKE_STRUCT_CASE(NAME, Name, name) \
1025 case NAME##_TYPE: \
1026 accumulator->Put('<'); \
1027 accumulator->Add(#Name); \
1028 accumulator->Put('>'); \
1029 break;
1030 STRUCT_LIST(MAKE_STRUCT_CASE)
1031#undef MAKE_STRUCT_CASE
1032 case CODE_TYPE:
1033 accumulator->Add("<Code>");
1034 break;
1035 case ODDBALL_TYPE: {
1036 if (IsUndefined())
1037 accumulator->Add("<undefined>");
1038 else if (IsTheHole())
1039 accumulator->Add("<the hole>");
1040 else if (IsNull())
1041 accumulator->Add("<null>");
1042 else if (IsTrue())
1043 accumulator->Add("<true>");
1044 else if (IsFalse())
1045 accumulator->Add("<false>");
1046 else
1047 accumulator->Add("<Odd Oddball>");
1048 break;
1049 }
1050 case HEAP_NUMBER_TYPE:
1051 accumulator->Add("<Number: ");
1052 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1053 accumulator->Put('>');
1054 break;
1055 case PROXY_TYPE:
1056 accumulator->Add("<Proxy>");
1057 break;
1058 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1059 accumulator->Add("Cell for ");
1060 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1061 break;
1062 default:
1063 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1064 break;
1065 }
1066}
1067
1068
Steve Blocka7e24c12009-10-30 11:49:00 +00001069void HeapObject::Iterate(ObjectVisitor* v) {
1070 // Handle header
1071 IteratePointer(v, kMapOffset);
1072 // Handle object body
1073 Map* m = map();
1074 IterateBody(m->instance_type(), SizeFromMap(m), v);
1075}
1076
1077
1078void HeapObject::IterateBody(InstanceType type, int object_size,
1079 ObjectVisitor* v) {
1080 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1081 // During GC, the map pointer field is encoded.
1082 if (type < FIRST_NONSTRING_TYPE) {
1083 switch (type & kStringRepresentationMask) {
1084 case kSeqStringTag:
1085 break;
1086 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001087 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001089 case kExternalStringTag:
1090 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1091 reinterpret_cast<ExternalAsciiString*>(this)->
1092 ExternalAsciiStringIterateBody(v);
1093 } else {
1094 reinterpret_cast<ExternalTwoByteString*>(this)->
1095 ExternalTwoByteStringIterateBody(v);
1096 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001097 break;
1098 }
1099 return;
1100 }
1101
1102 switch (type) {
1103 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001104 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 break;
1106 case JS_OBJECT_TYPE:
1107 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1108 case JS_VALUE_TYPE:
1109 case JS_ARRAY_TYPE:
1110 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001111 case JS_GLOBAL_PROXY_TYPE:
1112 case JS_GLOBAL_OBJECT_TYPE:
1113 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001114 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001115 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001116 break;
Steve Block791712a2010-08-27 10:21:07 +01001117 case JS_FUNCTION_TYPE:
1118 reinterpret_cast<JSFunction*>(this)
1119 ->JSFunctionIterateBody(object_size, v);
1120 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001121 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001122 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001123 break;
1124 case PROXY_TYPE:
1125 reinterpret_cast<Proxy*>(this)->ProxyIterateBody(v);
1126 break;
1127 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001128 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001129 break;
1130 case CODE_TYPE:
1131 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1132 break;
1133 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001134 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001135 break;
1136 case HEAP_NUMBER_TYPE:
1137 case FILLER_TYPE:
1138 case BYTE_ARRAY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001139 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001140 case EXTERNAL_BYTE_ARRAY_TYPE:
1141 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1142 case EXTERNAL_SHORT_ARRAY_TYPE:
1143 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1144 case EXTERNAL_INT_ARRAY_TYPE:
1145 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1146 case EXTERNAL_FLOAT_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001147 break;
Iain Merrick75681382010-08-19 15:07:18 +01001148 case SHARED_FUNCTION_INFO_TYPE:
1149 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001150 break;
Iain Merrick75681382010-08-19 15:07:18 +01001151
Steve Blocka7e24c12009-10-30 11:49:00 +00001152#define MAKE_STRUCT_CASE(NAME, Name, name) \
1153 case NAME##_TYPE:
1154 STRUCT_LIST(MAKE_STRUCT_CASE)
1155#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001156 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001157 break;
1158 default:
1159 PrintF("Unknown type: %d\n", type);
1160 UNREACHABLE();
1161 }
1162}
1163
1164
Steve Blocka7e24c12009-10-30 11:49:00 +00001165Object* HeapNumber::HeapNumberToBoolean() {
1166 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001167#if __BYTE_ORDER == __LITTLE_ENDIAN
1168 union IeeeDoubleLittleEndianArchType u;
1169#elif __BYTE_ORDER == __BIG_ENDIAN
1170 union IeeeDoubleBigEndianArchType u;
1171#endif
1172 u.d = value();
1173 if (u.bits.exp == 2047) {
1174 // Detect NaN for IEEE double precision floating point.
1175 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001176 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001177 }
Iain Merrick75681382010-08-19 15:07:18 +01001178 if (u.bits.exp == 0) {
1179 // Detect +0, and -0 for IEEE double precision floating point.
1180 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001181 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001182 }
Steve Block44f0eee2011-05-26 01:26:41 +01001183 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001184}
1185
1186
Ben Murdochb0fe1622011-05-05 13:52:32 +01001187void HeapNumber::HeapNumberPrint(FILE* out) {
1188 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001189}
1190
1191
1192void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1193 // The Windows version of vsnprintf can allocate when printing a %g string
1194 // into a buffer that may not be big enough. We don't want random memory
1195 // allocation when producing post-crash stack traces, so we print into a
1196 // buffer that is plenty big enough for any floating point number, then
1197 // print that using vsnprintf (which may truncate but never allocate if
1198 // there is no more space in the buffer).
1199 EmbeddedVector<char, 100> buffer;
1200 OS::SNPrintF(buffer, "%.16g", Number());
1201 accumulator->Add("%s", buffer.start());
1202}
1203
1204
1205String* JSObject::class_name() {
1206 if (IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001207 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001208 }
1209 if (map()->constructor()->IsJSFunction()) {
1210 JSFunction* constructor = JSFunction::cast(map()->constructor());
1211 return String::cast(constructor->shared()->instance_class_name());
1212 }
1213 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001214 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001215}
1216
1217
1218String* JSObject::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001219 if (map()->constructor()->IsJSFunction()) {
1220 JSFunction* constructor = JSFunction::cast(map()->constructor());
1221 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001222 if (name->length() > 0) return name;
1223 String* inferred_name = constructor->shared()->inferred_name();
1224 if (inferred_name->length() > 0) return inferred_name;
1225 Object* proto = GetPrototype();
1226 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001227 }
1228 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001229 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001230}
1231
1232
John Reck59135872010-11-02 12:39:01 -07001233MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1234 String* name,
1235 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001236 int index = new_map->PropertyIndexFor(name);
1237 if (map()->unused_property_fields() == 0) {
1238 ASSERT(map()->unused_property_fields() == 0);
1239 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001240 Object* values;
1241 { MaybeObject* maybe_values =
1242 properties()->CopySize(properties()->length() + new_unused + 1);
1243 if (!maybe_values->ToObject(&values)) return maybe_values;
1244 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001245 set_properties(FixedArray::cast(values));
1246 }
1247 set_map(new_map);
1248 return FastPropertyAtPut(index, value);
1249}
1250
1251
John Reck59135872010-11-02 12:39:01 -07001252MaybeObject* JSObject::AddFastProperty(String* name,
1253 Object* value,
1254 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001255 ASSERT(!IsJSGlobalProxy());
1256
Steve Blocka7e24c12009-10-30 11:49:00 +00001257 // Normalize the object if the name is an actual string (not the
1258 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001259 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001260 StringInputBuffer buffer(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001261 if (!isolate->scanner_constants()->IsIdentifier(&buffer)
1262 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001263 Object* obj;
1264 { MaybeObject* maybe_obj =
1265 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1266 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1267 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 return AddSlowProperty(name, value, attributes);
1269 }
1270
1271 DescriptorArray* old_descriptors = map()->instance_descriptors();
1272 // Compute the new index for new field.
1273 int index = map()->NextFreePropertyIndex();
1274
1275 // Allocate new instance descriptors with (name, index) added
1276 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001277 Object* new_descriptors;
1278 { MaybeObject* maybe_new_descriptors =
1279 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1280 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1281 return maybe_new_descriptors;
1282 }
1283 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001284
Steve Block44f0eee2011-05-26 01:26:41 +01001285 // Only allow map transition if the object isn't the global object and there
1286 // is not a transition for the name, or there's a transition for the name but
1287 // it's unrelated to properties.
1288 int descriptor_index = old_descriptors->Search(name);
1289
1290 // External array transitions are stored in the descriptor for property "",
1291 // which is not a identifier and should have forced a switch to slow
1292 // properties above.
1293 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1294 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1295 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1296 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001298 can_insert_transition &&
1299 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001300
1301 ASSERT(index < map()->inobject_properties() ||
1302 (index - map()->inobject_properties()) < properties()->length() ||
1303 map()->unused_property_fields() == 0);
1304 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001305 Object* r;
1306 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1307 if (!maybe_r->ToObject(&r)) return maybe_r;
1308 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 Map* new_map = Map::cast(r);
1310 if (allow_map_transition) {
1311 // Allocate new instance descriptors for the old map with map transition.
1312 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001313 Object* r;
1314 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1315 if (!maybe_r->ToObject(&r)) return maybe_r;
1316 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 old_descriptors = DescriptorArray::cast(r);
1318 }
1319
1320 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001321 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001322 Object* obj;
1323 { MaybeObject* maybe_obj =
1324 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1325 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1326 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001327 return AddSlowProperty(name, value, attributes);
1328 }
1329 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001330 Object* values;
1331 { MaybeObject* maybe_values =
1332 properties()->CopySize(properties()->length() + kFieldsAdded);
1333 if (!maybe_values->ToObject(&values)) return maybe_values;
1334 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 set_properties(FixedArray::cast(values));
1336 new_map->set_unused_property_fields(kFieldsAdded - 1);
1337 } else {
1338 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1339 }
1340 // We have now allocated all the necessary objects.
1341 // All the changes can be applied at once, so they are atomic.
1342 map()->set_instance_descriptors(old_descriptors);
1343 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1344 set_map(new_map);
1345 return FastPropertyAtPut(index, value);
1346}
1347
1348
John Reck59135872010-11-02 12:39:01 -07001349MaybeObject* JSObject::AddConstantFunctionProperty(
1350 String* name,
1351 JSFunction* function,
1352 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01001353 Heap* heap = GetHeap();
1354 ASSERT(!heap->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001355
Steve Blocka7e24c12009-10-30 11:49:00 +00001356 // Allocate new instance descriptors with (name, function) added
1357 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001358 Object* new_descriptors;
1359 { MaybeObject* maybe_new_descriptors =
1360 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1361 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1362 return maybe_new_descriptors;
1363 }
1364 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001365
1366 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001367 Object* new_map;
1368 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1369 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1370 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001371
1372 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1373 Map::cast(new_map)->set_instance_descriptors(descriptors);
1374 Map* old_map = map();
1375 set_map(Map::cast(new_map));
1376
1377 // If the old map is the global object map (from new Object()),
1378 // then transitions are not added to it, so we are done.
Steve Block44f0eee2011-05-26 01:26:41 +01001379 if (old_map == heap->isolate()->context()->global_context()->
1380 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 return function;
1382 }
1383
1384 // Do not add CONSTANT_TRANSITIONS to global objects
1385 if (IsGlobalObject()) {
1386 return function;
1387 }
1388
1389 // Add a CONSTANT_TRANSITION descriptor to the old map,
1390 // so future assignments to this property on other objects
1391 // of the same type will create a normal field, not a constant function.
1392 // Don't do this for special properties, with non-trival attributes.
1393 if (attributes != NONE) {
1394 return function;
1395 }
Iain Merrick75681382010-08-19 15:07:18 +01001396 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001397 { MaybeObject* maybe_new_descriptors =
1398 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1399 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1400 // We have accomplished the main goal, so return success.
1401 return function;
1402 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001403 }
1404 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1405
1406 return function;
1407}
1408
1409
1410// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001411MaybeObject* JSObject::AddSlowProperty(String* name,
1412 Object* value,
1413 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001414 ASSERT(!HasFastProperties());
Steve Block44f0eee2011-05-26 01:26:41 +01001415 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 StringDictionary* dict = property_dictionary();
1417 Object* store_value = value;
1418 if (IsGlobalObject()) {
1419 // In case name is an orphaned property reuse the cell.
1420 int entry = dict->FindEntry(name);
1421 if (entry != StringDictionary::kNotFound) {
1422 store_value = dict->ValueAt(entry);
1423 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1424 // Assign an enumeration index to the property and update
1425 // SetNextEnumerationIndex.
1426 int index = dict->NextEnumerationIndex();
1427 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1428 dict->SetNextEnumerationIndex(index + 1);
1429 dict->SetEntry(entry, name, store_value, details);
1430 return value;
1431 }
John Reck59135872010-11-02 12:39:01 -07001432 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001433 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001434 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1435 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1437 }
1438 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001439 Object* result;
1440 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1441 if (!maybe_result->ToObject(&result)) return maybe_result;
1442 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001443 if (dict != result) set_properties(StringDictionary::cast(result));
1444 return value;
1445}
1446
1447
John Reck59135872010-11-02 12:39:01 -07001448MaybeObject* JSObject::AddProperty(String* name,
1449 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001450 PropertyAttributes attributes,
1451 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001452 ASSERT(!IsJSGlobalProxy());
Steve Block44f0eee2011-05-26 01:26:41 +01001453 Heap* heap = GetHeap();
Steve Block8defd9f2010-07-08 12:39:36 +01001454 if (!map()->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001455 if (strict_mode == kNonStrictMode) {
1456 return heap->undefined_value();
1457 } else {
1458 Handle<Object> args[1] = {Handle<String>(name)};
1459 return heap->isolate()->Throw(
1460 *FACTORY->NewTypeError("object_not_extensible",
1461 HandleVector(args, 1)));
1462 }
Steve Block8defd9f2010-07-08 12:39:36 +01001463 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 if (HasFastProperties()) {
1465 // Ensure the descriptor array does not get too big.
1466 if (map()->instance_descriptors()->number_of_descriptors() <
1467 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001468 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001469 return AddConstantFunctionProperty(name,
1470 JSFunction::cast(value),
1471 attributes);
1472 } else {
1473 return AddFastProperty(name, value, attributes);
1474 }
1475 } else {
1476 // Normalize the object to prevent very large instance descriptors.
1477 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001478 Object* obj;
1479 { MaybeObject* maybe_obj =
1480 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1481 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1482 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 }
1484 }
1485 return AddSlowProperty(name, value, attributes);
1486}
1487
1488
John Reck59135872010-11-02 12:39:01 -07001489MaybeObject* JSObject::SetPropertyPostInterceptor(
1490 String* name,
1491 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001492 PropertyAttributes attributes,
1493 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001494 // Check local property, ignore interceptor.
1495 LookupResult result;
1496 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001497 if (result.IsFound()) {
1498 // An existing property, a map transition or a null descriptor was
1499 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001500 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001501 }
1502 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001503 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001504}
1505
1506
John Reck59135872010-11-02 12:39:01 -07001507MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1508 Object* value,
1509 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001510 StringDictionary* dictionary = property_dictionary();
1511 int old_index = dictionary->FindEntry(name);
1512 int new_enumeration_index = 0; // 0 means "Use the next available index."
1513 if (old_index != -1) {
1514 // All calls to ReplaceSlowProperty have had all transitions removed.
1515 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1516 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1517 }
1518
1519 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1520 return SetNormalizedProperty(name, value, new_details);
1521}
1522
Steve Blockd0582a62009-12-15 09:54:21 +00001523
John Reck59135872010-11-02 12:39:01 -07001524MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 String* name,
1526 Object* new_value,
1527 PropertyAttributes attributes) {
1528 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001529 Object* result;
1530 { MaybeObject* maybe_result =
1531 ConvertDescriptorToField(name, new_value, attributes);
1532 if (!maybe_result->ToObject(&result)) return maybe_result;
1533 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001534 // If we get to this point we have succeeded - do not return failure
1535 // after this point. Later stuff is optional.
1536 if (!HasFastProperties()) {
1537 return result;
1538 }
1539 // Do not add transitions to the map of "new Object()".
Steve Block44f0eee2011-05-26 01:26:41 +01001540 if (map() == GetHeap()->isolate()->context()->global_context()->
1541 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001542 return result;
1543 }
1544
1545 MapTransitionDescriptor transition(name,
1546 map(),
1547 attributes);
John Reck59135872010-11-02 12:39:01 -07001548 Object* new_descriptors;
1549 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1550 CopyInsert(&transition, KEEP_TRANSITIONS);
1551 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1552 return result; // Yes, return _result_.
1553 }
1554 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001555 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1556 return result;
1557}
1558
1559
John Reck59135872010-11-02 12:39:01 -07001560MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1561 Object* new_value,
1562 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001564 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001565 Object* obj;
1566 { MaybeObject* maybe_obj =
1567 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1568 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1569 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 return ReplaceSlowProperty(name, new_value, attributes);
1571 }
1572
1573 int index = map()->NextFreePropertyIndex();
1574 FieldDescriptor new_field(name, index, attributes);
1575 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001576 Object* descriptors_unchecked;
1577 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1578 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1579 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1580 return maybe_descriptors_unchecked;
1581 }
1582 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001583 DescriptorArray* new_descriptors =
1584 DescriptorArray::cast(descriptors_unchecked);
1585
1586 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001587 Object* new_map_unchecked;
1588 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1589 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1590 return maybe_new_map_unchecked;
1591 }
1592 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001593 Map* new_map = Map::cast(new_map_unchecked);
1594 new_map->set_instance_descriptors(new_descriptors);
1595
1596 // Make new properties array if necessary.
1597 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1598 int new_unused_property_fields = map()->unused_property_fields() - 1;
1599 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001600 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001601 Object* new_properties_object;
1602 { MaybeObject* maybe_new_properties_object =
1603 properties()->CopySize(properties()->length() + kFieldsAdded);
1604 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1605 return maybe_new_properties_object;
1606 }
1607 }
1608 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001609 }
1610
1611 // Update pointers to commit changes.
1612 // Object points to the new map.
1613 new_map->set_unused_property_fields(new_unused_property_fields);
1614 set_map(new_map);
1615 if (new_properties) {
1616 set_properties(FixedArray::cast(new_properties));
1617 }
1618 return FastPropertyAtPut(index, new_value);
1619}
1620
1621
1622
John Reck59135872010-11-02 12:39:01 -07001623MaybeObject* JSObject::SetPropertyWithInterceptor(
1624 String* name,
1625 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001626 PropertyAttributes attributes,
1627 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001628 Isolate* isolate = GetIsolate();
1629 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 Handle<JSObject> this_handle(this);
1631 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001632 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001633 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1634 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001635 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1636 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001637 v8::AccessorInfo info(args.end());
1638 v8::NamedPropertySetter setter =
1639 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1640 v8::Handle<v8::Value> result;
1641 {
1642 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001643 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001644 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001645 isolate->heap()->undefined_value() :
1646 value,
1647 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001648 result = setter(v8::Utils::ToLocal(name_handle),
1649 v8::Utils::ToLocal(value_unhole),
1650 info);
1651 }
Steve Block44f0eee2011-05-26 01:26:41 +01001652 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001653 if (!result.IsEmpty()) return *value_handle;
1654 }
John Reck59135872010-11-02 12:39:01 -07001655 MaybeObject* raw_result =
1656 this_handle->SetPropertyPostInterceptor(*name_handle,
1657 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001658 attributes,
1659 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001660 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001661 return raw_result;
1662}
1663
1664
John Reck59135872010-11-02 12:39:01 -07001665MaybeObject* JSObject::SetProperty(String* name,
1666 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001667 PropertyAttributes attributes,
1668 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 LookupResult result;
1670 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001671 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001672}
1673
1674
John Reck59135872010-11-02 12:39:01 -07001675MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1676 String* name,
1677 Object* value,
1678 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01001679 Isolate* isolate = GetIsolate();
1680 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001681
1682 // We should never get here to initialize a const with the hole
1683 // value since a const declaration would conflict with the setter.
1684 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001685 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001686
1687 // To accommodate both the old and the new api we switch on the
1688 // data structure used to store the callbacks. Eventually proxy
1689 // callbacks should be phased out.
1690 if (structure->IsProxy()) {
1691 AccessorDescriptor* callback =
1692 reinterpret_cast<AccessorDescriptor*>(Proxy::cast(structure)->proxy());
John Reck59135872010-11-02 12:39:01 -07001693 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001694 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 if (obj->IsFailure()) return obj;
1696 return *value_handle;
1697 }
1698
1699 if (structure->IsAccessorInfo()) {
1700 // api style callbacks
1701 AccessorInfo* data = AccessorInfo::cast(structure);
1702 Object* call_obj = data->setter();
1703 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1704 if (call_fun == NULL) return value;
1705 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001706 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1707 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001708 v8::AccessorInfo info(args.end());
1709 {
1710 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001711 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 call_fun(v8::Utils::ToLocal(key),
1713 v8::Utils::ToLocal(value_handle),
1714 info);
1715 }
Steve Block44f0eee2011-05-26 01:26:41 +01001716 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001717 return *value_handle;
1718 }
1719
1720 if (structure->IsFixedArray()) {
1721 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1722 if (setter->IsJSFunction()) {
1723 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1724 } else {
1725 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001726 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001727 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01001728 return isolate->Throw(
1729 *isolate->factory()->NewTypeError("no_setter_in_callback",
1730 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001731 }
1732 }
1733
1734 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01001735 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001736}
1737
1738
John Reck59135872010-11-02 12:39:01 -07001739MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1740 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01001741 Isolate* isolate = GetIsolate();
1742 Handle<Object> value_handle(value, isolate);
1743 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1744 Handle<JSObject> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001745#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01001746 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00001747 // Handle stepping into a setter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01001748 if (debug->StepInActive()) {
1749 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001750 }
1751#endif
1752 bool has_pending_exception;
1753 Object** argv[] = { value_handle.location() };
1754 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1755 // Check for pending exception and return the result.
1756 if (has_pending_exception) return Failure::Exception();
1757 return *value_handle;
1758}
1759
1760
1761void JSObject::LookupCallbackSetterInPrototypes(String* name,
1762 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001763 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001764 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001765 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001766 pt = pt->GetPrototype()) {
1767 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001768 if (result->IsProperty()) {
1769 if (result->IsReadOnly()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001770 result->NotFound();
1771 return;
1772 }
1773 if (result->type() == CALLBACKS) {
1774 return;
1775 }
1776 }
1777 }
1778 result->NotFound();
1779}
1780
1781
Steve Block1e0659c2011-05-24 12:43:12 +01001782MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
1783 Object* value,
1784 bool* found) {
Steve Block44f0eee2011-05-26 01:26:41 +01001785 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001787 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001788 pt = pt->GetPrototype()) {
1789 if (!JSObject::cast(pt)->HasDictionaryElements()) {
1790 continue;
1791 }
1792 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1793 int entry = dictionary->FindEntry(index);
1794 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001795 PropertyDetails details = dictionary->DetailsAt(entry);
1796 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001797 *found = true;
1798 return SetElementWithCallback(
1799 dictionary->ValueAt(entry), index, value, JSObject::cast(pt));
Steve Blocka7e24c12009-10-30 11:49:00 +00001800 }
1801 }
1802 }
Steve Block1e0659c2011-05-24 12:43:12 +01001803 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001804 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001805}
1806
1807
1808void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1809 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001810 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001811 if (number != DescriptorArray::kNotFound) {
1812 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1813 } else {
1814 result->NotFound();
1815 }
1816}
1817
1818
Ben Murdochb0fe1622011-05-05 13:52:32 +01001819void Map::LookupInDescriptors(JSObject* holder,
1820 String* name,
1821 LookupResult* result) {
1822 DescriptorArray* descriptors = instance_descriptors();
Steve Block44f0eee2011-05-26 01:26:41 +01001823 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1824 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001825 if (number == DescriptorLookupCache::kAbsent) {
1826 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001827 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001828 }
1829 if (number != DescriptorArray::kNotFound) {
1830 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1831 } else {
1832 result->NotFound();
1833 }
1834}
1835
1836
Steve Block44f0eee2011-05-26 01:26:41 +01001837MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
1838 bool safe_to_add_transition) {
1839 DescriptorArray* descriptors = instance_descriptors();
1840 String* external_array_sentinel_name = GetIsolate()->heap()->empty_symbol();
1841
1842 if (safe_to_add_transition) {
1843 // It's only safe to manipulate the descriptor array if it would be
1844 // safe to add a transition.
1845
1846 ASSERT(!is_shared()); // no transitions can be added to shared maps.
1847 // Check if the external array transition already exists.
1848 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1849 int index = cache->Lookup(descriptors, external_array_sentinel_name);
1850 if (index == DescriptorLookupCache::kAbsent) {
1851 index = descriptors->Search(external_array_sentinel_name);
1852 cache->Update(descriptors,
1853 external_array_sentinel_name,
1854 index);
1855 }
1856
1857 // If the transition already exists, check the type. If there is a match,
1858 // return it.
1859 if (index != DescriptorArray::kNotFound) {
1860 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
1861 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
1862 details.array_type() == array_type) {
1863 return descriptors->GetValue(index);
1864 } else {
1865 safe_to_add_transition = false;
1866 }
1867 }
1868 }
1869
1870 // No transition to an existing external array map. Make a new one.
1871 Object* obj;
1872 { MaybeObject* maybe_map = CopyDropTransitions();
1873 if (!maybe_map->ToObject(&obj)) return maybe_map;
1874 }
1875 Map* new_map = Map::cast(obj);
1876
1877 new_map->set_has_fast_elements(false);
1878 new_map->set_has_external_array_elements(true);
1879 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
1880
1881 // Only remember the map transition if the object's map is NOT equal to the
1882 // global object_function's map and there is not an already existing
1883 // non-matching external array transition.
1884 bool allow_map_transition =
1885 safe_to_add_transition &&
1886 (GetIsolate()->context()->global_context()->object_function()->map() !=
1887 map());
1888 if (allow_map_transition) {
1889 // Allocate new instance descriptors for the old map with map transition.
1890 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
1891 Map::cast(new_map),
1892 array_type);
1893 Object* new_descriptors;
1894 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
1895 &desc,
1896 KEEP_TRANSITIONS);
1897 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1898 return maybe_new_descriptors;
1899 }
1900 descriptors = DescriptorArray::cast(new_descriptors);
1901 set_instance_descriptors(descriptors);
1902 }
1903
1904 return new_map;
1905}
1906
1907
Steve Blocka7e24c12009-10-30 11:49:00 +00001908void JSObject::LocalLookupRealNamedProperty(String* name,
1909 LookupResult* result) {
1910 if (IsJSGlobalProxy()) {
1911 Object* proto = GetPrototype();
1912 if (proto->IsNull()) return result->NotFound();
1913 ASSERT(proto->IsJSGlobalObject());
1914 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
1915 }
1916
1917 if (HasFastProperties()) {
1918 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001919 if (result->IsFound()) {
1920 // A property, a map transition or a null descriptor was found.
1921 // We return all of these result types because
1922 // LocalLookupRealNamedProperty is used when setting properties
1923 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00001924 ASSERT(result->holder() == this && result->type() != NORMAL);
1925 // Disallow caching for uninitialized constants. These can only
1926 // occur as fields.
1927 if (result->IsReadOnly() && result->type() == FIELD &&
1928 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
1929 result->DisallowCaching();
1930 }
1931 return;
1932 }
1933 } else {
1934 int entry = property_dictionary()->FindEntry(name);
1935 if (entry != StringDictionary::kNotFound) {
1936 Object* value = property_dictionary()->ValueAt(entry);
1937 if (IsGlobalObject()) {
1938 PropertyDetails d = property_dictionary()->DetailsAt(entry);
1939 if (d.IsDeleted()) {
1940 result->NotFound();
1941 return;
1942 }
1943 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001944 }
1945 // Make sure to disallow caching for uninitialized constants
1946 // found in the dictionary-mode objects.
1947 if (value->IsTheHole()) result->DisallowCaching();
1948 result->DictionaryResult(this, entry);
1949 return;
1950 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001951 }
1952 result->NotFound();
1953}
1954
1955
1956void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
1957 LocalLookupRealNamedProperty(name, result);
1958 if (result->IsProperty()) return;
1959
1960 LookupRealNamedPropertyInPrototypes(name, result);
1961}
1962
1963
1964void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
1965 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001966 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001967 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001968 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001969 pt = JSObject::cast(pt)->GetPrototype()) {
1970 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001971 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001972 }
1973 result->NotFound();
1974}
1975
1976
1977// We only need to deal with CALLBACKS and INTERCEPTORS
John Reck59135872010-11-02 12:39:01 -07001978MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
1979 String* name,
Ben Murdoch086aeea2011-05-13 15:57:08 +01001980 Object* value,
1981 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01001982 Heap* heap = GetHeap();
Ben Murdoch086aeea2011-05-13 15:57:08 +01001983 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001984 LookupCallbackSetterInPrototypes(name, result);
1985 }
1986
1987 if (result->IsProperty()) {
1988 if (!result->IsReadOnly()) {
1989 switch (result->type()) {
1990 case CALLBACKS: {
1991 Object* obj = result->GetCallbackObject();
1992 if (obj->IsAccessorInfo()) {
1993 AccessorInfo* info = AccessorInfo::cast(obj);
1994 if (info->all_can_write()) {
1995 return SetPropertyWithCallback(result->GetCallbackObject(),
1996 name,
1997 value,
1998 result->holder());
1999 }
2000 }
2001 break;
2002 }
2003 case INTERCEPTOR: {
2004 // Try lookup real named properties. Note that only property can be
2005 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2006 LookupResult r;
2007 LookupRealNamedProperty(name, &r);
2008 if (r.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002009 return SetPropertyWithFailedAccessCheck(&r, name, value,
2010 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00002011 }
2012 break;
2013 }
2014 default: {
2015 break;
2016 }
2017 }
2018 }
2019 }
2020
Iain Merrick75681382010-08-19 15:07:18 +01002021 HandleScope scope;
2022 Handle<Object> value_handle(value);
Steve Block44f0eee2011-05-26 01:26:41 +01002023 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002024 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002025}
2026
2027
John Reck59135872010-11-02 12:39:01 -07002028MaybeObject* JSObject::SetProperty(LookupResult* result,
2029 String* name,
2030 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002031 PropertyAttributes attributes,
2032 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002033 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002034 // Make sure that the top context does not change when doing callbacks or
2035 // interceptor calls.
2036 AssertNoContextChange ncc;
2037
Steve Blockd0582a62009-12-15 09:54:21 +00002038 // Optimization for 2-byte strings often used as keys in a decompression
2039 // dictionary. We make these short keys into symbols to avoid constantly
2040 // reallocating them.
2041 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002042 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002043 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002044 if (maybe_symbol_version->ToObject(&symbol_version)) {
2045 name = String::cast(symbol_version);
2046 }
2047 }
Steve Blockd0582a62009-12-15 09:54:21 +00002048 }
2049
Steve Blocka7e24c12009-10-30 11:49:00 +00002050 // Check access rights if needed.
2051 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002052 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002053 return SetPropertyWithFailedAccessCheck(result, name, value, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00002054 }
2055
2056 if (IsJSGlobalProxy()) {
2057 Object* proto = GetPrototype();
2058 if (proto->IsNull()) return value;
2059 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002060 return JSObject::cast(proto)->SetProperty(
2061 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002062 }
2063
2064 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2065 // We could not find a local property so let's check whether there is an
2066 // accessor that wants to handle the property.
2067 LookupResult accessor_result;
2068 LookupCallbackSetterInPrototypes(name, &accessor_result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002069 if (accessor_result.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002070 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2071 name,
2072 value,
2073 accessor_result.holder());
2074 }
2075 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002076 if (!result->IsFound()) {
2077 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002078 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002079 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002080 if (result->IsReadOnly() && result->IsProperty()) {
2081 if (strict_mode == kStrictMode) {
2082 HandleScope scope;
2083 Handle<String> key(name);
2084 Handle<Object> holder(this);
2085 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002086 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2087 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002088 } else {
2089 return value;
2090 }
2091 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002092 // This is a real property that is not read-only, or it is a
2093 // transition or null descriptor and there are no setters in the prototypes.
2094 switch (result->type()) {
2095 case NORMAL:
2096 return SetNormalizedProperty(result, value);
2097 case FIELD:
2098 return FastPropertyAtPut(result->GetFieldIndex(), value);
2099 case MAP_TRANSITION:
2100 if (attributes == result->GetAttributes()) {
2101 // Only use map transition if the attributes match.
2102 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2103 name,
2104 value);
2105 }
2106 return ConvertDescriptorToField(name, value, attributes);
2107 case CONSTANT_FUNCTION:
2108 // Only replace the function if necessary.
2109 if (value == result->GetConstantFunction()) return value;
2110 // Preserve the attributes of this existing property.
2111 attributes = result->GetAttributes();
2112 return ConvertDescriptorToField(name, value, attributes);
2113 case CALLBACKS:
2114 return SetPropertyWithCallback(result->GetCallbackObject(),
2115 name,
2116 value,
2117 result->holder());
2118 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002119 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002120 case CONSTANT_TRANSITION: {
2121 // If the same constant function is being added we can simply
2122 // transition to the target map.
2123 Map* target_map = result->GetTransitionMap();
2124 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2125 int number = target_descriptors->SearchWithCache(name);
2126 ASSERT(number != DescriptorArray::kNotFound);
2127 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2128 JSFunction* function =
2129 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002130 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002131 if (value == function) {
2132 set_map(target_map);
2133 return value;
2134 }
2135 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2136 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002137 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002138 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002139 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002140 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002141 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2142 default:
2143 UNREACHABLE();
2144 }
2145 UNREACHABLE();
2146 return value;
2147}
2148
2149
2150// Set a real local property, even if it is READ_ONLY. If the property is not
2151// present, add it with attributes NONE. This code is an exact clone of
2152// SetProperty, with the check for IsReadOnly and the check for a
2153// callback setter removed. The two lines looking up the LookupResult
2154// result are also added. If one of the functions is changed, the other
2155// should be.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002156MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002157 String* name,
2158 Object* value,
2159 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002160 Heap* heap = GetHeap();
2161
Steve Blocka7e24c12009-10-30 11:49:00 +00002162 // Make sure that the top context does not change when doing callbacks or
2163 // interceptor calls.
2164 AssertNoContextChange ncc;
Andrei Popescu402d9372010-02-26 13:31:12 +00002165 LookupResult result;
2166 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002167 // Check access rights if needed.
2168 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002169 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002170 return SetPropertyWithFailedAccessCheck(&result, name, value, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00002171 }
2172
2173 if (IsJSGlobalProxy()) {
2174 Object* proto = GetPrototype();
2175 if (proto->IsNull()) return value;
2176 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002177 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002178 name,
2179 value,
2180 attributes);
2181 }
2182
2183 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002184 if (!result.IsFound()) {
2185 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002186 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002187 }
Steve Block6ded16b2010-05-10 14:33:55 +01002188
Andrei Popescu402d9372010-02-26 13:31:12 +00002189 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2190
Steve Blocka7e24c12009-10-30 11:49:00 +00002191 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002192 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002194 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002195 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002196 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002197 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002198 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002199 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002200 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002201 name,
2202 value);
2203 }
2204 return ConvertDescriptorToField(name, value, attributes);
2205 case CONSTANT_FUNCTION:
2206 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002207 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002208 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002209 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002210 return ConvertDescriptorToField(name, value, attributes);
2211 case CALLBACKS:
2212 case INTERCEPTOR:
2213 // Override callback in clone
2214 return ConvertDescriptorToField(name, value, attributes);
2215 case CONSTANT_TRANSITION:
2216 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2217 // if the value is a function.
2218 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2219 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002220 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002221 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2222 default:
2223 UNREACHABLE();
2224 }
2225 UNREACHABLE();
2226 return value;
2227}
2228
2229
2230PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2231 JSObject* receiver,
2232 String* name,
2233 bool continue_search) {
2234 // Check local property, ignore interceptor.
2235 LookupResult result;
2236 LocalLookupRealNamedProperty(name, &result);
2237 if (result.IsProperty()) return result.GetAttributes();
2238
2239 if (continue_search) {
2240 // Continue searching via the prototype chain.
2241 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002242 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002243 return JSObject::cast(pt)->
2244 GetPropertyAttributeWithReceiver(receiver, name);
2245 }
2246 }
2247 return ABSENT;
2248}
2249
2250
2251PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2252 JSObject* receiver,
2253 String* name,
2254 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002255 Isolate* isolate = GetIsolate();
2256
Steve Blocka7e24c12009-10-30 11:49:00 +00002257 // Make sure that the top context does not change when doing
2258 // callbacks or interceptor calls.
2259 AssertNoContextChange ncc;
2260
Steve Block44f0eee2011-05-26 01:26:41 +01002261 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002262 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2263 Handle<JSObject> receiver_handle(receiver);
2264 Handle<JSObject> holder_handle(this);
2265 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002266 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002267 v8::AccessorInfo info(args.end());
2268 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002269 v8::NamedPropertyQuery query =
2270 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002271 LOG(isolate,
2272 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002273 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002274 {
2275 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002276 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002277 result = query(v8::Utils::ToLocal(name_handle), info);
2278 }
2279 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002280 ASSERT(result->IsInt32());
2281 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002282 }
2283 } else if (!interceptor->getter()->IsUndefined()) {
2284 v8::NamedPropertyGetter getter =
2285 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002286 LOG(isolate,
2287 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002288 v8::Handle<v8::Value> result;
2289 {
2290 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002291 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002292 result = getter(v8::Utils::ToLocal(name_handle), info);
2293 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002294 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002295 }
2296 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2297 *name_handle,
2298 continue_search);
2299}
2300
2301
2302PropertyAttributes JSObject::GetPropertyAttributeWithReceiver(
2303 JSObject* receiver,
2304 String* key) {
2305 uint32_t index = 0;
2306 if (key->AsArrayIndex(&index)) {
2307 if (HasElementWithReceiver(receiver, index)) return NONE;
2308 return ABSENT;
2309 }
2310 // Named property.
2311 LookupResult result;
2312 Lookup(key, &result);
2313 return GetPropertyAttribute(receiver, &result, key, true);
2314}
2315
2316
2317PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
2318 LookupResult* result,
2319 String* name,
2320 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002321 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002322 // Check access rights if needed.
2323 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002324 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002325 return GetPropertyAttributeWithFailedAccessCheck(receiver,
2326 result,
2327 name,
2328 continue_search);
2329 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002330 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002331 switch (result->type()) {
2332 case NORMAL: // fall through
2333 case FIELD:
2334 case CONSTANT_FUNCTION:
2335 case CALLBACKS:
2336 return result->GetAttributes();
2337 case INTERCEPTOR:
2338 return result->holder()->
2339 GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002340 default:
2341 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002342 }
2343 }
2344 return ABSENT;
2345}
2346
2347
2348PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
2349 // Check whether the name is an array index.
2350 uint32_t index = 0;
2351 if (name->AsArrayIndex(&index)) {
2352 if (HasLocalElement(index)) return NONE;
2353 return ABSENT;
2354 }
2355 // Named property.
2356 LookupResult result;
2357 LocalLookup(name, &result);
2358 return GetPropertyAttribute(this, &result, name, false);
2359}
2360
2361
John Reck59135872010-11-02 12:39:01 -07002362MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2363 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002364 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002365 Map* fast = obj->map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002366 int index = Hash(fast) % kEntries;
2367 Object* result = get(index);
2368 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002369#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002370 if (FLAG_enable_slow_asserts) {
2371 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002372 Object* fresh;
2373 { MaybeObject* maybe_fresh =
2374 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2375 if (maybe_fresh->ToObject(&fresh)) {
2376 ASSERT(memcmp(Map::cast(fresh)->address(),
2377 Map::cast(result)->address(),
2378 Map::kSize) == 0);
2379 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002380 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002381 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002382#endif
2383 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002384 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002385
John Reck59135872010-11-02 12:39:01 -07002386 { MaybeObject* maybe_result =
2387 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2388 if (!maybe_result->ToObject(&result)) return maybe_result;
2389 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002390 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002391 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002392
2393 return result;
2394}
2395
2396
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002397void NormalizedMapCache::Clear() {
2398 int entries = length();
2399 for (int i = 0; i != entries; i++) {
2400 set_undefined(i);
2401 }
2402}
2403
2404
2405int NormalizedMapCache::Hash(Map* fast) {
2406 // For performance reasons we only hash the 3 most variable fields of a map:
2407 // constructor, prototype and bit_field2.
2408
2409 // Shift away the tag.
2410 int hash = (static_cast<uint32_t>(
2411 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2);
2412
2413 // XOR-ing the prototype and constructor directly yields too many zero bits
2414 // when the two pointers are close (which is fairly common).
2415 // To avoid this we shift the prototype 4 bits relatively to the constructor.
2416 hash ^= (static_cast<uint32_t>(
2417 reinterpret_cast<uintptr_t>(fast->prototype())) << 2);
2418
2419 return hash ^ (hash >> 16) ^ fast->bit_field2();
2420}
2421
2422
2423bool NormalizedMapCache::CheckHit(Map* slow,
2424 Map* fast,
2425 PropertyNormalizationMode mode) {
2426#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002427 slow->SharedMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002428#endif
2429 return
2430 slow->constructor() == fast->constructor() &&
2431 slow->prototype() == fast->prototype() &&
2432 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
2433 0 :
2434 fast->inobject_properties()) &&
2435 slow->instance_type() == fast->instance_type() &&
2436 slow->bit_field() == fast->bit_field() &&
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002437 (slow->bit_field2() & ~(1<<Map::kIsShared)) == fast->bit_field2();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002438}
2439
2440
John Reck59135872010-11-02 12:39:01 -07002441MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002442 if (map()->is_shared()) {
2443 // Fast case maps are never marked as shared.
2444 ASSERT(!HasFastProperties());
2445 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002446 Object* obj;
2447 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2448 UNIQUE_NORMALIZED_MAP);
2449 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2450 }
Steve Block44f0eee2011-05-26 01:26:41 +01002451 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002452
2453 set_map(Map::cast(obj));
2454 }
2455 return map()->UpdateCodeCache(name, code);
2456}
2457
2458
John Reck59135872010-11-02 12:39:01 -07002459MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2460 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002461 if (!HasFastProperties()) return this;
2462
2463 // The global object is always normalized.
2464 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002465 // JSGlobalProxy must never be normalized
2466 ASSERT(!IsJSGlobalProxy());
2467
Steve Block44f0eee2011-05-26 01:26:41 +01002468 Heap* heap = GetHeap();
2469
Steve Blocka7e24c12009-10-30 11:49:00 +00002470 // Allocate new content.
2471 int property_count = map()->NumberOfDescribedProperties();
2472 if (expected_additional_properties > 0) {
2473 property_count += expected_additional_properties;
2474 } else {
2475 property_count += 2; // Make space for two more properties.
2476 }
John Reck59135872010-11-02 12:39:01 -07002477 Object* obj;
2478 { MaybeObject* maybe_obj =
2479 StringDictionary::Allocate(property_count);
2480 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2481 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002482 StringDictionary* dictionary = StringDictionary::cast(obj);
2483
2484 DescriptorArray* descs = map()->instance_descriptors();
2485 for (int i = 0; i < descs->number_of_descriptors(); i++) {
2486 PropertyDetails details = descs->GetDetails(i);
2487 switch (details.type()) {
2488 case CONSTANT_FUNCTION: {
2489 PropertyDetails d =
2490 PropertyDetails(details.attributes(), NORMAL, details.index());
2491 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07002492 Object* result;
2493 { MaybeObject* maybe_result =
2494 dictionary->Add(descs->GetKey(i), value, d);
2495 if (!maybe_result->ToObject(&result)) return maybe_result;
2496 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002497 dictionary = StringDictionary::cast(result);
2498 break;
2499 }
2500 case FIELD: {
2501 PropertyDetails d =
2502 PropertyDetails(details.attributes(), NORMAL, details.index());
2503 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07002504 Object* result;
2505 { MaybeObject* maybe_result =
2506 dictionary->Add(descs->GetKey(i), value, d);
2507 if (!maybe_result->ToObject(&result)) return maybe_result;
2508 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002509 dictionary = StringDictionary::cast(result);
2510 break;
2511 }
2512 case CALLBACKS: {
2513 PropertyDetails d =
2514 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2515 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07002516 Object* result;
2517 { MaybeObject* maybe_result =
2518 dictionary->Add(descs->GetKey(i), value, d);
2519 if (!maybe_result->ToObject(&result)) return maybe_result;
2520 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002521 dictionary = StringDictionary::cast(result);
2522 break;
2523 }
2524 case MAP_TRANSITION:
2525 case CONSTANT_TRANSITION:
2526 case NULL_DESCRIPTOR:
2527 case INTERCEPTOR:
2528 break;
2529 default:
2530 UNREACHABLE();
2531 }
2532 }
2533
2534 // Copy the next enumeration index from instance descriptor.
2535 int index = map()->instance_descriptors()->NextEnumerationIndex();
2536 dictionary->SetNextEnumerationIndex(index);
2537
Steve Block44f0eee2011-05-26 01:26:41 +01002538 { MaybeObject* maybe_obj = heap->isolate()->context()->global_context()->
2539 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07002540 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2541 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002542 Map* new_map = Map::cast(obj);
2543
Steve Blocka7e24c12009-10-30 11:49:00 +00002544 // We have now successfully allocated all the necessary objects.
2545 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002546
2547 // Resize the object in the heap if necessary.
2548 int new_instance_size = new_map->instance_size();
2549 int instance_size_delta = map()->instance_size() - new_instance_size;
2550 ASSERT(instance_size_delta >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01002551 heap->CreateFillerObjectAt(this->address() + new_instance_size,
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002552 instance_size_delta);
2553
Steve Blocka7e24c12009-10-30 11:49:00 +00002554 set_map(new_map);
Steve Block44f0eee2011-05-26 01:26:41 +01002555 map()->set_instance_descriptors(heap->empty_descriptor_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00002556
2557 set_properties(dictionary);
2558
Steve Block44f0eee2011-05-26 01:26:41 +01002559 heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002560
2561#ifdef DEBUG
2562 if (FLAG_trace_normalization) {
2563 PrintF("Object properties have been normalized:\n");
2564 Print();
2565 }
2566#endif
2567 return this;
2568}
2569
2570
John Reck59135872010-11-02 12:39:01 -07002571MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002572 if (HasFastProperties()) return this;
2573 ASSERT(!IsGlobalObject());
2574 return property_dictionary()->
2575 TransformPropertiesToFastFor(this, unused_property_fields);
2576}
2577
2578
John Reck59135872010-11-02 12:39:01 -07002579MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002580 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00002581 if (HasDictionaryElements()) return this;
Steve Block8defd9f2010-07-08 12:39:36 +01002582 ASSERT(map()->has_fast_elements());
2583
John Reck59135872010-11-02 12:39:01 -07002584 Object* obj;
2585 { MaybeObject* maybe_obj = map()->GetSlowElementsMap();
2586 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2587 }
Steve Block8defd9f2010-07-08 12:39:36 +01002588 Map* new_map = Map::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00002589
2590 // Get number of entries.
2591 FixedArray* array = FixedArray::cast(elements());
2592
2593 // Compute the effective length.
2594 int length = IsJSArray() ?
2595 Smi::cast(JSArray::cast(this)->length())->value() :
2596 array->length();
John Reck59135872010-11-02 12:39:01 -07002597 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length);
2598 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2599 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002600 NumberDictionary* dictionary = NumberDictionary::cast(obj);
2601 // Copy entries.
2602 for (int i = 0; i < length; i++) {
2603 Object* value = array->get(i);
2604 if (!value->IsTheHole()) {
2605 PropertyDetails details = PropertyDetails(NONE, NORMAL);
John Reck59135872010-11-02 12:39:01 -07002606 Object* result;
2607 { MaybeObject* maybe_result =
2608 dictionary->AddNumberEntry(i, array->get(i), details);
2609 if (!maybe_result->ToObject(&result)) return maybe_result;
2610 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002611 dictionary = NumberDictionary::cast(result);
2612 }
2613 }
Steve Block8defd9f2010-07-08 12:39:36 +01002614 // Switch to using the dictionary as the backing storage for
2615 // elements. Set the new map first to satify the elements type
2616 // assert in set_elements().
2617 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00002618 set_elements(dictionary);
2619
Steve Block44f0eee2011-05-26 01:26:41 +01002620 new_map->GetHeap()->isolate()->counters()->elements_to_dictionary()->
2621 Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002622
2623#ifdef DEBUG
2624 if (FLAG_trace_normalization) {
2625 PrintF("Object elements have been normalized:\n");
2626 Print();
2627 }
2628#endif
2629
2630 return this;
2631}
2632
2633
John Reck59135872010-11-02 12:39:01 -07002634MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
2635 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002636 // Check local property, ignore interceptor.
Steve Block44f0eee2011-05-26 01:26:41 +01002637 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002638 LookupResult result;
2639 LocalLookupRealNamedProperty(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01002640 if (!result.IsProperty()) return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002641
2642 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002643 Object* obj;
2644 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2645 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2646 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002647
2648 return DeleteNormalizedProperty(name, mode);
2649}
2650
2651
John Reck59135872010-11-02 12:39:01 -07002652MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01002653 Isolate* isolate = GetIsolate();
2654 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002655 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2656 Handle<String> name_handle(name);
2657 Handle<JSObject> this_handle(this);
2658 if (!interceptor->deleter()->IsUndefined()) {
2659 v8::NamedPropertyDeleter deleter =
2660 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01002661 LOG(isolate,
2662 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2663 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002664 v8::AccessorInfo info(args.end());
2665 v8::Handle<v8::Boolean> result;
2666 {
2667 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002668 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002669 result = deleter(v8::Utils::ToLocal(name_handle), info);
2670 }
Steve Block44f0eee2011-05-26 01:26:41 +01002671 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002672 if (!result.IsEmpty()) {
2673 ASSERT(result->IsBoolean());
2674 return *v8::Utils::OpenHandle(*result);
2675 }
2676 }
John Reck59135872010-11-02 12:39:01 -07002677 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00002678 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01002679 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002680 return raw_result;
2681}
2682
2683
John Reck59135872010-11-02 12:39:01 -07002684MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
2685 DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002686 Heap* heap = GetHeap();
2687 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00002688 switch (GetElementsKind()) {
2689 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07002690 Object* obj;
2691 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2692 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2693 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002694 uint32_t length = IsJSArray() ?
2695 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2696 static_cast<uint32_t>(FixedArray::cast(elements())->length());
2697 if (index < length) {
2698 FixedArray::cast(elements())->set_the_hole(index);
2699 }
2700 break;
2701 }
2702 case DICTIONARY_ELEMENTS: {
2703 NumberDictionary* dictionary = element_dictionary();
2704 int entry = dictionary->FindEntry(index);
2705 if (entry != NumberDictionary::kNotFound) {
2706 return dictionary->DeleteProperty(entry, mode);
2707 }
2708 break;
2709 }
2710 default:
2711 UNREACHABLE();
2712 break;
2713 }
Steve Block44f0eee2011-05-26 01:26:41 +01002714 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002715}
2716
2717
John Reck59135872010-11-02 12:39:01 -07002718MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01002719 Isolate* isolate = GetIsolate();
2720 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002721 // Make sure that the top context does not change when doing
2722 // callbacks or interceptor calls.
2723 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01002724 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002725 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01002726 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002727 v8::IndexedPropertyDeleter deleter =
2728 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
2729 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01002730 LOG(isolate,
2731 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
2732 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002733 v8::AccessorInfo info(args.end());
2734 v8::Handle<v8::Boolean> result;
2735 {
2736 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002737 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002738 result = deleter(index, info);
2739 }
Steve Block44f0eee2011-05-26 01:26:41 +01002740 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002741 if (!result.IsEmpty()) {
2742 ASSERT(result->IsBoolean());
2743 return *v8::Utils::OpenHandle(*result);
2744 }
John Reck59135872010-11-02 12:39:01 -07002745 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00002746 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01002747 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002748 return raw_result;
2749}
2750
2751
John Reck59135872010-11-02 12:39:01 -07002752MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002753 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002754 // Check access rights if needed.
2755 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002756 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
2757 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2758 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002759 }
2760
2761 if (IsJSGlobalProxy()) {
2762 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002763 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002764 ASSERT(proto->IsJSGlobalObject());
2765 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
2766 }
2767
2768 if (HasIndexedInterceptor()) {
2769 // Skip interceptor if forcing deletion.
2770 if (mode == FORCE_DELETION) {
2771 return DeleteElementPostInterceptor(index, mode);
2772 }
2773 return DeleteElementWithInterceptor(index);
2774 }
2775
2776 switch (GetElementsKind()) {
2777 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07002778 Object* obj;
2779 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2780 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2781 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002782 uint32_t length = IsJSArray() ?
2783 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2784 static_cast<uint32_t>(FixedArray::cast(elements())->length());
2785 if (index < length) {
2786 FixedArray::cast(elements())->set_the_hole(index);
2787 }
2788 break;
2789 }
Steve Block44f0eee2011-05-26 01:26:41 +01002790 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00002791 case EXTERNAL_BYTE_ELEMENTS:
2792 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2793 case EXTERNAL_SHORT_ELEMENTS:
2794 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2795 case EXTERNAL_INT_ELEMENTS:
2796 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2797 case EXTERNAL_FLOAT_ELEMENTS:
2798 // Pixel and external array elements cannot be deleted. Just
2799 // silently ignore here.
Steve Blocka7e24c12009-10-30 11:49:00 +00002800 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002801 case DICTIONARY_ELEMENTS: {
2802 NumberDictionary* dictionary = element_dictionary();
2803 int entry = dictionary->FindEntry(index);
2804 if (entry != NumberDictionary::kNotFound) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002805 Object* result = dictionary->DeleteProperty(entry, mode);
Steve Block44f0eee2011-05-26 01:26:41 +01002806 if (mode == STRICT_DELETION && result ==
2807 isolate->heap()->false_value()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002808 // In strict mode, deleting a non-configurable property throws
2809 // exception. dictionary->DeleteProperty will return false_value()
2810 // if a non-configurable property is being deleted.
2811 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01002812 Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002813 Handle<Object> args[2] = { i, Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01002814 return isolate->Throw(*isolate->factory()->NewTypeError(
2815 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002816 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002817 }
2818 break;
2819 }
2820 default:
2821 UNREACHABLE();
2822 break;
2823 }
Steve Block44f0eee2011-05-26 01:26:41 +01002824 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002825}
2826
2827
John Reck59135872010-11-02 12:39:01 -07002828MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002829 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002830 // ECMA-262, 3rd, 8.6.2.5
2831 ASSERT(name->IsString());
2832
2833 // Check access rights if needed.
2834 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002835 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
2836 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2837 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002838 }
2839
2840 if (IsJSGlobalProxy()) {
2841 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002842 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002843 ASSERT(proto->IsJSGlobalObject());
2844 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
2845 }
2846
2847 uint32_t index = 0;
2848 if (name->AsArrayIndex(&index)) {
2849 return DeleteElement(index, mode);
2850 } else {
2851 LookupResult result;
2852 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01002853 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002854 // Ignore attributes if forcing a deletion.
2855 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002856 if (mode == STRICT_DELETION) {
2857 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01002858 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002859 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01002860 return isolate->Throw(*isolate->factory()->NewTypeError(
2861 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002862 }
Steve Block44f0eee2011-05-26 01:26:41 +01002863 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002864 }
2865 // Check for interceptor.
2866 if (result.type() == INTERCEPTOR) {
2867 // Skip interceptor if forcing a deletion.
2868 if (mode == FORCE_DELETION) {
2869 return DeletePropertyPostInterceptor(name, mode);
2870 }
2871 return DeletePropertyWithInterceptor(name);
2872 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002873 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002874 Object* obj;
2875 { MaybeObject* maybe_obj =
2876 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2877 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2878 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002879 // Make sure the properties are normalized before removing the entry.
2880 return DeleteNormalizedProperty(name, mode);
2881 }
2882}
2883
2884
2885// Check whether this object references another object.
2886bool JSObject::ReferencesObject(Object* obj) {
Steve Block44f0eee2011-05-26 01:26:41 +01002887 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002888 AssertNoAllocation no_alloc;
2889
2890 // Is the object the constructor for this object?
2891 if (map()->constructor() == obj) {
2892 return true;
2893 }
2894
2895 // Is the object the prototype for this object?
2896 if (map()->prototype() == obj) {
2897 return true;
2898 }
2899
2900 // Check if the object is among the named properties.
2901 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01002902 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002903 return true;
2904 }
2905
2906 // Check if the object is among the indexed properties.
2907 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002908 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00002909 case EXTERNAL_BYTE_ELEMENTS:
2910 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2911 case EXTERNAL_SHORT_ELEMENTS:
2912 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2913 case EXTERNAL_INT_ELEMENTS:
2914 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2915 case EXTERNAL_FLOAT_ELEMENTS:
2916 // Raw pixels and external arrays do not reference other
2917 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00002918 break;
2919 case FAST_ELEMENTS: {
2920 int length = IsJSArray() ?
2921 Smi::cast(JSArray::cast(this)->length())->value() :
2922 FixedArray::cast(elements())->length();
2923 for (int i = 0; i < length; i++) {
2924 Object* element = FixedArray::cast(elements())->get(i);
2925 if (!element->IsTheHole() && element == obj) {
2926 return true;
2927 }
2928 }
2929 break;
2930 }
2931 case DICTIONARY_ELEMENTS: {
2932 key = element_dictionary()->SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01002933 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002934 return true;
2935 }
2936 break;
2937 }
2938 default:
2939 UNREACHABLE();
2940 break;
2941 }
2942
Steve Block6ded16b2010-05-10 14:33:55 +01002943 // For functions check the context.
2944 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002945 // Get the constructor function for arguments array.
2946 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01002947 heap->isolate()->context()->global_context()->
2948 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002949 JSFunction* arguments_function =
2950 JSFunction::cast(arguments_boilerplate->map()->constructor());
2951
2952 // Get the context and don't check if it is the global context.
2953 JSFunction* f = JSFunction::cast(this);
2954 Context* context = f->context();
2955 if (context->IsGlobalContext()) {
2956 return false;
2957 }
2958
2959 // Check the non-special context slots.
2960 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
2961 // Only check JS objects.
2962 if (context->get(i)->IsJSObject()) {
2963 JSObject* ctxobj = JSObject::cast(context->get(i));
2964 // If it is an arguments array check the content.
2965 if (ctxobj->map()->constructor() == arguments_function) {
2966 if (ctxobj->ReferencesObject(obj)) {
2967 return true;
2968 }
2969 } else if (ctxobj == obj) {
2970 return true;
2971 }
2972 }
2973 }
2974
2975 // Check the context extension if any.
2976 if (context->has_extension()) {
2977 return context->extension()->ReferencesObject(obj);
2978 }
2979 }
2980
2981 // No references to object.
2982 return false;
2983}
2984
2985
John Reck59135872010-11-02 12:39:01 -07002986MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01002987 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002988 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002989 !isolate->MayNamedAccess(this,
2990 isolate->heap()->undefined_value(),
2991 v8::ACCESS_KEYS)) {
2992 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
2993 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002994 }
2995
Steve Block1e0659c2011-05-24 12:43:12 +01002996 if (IsJSGlobalProxy()) {
2997 Object* proto = GetPrototype();
2998 if (proto->IsNull()) return this;
2999 ASSERT(proto->IsJSGlobalObject());
3000 return JSObject::cast(proto)->PreventExtensions();
3001 }
3002
Steve Block8defd9f2010-07-08 12:39:36 +01003003 // If there are fast elements we normalize.
3004 if (HasFastElements()) {
John Reck59135872010-11-02 12:39:01 -07003005 Object* ok;
3006 { MaybeObject* maybe_ok = NormalizeElements();
3007 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3008 }
Steve Block8defd9f2010-07-08 12:39:36 +01003009 }
3010 // Make sure that we never go back to fast case.
3011 element_dictionary()->set_requires_slow_elements();
3012
3013 // Do a map transition, other objects with this map may still
3014 // be extensible.
John Reck59135872010-11-02 12:39:01 -07003015 Object* new_map;
3016 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
3017 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3018 }
Steve Block8defd9f2010-07-08 12:39:36 +01003019 Map::cast(new_map)->set_is_extensible(false);
3020 set_map(Map::cast(new_map));
3021 ASSERT(!map()->is_extensible());
3022 return new_map;
3023}
3024
3025
Steve Blocka7e24c12009-10-30 11:49:00 +00003026// Tests for the fast common case for property enumeration:
Steve Blockd0582a62009-12-15 09:54:21 +00003027// - This object and all prototypes has an enum cache (which means that it has
3028// no interceptors and needs no access checks).
3029// - This object has no elements.
3030// - No prototype has enumerable properties/elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00003031bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003032 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003033 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003034 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003035 o = JSObject::cast(o)->GetPrototype()) {
3036 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003037 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003038 ASSERT(!curr->HasNamedInterceptor());
3039 ASSERT(!curr->HasIndexedInterceptor());
3040 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003041 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003042 if (curr != this) {
3043 FixedArray* curr_fixed_array =
3044 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003045 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003046 }
3047 }
3048 return true;
3049}
3050
3051
3052int Map::NumberOfDescribedProperties() {
3053 int result = 0;
3054 DescriptorArray* descs = instance_descriptors();
3055 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3056 if (descs->IsProperty(i)) result++;
3057 }
3058 return result;
3059}
3060
3061
3062int Map::PropertyIndexFor(String* name) {
3063 DescriptorArray* descs = instance_descriptors();
3064 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3065 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3066 return descs->GetFieldIndex(i);
3067 }
3068 }
3069 return -1;
3070}
3071
3072
3073int Map::NextFreePropertyIndex() {
3074 int max_index = -1;
3075 DescriptorArray* descs = instance_descriptors();
3076 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3077 if (descs->GetType(i) == FIELD) {
3078 int current_index = descs->GetFieldIndex(i);
3079 if (current_index > max_index) max_index = current_index;
3080 }
3081 }
3082 return max_index + 1;
3083}
3084
3085
3086AccessorDescriptor* Map::FindAccessor(String* name) {
3087 DescriptorArray* descs = instance_descriptors();
3088 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3089 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3090 return descs->GetCallbacks(i);
3091 }
3092 }
3093 return NULL;
3094}
3095
3096
3097void JSObject::LocalLookup(String* name, LookupResult* result) {
3098 ASSERT(name->IsString());
3099
Steve Block44f0eee2011-05-26 01:26:41 +01003100 Heap* heap = GetHeap();
3101
Steve Blocka7e24c12009-10-30 11:49:00 +00003102 if (IsJSGlobalProxy()) {
3103 Object* proto = GetPrototype();
3104 if (proto->IsNull()) return result->NotFound();
3105 ASSERT(proto->IsJSGlobalObject());
3106 return JSObject::cast(proto)->LocalLookup(name, result);
3107 }
3108
3109 // Do not use inline caching if the object is a non-global object
3110 // that requires access checks.
3111 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
3112 result->DisallowCaching();
3113 }
3114
3115 // Check __proto__ before interceptor.
Steve Block44f0eee2011-05-26 01:26:41 +01003116 if (name->Equals(heap->Proto_symbol()) &&
3117 !IsJSContextExtensionObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003118 result->ConstantResult(this);
3119 return;
3120 }
3121
3122 // Check for lookup interceptor except when bootstrapping.
Steve Block44f0eee2011-05-26 01:26:41 +01003123 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003124 result->InterceptorResult(this);
3125 return;
3126 }
3127
3128 LocalLookupRealNamedProperty(name, result);
3129}
3130
3131
3132void JSObject::Lookup(String* name, LookupResult* result) {
3133 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003134 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003135 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003136 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003137 current = JSObject::cast(current)->GetPrototype()) {
3138 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003139 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003140 }
3141 result->NotFound();
3142}
3143
3144
3145// Search object and it's prototype chain for callback properties.
3146void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003147 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003148 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003149 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003150 current = JSObject::cast(current)->GetPrototype()) {
3151 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003152 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003153 }
3154 result->NotFound();
3155}
3156
3157
John Reck59135872010-11-02 12:39:01 -07003158MaybeObject* JSObject::DefineGetterSetter(String* name,
3159 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003160 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003161 // Make sure that the top context does not change when doing callbacks or
3162 // interceptor calls.
3163 AssertNoContextChange ncc;
3164
Steve Blocka7e24c12009-10-30 11:49:00 +00003165 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01003166 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003167
Leon Clarkef7060e22010-06-03 12:02:55 +01003168 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003169 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003170 }
3171
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003172 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003173 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003174
3175 if (is_element) {
3176 switch (GetElementsKind()) {
3177 case FAST_ELEMENTS:
3178 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003179 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003180 case EXTERNAL_BYTE_ELEMENTS:
3181 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3182 case EXTERNAL_SHORT_ELEMENTS:
3183 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3184 case EXTERNAL_INT_ELEMENTS:
3185 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3186 case EXTERNAL_FLOAT_ELEMENTS:
3187 // Ignore getters and setters on pixel and external array
3188 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003189 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003190 case DICTIONARY_ELEMENTS: {
3191 // Lookup the index.
3192 NumberDictionary* dictionary = element_dictionary();
3193 int entry = dictionary->FindEntry(index);
3194 if (entry != NumberDictionary::kNotFound) {
3195 Object* result = dictionary->ValueAt(entry);
3196 PropertyDetails details = dictionary->DetailsAt(entry);
Steve Block44f0eee2011-05-26 01:26:41 +01003197 if (details.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003198 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003199 if (result->IsFixedArray()) {
3200 return result;
3201 }
3202 // Otherwise allow to override it.
Steve Blocka7e24c12009-10-30 11:49:00 +00003203 }
3204 }
3205 break;
3206 }
3207 default:
3208 UNREACHABLE();
3209 break;
3210 }
3211 } else {
3212 // Lookup the name.
3213 LookupResult result;
3214 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003215 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003216 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003217 if (result.type() == CALLBACKS) {
3218 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01003219 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00003220 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003221 // Use set to update attributes.
3222 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003223 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003224 }
3225 }
3226 }
3227
3228 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07003229 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01003230 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07003231 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3232 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003233
3234 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003235 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003236 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003237 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003238 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003239}
3240
3241
3242bool JSObject::CanSetCallback(String* name) {
3243 ASSERT(!IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01003244 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003245
3246 // Check if there is an API defined callback object which prohibits
3247 // callback overwriting in this object or it's prototype chain.
3248 // This mechanism is needed for instance in a browser setting, where
3249 // certain accessors such as window.location should not be allowed
3250 // to be overwritten because allowing overwriting could potentially
3251 // cause security problems.
3252 LookupResult callback_result;
3253 LookupCallback(name, &callback_result);
3254 if (callback_result.IsProperty()) {
3255 Object* obj = callback_result.GetCallbackObject();
3256 if (obj->IsAccessorInfo() &&
3257 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3258 return false;
3259 }
3260 }
3261
3262 return true;
3263}
3264
3265
John Reck59135872010-11-02 12:39:01 -07003266MaybeObject* JSObject::SetElementCallback(uint32_t index,
3267 Object* structure,
3268 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003269 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3270
3271 // Normalize elements to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003272 Object* ok;
3273 { MaybeObject* maybe_ok = NormalizeElements();
3274 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3275 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003276
3277 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003278 Object* dict;
3279 { MaybeObject* maybe_dict =
3280 element_dictionary()->Set(index, structure, details);
3281 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
3282 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003283
3284 NumberDictionary* elements = NumberDictionary::cast(dict);
3285 elements->set_requires_slow_elements();
3286 // Set the potential new dictionary on the object.
3287 set_elements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00003288
3289 return structure;
3290}
3291
3292
John Reck59135872010-11-02 12:39:01 -07003293MaybeObject* JSObject::SetPropertyCallback(String* name,
3294 Object* structure,
3295 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003296 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3297
3298 bool convert_back_to_fast = HasFastProperties() &&
3299 (map()->instance_descriptors()->number_of_descriptors()
3300 < DescriptorArray::kMaxNumberOfDescriptors);
3301
3302 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003303 Object* ok;
3304 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3305 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3306 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003307
3308 // For the global object allocate a new map to invalidate the global inline
3309 // caches which have a global property cell reference directly in the code.
3310 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07003311 Object* new_map;
3312 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3313 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3314 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003315 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003316 // When running crankshaft, changing the map is not enough. We
3317 // need to deoptimize all functions that rely on this global
3318 // object.
3319 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003320 }
3321
3322 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003323 Object* result;
3324 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3325 if (!maybe_result->ToObject(&result)) return maybe_result;
3326 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003327
3328 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07003329 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3330 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3331 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003332 }
3333 return result;
3334}
3335
John Reck59135872010-11-02 12:39:01 -07003336MaybeObject* JSObject::DefineAccessor(String* name,
3337 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01003338 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003339 PropertyAttributes attributes) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003340 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003341 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003342 // Check access rights if needed.
3343 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003344 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3345 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3346 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003347 }
3348
3349 if (IsJSGlobalProxy()) {
3350 Object* proto = GetPrototype();
3351 if (proto->IsNull()) return this;
3352 ASSERT(proto->IsJSGlobalObject());
3353 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3354 fun, attributes);
3355 }
3356
John Reck59135872010-11-02 12:39:01 -07003357 Object* array;
3358 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3359 if (!maybe_array->ToObject(&array)) return maybe_array;
3360 }
3361 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003362 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3363 return this;
3364}
3365
3366
John Reck59135872010-11-02 12:39:01 -07003367MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003368 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003369 String* name = String::cast(info->name());
3370 // Check access rights if needed.
3371 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003372 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3373 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3374 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003375 }
3376
3377 if (IsJSGlobalProxy()) {
3378 Object* proto = GetPrototype();
3379 if (proto->IsNull()) return this;
3380 ASSERT(proto->IsJSGlobalObject());
3381 return JSObject::cast(proto)->DefineAccessor(info);
3382 }
3383
3384 // Make sure that the top context does not change when doing callbacks or
3385 // interceptor calls.
3386 AssertNoContextChange ncc;
3387
3388 // Try to flatten before operating on the string.
3389 name->TryFlatten();
3390
3391 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003392 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003393 }
3394
3395 uint32_t index = 0;
3396 bool is_element = name->AsArrayIndex(&index);
3397
3398 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003399 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003400
3401 // Accessors overwrite previous callbacks (cf. with getters/setters).
3402 switch (GetElementsKind()) {
3403 case FAST_ELEMENTS:
3404 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003405 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003406 case EXTERNAL_BYTE_ELEMENTS:
3407 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3408 case EXTERNAL_SHORT_ELEMENTS:
3409 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3410 case EXTERNAL_INT_ELEMENTS:
3411 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3412 case EXTERNAL_FLOAT_ELEMENTS:
3413 // Ignore getters and setters on pixel and external array
3414 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003415 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003416 case DICTIONARY_ELEMENTS:
3417 break;
3418 default:
3419 UNREACHABLE();
3420 break;
3421 }
3422
John Reck59135872010-11-02 12:39:01 -07003423 Object* ok;
3424 { MaybeObject* maybe_ok =
3425 SetElementCallback(index, info, info->property_attributes());
3426 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3427 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003428 } else {
3429 // Lookup the name.
3430 LookupResult result;
3431 LocalLookup(name, &result);
3432 // ES5 forbids turning a property into an accessor if it's not
3433 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3434 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003435 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003436 }
John Reck59135872010-11-02 12:39:01 -07003437 Object* ok;
3438 { MaybeObject* maybe_ok =
3439 SetPropertyCallback(name, info, info->property_attributes());
3440 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3441 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003442 }
3443
3444 return this;
3445}
3446
3447
Steve Blocka7e24c12009-10-30 11:49:00 +00003448Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003449 Heap* heap = GetHeap();
3450
Steve Blocka7e24c12009-10-30 11:49:00 +00003451 // Make sure that the top context does not change when doing callbacks or
3452 // interceptor calls.
3453 AssertNoContextChange ncc;
3454
3455 // Check access rights if needed.
3456 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003457 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3458 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3459 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003460 }
3461
3462 // Make the lookup and include prototypes.
3463 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003464 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003465 if (name->AsArrayIndex(&index)) {
3466 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003467 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003468 obj = JSObject::cast(obj)->GetPrototype()) {
3469 JSObject* js_object = JSObject::cast(obj);
3470 if (js_object->HasDictionaryElements()) {
3471 NumberDictionary* dictionary = js_object->element_dictionary();
3472 int entry = dictionary->FindEntry(index);
3473 if (entry != NumberDictionary::kNotFound) {
3474 Object* element = dictionary->ValueAt(entry);
3475 PropertyDetails details = dictionary->DetailsAt(entry);
3476 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003477 if (element->IsFixedArray()) {
3478 return FixedArray::cast(element)->get(accessor_index);
3479 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003480 }
3481 }
3482 }
3483 }
3484 } else {
3485 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003486 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003487 obj = JSObject::cast(obj)->GetPrototype()) {
3488 LookupResult result;
3489 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003490 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003491 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003492 if (result.type() == CALLBACKS) {
3493 Object* obj = result.GetCallbackObject();
3494 if (obj->IsFixedArray()) {
3495 return FixedArray::cast(obj)->get(accessor_index);
3496 }
3497 }
3498 }
3499 }
3500 }
Steve Block44f0eee2011-05-26 01:26:41 +01003501 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003502}
3503
3504
3505Object* JSObject::SlowReverseLookup(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01003506 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003507 if (HasFastProperties()) {
3508 DescriptorArray* descs = map()->instance_descriptors();
3509 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3510 if (descs->GetType(i) == FIELD) {
3511 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3512 return descs->GetKey(i);
3513 }
3514 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3515 if (descs->GetConstantFunction(i) == value) {
3516 return descs->GetKey(i);
3517 }
3518 }
3519 }
Steve Block44f0eee2011-05-26 01:26:41 +01003520 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003521 } else {
3522 return property_dictionary()->SlowReverseLookup(value);
3523 }
3524}
3525
3526
John Reck59135872010-11-02 12:39:01 -07003527MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01003528 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07003529 Object* result;
3530 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003531 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07003532 if (!maybe_result->ToObject(&result)) return maybe_result;
3533 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003534 Map::cast(result)->set_prototype(prototype());
3535 Map::cast(result)->set_constructor(constructor());
3536 // Don't copy descriptors, so map transitions always remain a forest.
3537 // If we retained the same descriptors we would have two maps
3538 // pointing to the same transition which is bad because the garbage
3539 // collector relies on being able to reverse pointers from transitions
3540 // to maps. If properties need to be retained use CopyDropTransitions.
Steve Block44f0eee2011-05-26 01:26:41 +01003541 Map::cast(result)->set_instance_descriptors(
3542 heap->empty_descriptor_array());
Steve Blocka7e24c12009-10-30 11:49:00 +00003543 // Please note instance_type and instance_size are set when allocated.
3544 Map::cast(result)->set_inobject_properties(inobject_properties());
3545 Map::cast(result)->set_unused_property_fields(unused_property_fields());
3546
3547 // If the map has pre-allocated properties always start out with a descriptor
3548 // array describing these properties.
3549 if (pre_allocated_property_fields() > 0) {
3550 ASSERT(constructor()->IsJSFunction());
3551 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07003552 Object* descriptors;
3553 { MaybeObject* maybe_descriptors =
3554 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
3555 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3556 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003557 Map::cast(result)->set_instance_descriptors(
3558 DescriptorArray::cast(descriptors));
3559 Map::cast(result)->set_pre_allocated_property_fields(
3560 pre_allocated_property_fields());
3561 }
3562 Map::cast(result)->set_bit_field(bit_field());
3563 Map::cast(result)->set_bit_field2(bit_field2());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003564 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01003565 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00003566 return result;
3567}
3568
3569
John Reck59135872010-11-02 12:39:01 -07003570MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
3571 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003572 int new_instance_size = instance_size();
3573 if (mode == CLEAR_INOBJECT_PROPERTIES) {
3574 new_instance_size -= inobject_properties() * kPointerSize;
3575 }
3576
John Reck59135872010-11-02 12:39:01 -07003577 Object* result;
3578 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003579 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07003580 if (!maybe_result->ToObject(&result)) return maybe_result;
3581 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003582
3583 if (mode != CLEAR_INOBJECT_PROPERTIES) {
3584 Map::cast(result)->set_inobject_properties(inobject_properties());
3585 }
3586
3587 Map::cast(result)->set_prototype(prototype());
3588 Map::cast(result)->set_constructor(constructor());
3589
3590 Map::cast(result)->set_bit_field(bit_field());
3591 Map::cast(result)->set_bit_field2(bit_field2());
3592
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003593 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
3594
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003595#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003596 if (Map::cast(result)->is_shared()) {
3597 Map::cast(result)->SharedMapVerify();
3598 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003599#endif
3600
3601 return result;
3602}
3603
3604
John Reck59135872010-11-02 12:39:01 -07003605MaybeObject* Map::CopyDropTransitions() {
3606 Object* new_map;
3607 { MaybeObject* maybe_new_map = CopyDropDescriptors();
3608 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3609 }
3610 Object* descriptors;
3611 { MaybeObject* maybe_descriptors =
3612 instance_descriptors()->RemoveTransitions();
3613 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3614 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003615 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01003616 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003617}
3618
3619
John Reck59135872010-11-02 12:39:01 -07003620MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003621 // Allocate the code cache if not present.
3622 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07003623 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +01003624 { MaybeObject* maybe_result = GetHeap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07003625 if (!maybe_result->ToObject(&result)) return maybe_result;
3626 }
Steve Block6ded16b2010-05-10 14:33:55 +01003627 set_code_cache(result);
3628 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003629
Steve Block6ded16b2010-05-10 14:33:55 +01003630 // Update the code cache.
3631 return CodeCache::cast(code_cache())->Update(name, code);
3632}
3633
3634
3635Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3636 // Do a lookup if a code cache exists.
3637 if (!code_cache()->IsFixedArray()) {
3638 return CodeCache::cast(code_cache())->Lookup(name, flags);
3639 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003640 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003641 }
3642}
3643
3644
3645int Map::IndexInCodeCache(Object* name, Code* code) {
3646 // Get the internal index if a code cache exists.
3647 if (!code_cache()->IsFixedArray()) {
3648 return CodeCache::cast(code_cache())->GetIndex(name, code);
3649 }
3650 return -1;
3651}
3652
3653
3654void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3655 // No GC is supposed to happen between a call to IndexInCodeCache and
3656 // RemoveFromCodeCache so the code cache must be there.
3657 ASSERT(!code_cache()->IsFixedArray());
3658 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3659}
3660
3661
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003662void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
3663 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003664 Map* meta_map = heap()->meta_map();
3665 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003666 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
3667 *RawField(current, Map::kInstanceDescriptorsOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01003668 if (d == heap()->empty_descriptor_array()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003669 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003670 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003671 callback(current, data);
3672 current = prev;
3673 continue;
3674 }
3675
3676 FixedArray* contents = reinterpret_cast<FixedArray*>(
3677 d->get(DescriptorArray::kContentArrayIndex));
3678 Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3679 Object* map_or_index = *map_or_index_field;
3680 bool map_done = true;
3681 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3682 i < contents->length();
3683 i += 2) {
3684 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3685 if (details.IsTransition()) {
3686 Map* next = reinterpret_cast<Map*>(contents->get(i));
3687 next->set_map(current);
3688 *map_or_index_field = Smi::FromInt(i + 2);
3689 current = next;
3690 map_done = false;
3691 break;
3692 }
3693 }
3694 if (!map_done) continue;
Steve Block44f0eee2011-05-26 01:26:41 +01003695 *map_or_index_field = heap()->fixed_array_map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003696 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003697 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003698 callback(current, data);
3699 current = prev;
3700 }
3701}
3702
3703
John Reck59135872010-11-02 12:39:01 -07003704MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003705 ASSERT(code->ic_state() == MONOMORPHIC);
3706
3707 // The number of monomorphic stubs for normal load/store/call IC's can grow to
3708 // a large number and therefore they need to go into a hash table. They are
3709 // used to load global properties from cells.
3710 if (code->type() == NORMAL) {
3711 // Make sure that a hash table is allocated for the normal load code cache.
3712 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07003713 Object* result;
3714 { MaybeObject* maybe_result =
3715 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
3716 if (!maybe_result->ToObject(&result)) return maybe_result;
3717 }
Steve Block6ded16b2010-05-10 14:33:55 +01003718 set_normal_type_cache(result);
3719 }
3720 return UpdateNormalTypeCache(name, code);
3721 } else {
3722 ASSERT(default_cache()->IsFixedArray());
3723 return UpdateDefaultCache(name, code);
3724 }
3725}
3726
3727
John Reck59135872010-11-02 12:39:01 -07003728MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003729 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00003730 // flags. This allows call constant stubs to overwrite call field
3731 // stubs, etc.
3732 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
3733
3734 // First check whether we can update existing code cache without
3735 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01003736 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003737 int length = cache->length();
3738 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01003739 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003740 Object* key = cache->get(i);
3741 if (key->IsNull()) {
3742 if (deleted_index < 0) deleted_index = i;
3743 continue;
3744 }
3745 if (key->IsUndefined()) {
3746 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01003747 cache->set(i + kCodeCacheEntryNameOffset, name);
3748 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003749 return this;
3750 }
3751 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003752 Code::Flags found =
3753 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00003754 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01003755 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003756 return this;
3757 }
3758 }
3759 }
3760
3761 // Reached the end of the code cache. If there were deleted
3762 // elements, reuse the space for the first of them.
3763 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01003764 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
3765 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003766 return this;
3767 }
3768
Steve Block6ded16b2010-05-10 14:33:55 +01003769 // Extend the code cache with some new entries (at least one). Must be a
3770 // multiple of the entry size.
3771 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
3772 new_length = new_length - new_length % kCodeCacheEntrySize;
3773 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07003774 Object* result;
3775 { MaybeObject* maybe_result = cache->CopySize(new_length);
3776 if (!maybe_result->ToObject(&result)) return maybe_result;
3777 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003778
3779 // Add the (name, code) pair to the new cache.
3780 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01003781 cache->set(length + kCodeCacheEntryNameOffset, name);
3782 cache->set(length + kCodeCacheEntryCodeOffset, code);
3783 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00003784 return this;
3785}
3786
3787
John Reck59135872010-11-02 12:39:01 -07003788MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003789 // Adding a new entry can cause a new cache to be allocated.
3790 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07003791 Object* new_cache;
3792 { MaybeObject* maybe_new_cache = cache->Put(name, code);
3793 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
3794 }
Steve Block6ded16b2010-05-10 14:33:55 +01003795 set_normal_type_cache(new_cache);
3796 return this;
3797}
3798
3799
3800Object* CodeCache::Lookup(String* name, Code::Flags flags) {
3801 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
3802 return LookupNormalTypeCache(name, flags);
3803 } else {
3804 return LookupDefaultCache(name, flags);
3805 }
3806}
3807
3808
3809Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01003810 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01003811 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003812 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003813 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
3814 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00003815 // Skip deleted elements.
3816 if (key->IsNull()) continue;
3817 if (key->IsUndefined()) return key;
3818 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003819 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
3820 if (code->flags() == flags) {
3821 return code;
3822 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003823 }
3824 }
Steve Block44f0eee2011-05-26 01:26:41 +01003825 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003826}
3827
3828
Steve Block6ded16b2010-05-10 14:33:55 +01003829Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
3830 if (!normal_type_cache()->IsUndefined()) {
3831 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3832 return cache->Lookup(name, flags);
3833 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003834 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003835 }
3836}
3837
3838
3839int CodeCache::GetIndex(Object* name, Code* code) {
3840 if (code->type() == NORMAL) {
3841 if (normal_type_cache()->IsUndefined()) return -1;
3842 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3843 return cache->GetIndex(String::cast(name), code->flags());
3844 }
3845
3846 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003847 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003848 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
3849 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00003850 }
3851 return -1;
3852}
3853
3854
Steve Block6ded16b2010-05-10 14:33:55 +01003855void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
3856 if (code->type() == NORMAL) {
3857 ASSERT(!normal_type_cache()->IsUndefined());
3858 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3859 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
3860 cache->RemoveByIndex(index);
3861 } else {
3862 FixedArray* array = default_cache();
3863 ASSERT(array->length() >= index && array->get(index)->IsCode());
3864 // Use null instead of undefined for deleted elements to distinguish
3865 // deleted elements from unused elements. This distinction is used
3866 // when looking up in the cache and when updating the cache.
3867 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
3868 array->set_null(index - 1); // Name.
3869 array->set_null(index); // Code.
3870 }
3871}
3872
3873
3874// The key in the code cache hash table consists of the property name and the
3875// code object. The actual match is on the name and the code flags. If a key
3876// is created using the flags and not a code object it can only be used for
3877// lookup not to create a new entry.
3878class CodeCacheHashTableKey : public HashTableKey {
3879 public:
3880 CodeCacheHashTableKey(String* name, Code::Flags flags)
3881 : name_(name), flags_(flags), code_(NULL) { }
3882
3883 CodeCacheHashTableKey(String* name, Code* code)
3884 : name_(name),
3885 flags_(code->flags()),
3886 code_(code) { }
3887
3888
3889 bool IsMatch(Object* other) {
3890 if (!other->IsFixedArray()) return false;
3891 FixedArray* pair = FixedArray::cast(other);
3892 String* name = String::cast(pair->get(0));
3893 Code::Flags flags = Code::cast(pair->get(1))->flags();
3894 if (flags != flags_) {
3895 return false;
3896 }
3897 return name_->Equals(name);
3898 }
3899
3900 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
3901 return name->Hash() ^ flags;
3902 }
3903
3904 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
3905
3906 uint32_t HashForObject(Object* obj) {
3907 FixedArray* pair = FixedArray::cast(obj);
3908 String* name = String::cast(pair->get(0));
3909 Code* code = Code::cast(pair->get(1));
3910 return NameFlagsHashHelper(name, code->flags());
3911 }
3912
John Reck59135872010-11-02 12:39:01 -07003913 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01003914 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07003915 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01003916 { MaybeObject* maybe_obj = code_->GetHeap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07003917 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3918 }
Steve Block6ded16b2010-05-10 14:33:55 +01003919 FixedArray* pair = FixedArray::cast(obj);
3920 pair->set(0, name_);
3921 pair->set(1, code_);
3922 return pair;
3923 }
3924
3925 private:
3926 String* name_;
3927 Code::Flags flags_;
3928 Code* code_;
3929};
3930
3931
3932Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
3933 CodeCacheHashTableKey key(name, flags);
3934 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01003935 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003936 return get(EntryToIndex(entry) + 1);
3937}
3938
3939
John Reck59135872010-11-02 12:39:01 -07003940MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003941 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07003942 Object* obj;
3943 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
3944 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3945 }
Steve Block6ded16b2010-05-10 14:33:55 +01003946
3947 // Don't use this, as the table might have grown.
3948 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
3949
3950 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07003951 Object* k;
3952 { MaybeObject* maybe_k = key.AsObject();
3953 if (!maybe_k->ToObject(&k)) return maybe_k;
3954 }
Steve Block6ded16b2010-05-10 14:33:55 +01003955
3956 cache->set(EntryToIndex(entry), k);
3957 cache->set(EntryToIndex(entry) + 1, code);
3958 cache->ElementAdded();
3959 return cache;
3960}
3961
3962
3963int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
3964 CodeCacheHashTableKey key(name, flags);
3965 int entry = FindEntry(&key);
3966 return (entry == kNotFound) ? -1 : entry;
3967}
3968
3969
3970void CodeCacheHashTable::RemoveByIndex(int index) {
3971 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01003972 Heap* heap = GetHeap();
3973 set(EntryToIndex(index), heap->null_value());
3974 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01003975 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00003976}
3977
3978
Steve Blocka7e24c12009-10-30 11:49:00 +00003979static bool HasKey(FixedArray* array, Object* key) {
3980 int len0 = array->length();
3981 for (int i = 0; i < len0; i++) {
3982 Object* element = array->get(i);
3983 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
3984 if (element->IsString() &&
3985 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
3986 return true;
3987 }
3988 }
3989 return false;
3990}
3991
3992
John Reck59135872010-11-02 12:39:01 -07003993MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Steve Block44f0eee2011-05-26 01:26:41 +01003994 Heap* heap = GetHeap();
3995 ASSERT(!array->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00003996 switch (array->GetElementsKind()) {
3997 case JSObject::FAST_ELEMENTS:
3998 return UnionOfKeys(FixedArray::cast(array->elements()));
3999 case JSObject::DICTIONARY_ELEMENTS: {
4000 NumberDictionary* dict = array->element_dictionary();
4001 int size = dict->NumberOfElements();
4002
4003 // Allocate a temporary fixed array.
John Reck59135872010-11-02 12:39:01 -07004004 Object* object;
Steve Block44f0eee2011-05-26 01:26:41 +01004005 { MaybeObject* maybe_object = heap->AllocateFixedArray(size);
John Reck59135872010-11-02 12:39:01 -07004006 if (!maybe_object->ToObject(&object)) return maybe_object;
4007 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004008 FixedArray* key_array = FixedArray::cast(object);
4009
4010 int capacity = dict->Capacity();
4011 int pos = 0;
4012 // Copy the elements from the JSArray to the temporary fixed array.
4013 for (int i = 0; i < capacity; i++) {
4014 if (dict->IsKey(dict->KeyAt(i))) {
4015 key_array->set(pos++, dict->ValueAt(i));
4016 }
4017 }
4018 // Compute the union of this and the temporary fixed array.
4019 return UnionOfKeys(key_array);
4020 }
4021 default:
4022 UNREACHABLE();
4023 }
4024 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01004025 return heap->null_value(); // Failure case needs to "return" a value.
Steve Blocka7e24c12009-10-30 11:49:00 +00004026}
4027
4028
John Reck59135872010-11-02 12:39:01 -07004029MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Steve Block44f0eee2011-05-26 01:26:41 +01004030 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004031 int len0 = length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004032#ifdef DEBUG
4033 if (FLAG_enable_slow_asserts) {
4034 for (int i = 0; i < len0; i++) {
4035 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4036 }
4037 }
4038#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004039 int len1 = other->length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004040 // Optimize if 'other' is empty.
4041 // We cannot optimize if 'this' is empty, as other may have holes
4042 // or non keys.
Steve Blocka7e24c12009-10-30 11:49:00 +00004043 if (len1 == 0) return this;
4044
4045 // Compute how many elements are not in this.
4046 int extra = 0;
4047 for (int y = 0; y < len1; y++) {
4048 Object* value = other->get(y);
4049 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
4050 }
4051
4052 if (extra == 0) return this;
4053
4054 // Allocate the result
John Reck59135872010-11-02 12:39:01 -07004055 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004056 { MaybeObject* maybe_obj = heap->AllocateFixedArray(len0 + extra);
John Reck59135872010-11-02 12:39:01 -07004057 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004059 // Fill in the content
Leon Clarke4515c472010-02-03 11:58:03 +00004060 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004061 FixedArray* result = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00004062 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004063 for (int i = 0; i < len0; i++) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004064 Object* e = get(i);
4065 ASSERT(e->IsString() || e->IsNumber());
4066 result->set(i, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004067 }
4068 // Fill in the extra keys.
4069 int index = 0;
4070 for (int y = 0; y < len1; y++) {
4071 Object* value = other->get(y);
4072 if (!value->IsTheHole() && !HasKey(this, value)) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004073 Object* e = other->get(y);
4074 ASSERT(e->IsString() || e->IsNumber());
4075 result->set(len0 + index, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004076 index++;
4077 }
4078 }
4079 ASSERT(extra == index);
4080 return result;
4081}
4082
4083
John Reck59135872010-11-02 12:39:01 -07004084MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004085 Heap* heap = GetHeap();
4086 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004087 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004088 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004089 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4090 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004091 FixedArray* result = FixedArray::cast(obj);
4092 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004093 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004094 int len = length();
4095 if (new_length < len) len = new_length;
4096 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004097 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004098 for (int i = 0; i < len; i++) {
4099 result->set(i, get(i), mode);
4100 }
4101 return result;
4102}
4103
4104
4105void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004106 AssertNoAllocation no_gc;
4107 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004108 for (int index = 0; index < len; index++) {
4109 dest->set(dest_pos+index, get(pos+index), mode);
4110 }
4111}
4112
4113
4114#ifdef DEBUG
4115bool FixedArray::IsEqualTo(FixedArray* other) {
4116 if (length() != other->length()) return false;
4117 for (int i = 0 ; i < length(); ++i) {
4118 if (get(i) != other->get(i)) return false;
4119 }
4120 return true;
4121}
4122#endif
4123
4124
John Reck59135872010-11-02 12:39:01 -07004125MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004126 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004127 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004128 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004129 }
4130 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004131 Object* array;
4132 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004133 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004134 if (!maybe_array->ToObject(&array)) return maybe_array;
4135 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004136 // Do not use DescriptorArray::cast on incomplete object.
4137 FixedArray* result = FixedArray::cast(array);
4138
4139 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004140 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004141 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004142 if (!maybe_array->ToObject(&array)) return maybe_array;
4143 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004144 result->set(kContentArrayIndex, array);
4145 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004146 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004147 return result;
4148}
4149
4150
4151void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4152 FixedArray* new_cache) {
4153 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4154 if (HasEnumCache()) {
4155 FixedArray::cast(get(kEnumerationIndexIndex))->
4156 set(kEnumCacheBridgeCacheIndex, new_cache);
4157 } else {
4158 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4159 FixedArray::cast(bridge_storage)->
4160 set(kEnumCacheBridgeCacheIndex, new_cache);
4161 fast_set(FixedArray::cast(bridge_storage),
4162 kEnumCacheBridgeEnumIndex,
4163 get(kEnumerationIndexIndex));
4164 set(kEnumerationIndexIndex, bridge_storage);
4165 }
4166}
4167
4168
John Reck59135872010-11-02 12:39:01 -07004169MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4170 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004171 // Transitions are only kept when inserting another transition.
4172 // This precondition is not required by this function's implementation, but
4173 // is currently required by the semantics of maps, so we check it.
4174 // Conversely, we filter after replacing, so replacing a transition and
4175 // removing all other transitions is not supported.
4176 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4177 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4178 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4179
4180 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004181 Object* result;
4182 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4183 if (!maybe_result->ToObject(&result)) return maybe_result;
4184 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004185
4186 int transitions = 0;
4187 int null_descriptors = 0;
4188 if (remove_transitions) {
4189 for (int i = 0; i < number_of_descriptors(); i++) {
4190 if (IsTransition(i)) transitions++;
4191 if (IsNullDescriptor(i)) null_descriptors++;
4192 }
4193 } else {
4194 for (int i = 0; i < number_of_descriptors(); i++) {
4195 if (IsNullDescriptor(i)) null_descriptors++;
4196 }
4197 }
4198 int new_size = number_of_descriptors() - transitions - null_descriptors;
4199
4200 // If key is in descriptor, we replace it in-place when filtering.
4201 // Count a null descriptor for key as inserted, not replaced.
4202 int index = Search(descriptor->GetKey());
4203 const bool inserting = (index == kNotFound);
4204 const bool replacing = !inserting;
4205 bool keep_enumeration_index = false;
4206 if (inserting) {
4207 ++new_size;
4208 }
4209 if (replacing) {
4210 // We are replacing an existing descriptor. We keep the enumeration
4211 // index of a visible property.
4212 PropertyType t = PropertyDetails(GetDetails(index)).type();
4213 if (t == CONSTANT_FUNCTION ||
4214 t == FIELD ||
4215 t == CALLBACKS ||
4216 t == INTERCEPTOR) {
4217 keep_enumeration_index = true;
4218 } else if (remove_transitions) {
4219 // Replaced descriptor has been counted as removed if it is
4220 // a transition that will be replaced. Adjust count in this case.
4221 ++new_size;
4222 }
4223 }
John Reck59135872010-11-02 12:39:01 -07004224 { MaybeObject* maybe_result = Allocate(new_size);
4225 if (!maybe_result->ToObject(&result)) return maybe_result;
4226 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004227 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4228 // Set the enumeration index in the descriptors and set the enumeration index
4229 // in the result.
4230 int enumeration_index = NextEnumerationIndex();
4231 if (!descriptor->GetDetails().IsTransition()) {
4232 if (keep_enumeration_index) {
4233 descriptor->SetEnumerationIndex(
4234 PropertyDetails(GetDetails(index)).index());
4235 } else {
4236 descriptor->SetEnumerationIndex(enumeration_index);
4237 ++enumeration_index;
4238 }
4239 }
4240 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4241
4242 // Copy the descriptors, filtering out transitions and null descriptors,
4243 // and inserting or replacing a descriptor.
4244 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4245 int from_index = 0;
4246 int to_index = 0;
4247
4248 for (; from_index < number_of_descriptors(); from_index++) {
4249 String* key = GetKey(from_index);
4250 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4251 break;
4252 }
4253 if (IsNullDescriptor(from_index)) continue;
4254 if (remove_transitions && IsTransition(from_index)) continue;
4255 new_descriptors->CopyFrom(to_index++, this, from_index);
4256 }
4257
4258 new_descriptors->Set(to_index++, descriptor);
4259 if (replacing) from_index++;
4260
4261 for (; from_index < number_of_descriptors(); from_index++) {
4262 if (IsNullDescriptor(from_index)) continue;
4263 if (remove_transitions && IsTransition(from_index)) continue;
4264 new_descriptors->CopyFrom(to_index++, this, from_index);
4265 }
4266
4267 ASSERT(to_index == new_descriptors->number_of_descriptors());
4268 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4269
4270 return new_descriptors;
4271}
4272
4273
John Reck59135872010-11-02 12:39:01 -07004274MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004275 // Remove all transitions and null descriptors. Return a copy of the array
4276 // with all transitions removed, or a Failure object if the new array could
4277 // not be allocated.
4278
4279 // Compute the size of the map transition entries to be removed.
4280 int num_removed = 0;
4281 for (int i = 0; i < number_of_descriptors(); i++) {
4282 if (!IsProperty(i)) num_removed++;
4283 }
4284
4285 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07004286 Object* result;
4287 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4288 if (!maybe_result->ToObject(&result)) return maybe_result;
4289 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004290 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4291
4292 // Copy the content.
4293 int next_descriptor = 0;
4294 for (int i = 0; i < number_of_descriptors(); i++) {
4295 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
4296 }
4297 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4298
4299 return new_descriptors;
4300}
4301
4302
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004303void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004304 // In-place heap sort.
4305 int len = number_of_descriptors();
4306
4307 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004308 // Index of the last node with children
4309 const int max_parent_index = (len / 2) - 1;
4310 for (int i = max_parent_index; i >= 0; --i) {
4311 int parent_index = i;
4312 const uint32_t parent_hash = GetKey(i)->Hash();
4313 while (parent_index <= max_parent_index) {
4314 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004315 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004316 if (child_index + 1 < len) {
4317 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4318 if (right_child_hash > child_hash) {
4319 child_index++;
4320 child_hash = right_child_hash;
4321 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004322 }
Steve Block6ded16b2010-05-10 14:33:55 +01004323 if (child_hash <= parent_hash) break;
4324 Swap(parent_index, child_index);
4325 // Now element at child_index could be < its children.
4326 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004327 }
4328 }
4329
4330 // Extract elements and create sorted array.
4331 for (int i = len - 1; i > 0; --i) {
4332 // Put max element at the back of the array.
4333 Swap(0, i);
4334 // Sift down the new top element.
4335 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004336 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4337 const int max_parent_index = (i / 2) - 1;
4338 while (parent_index <= max_parent_index) {
4339 int child_index = parent_index * 2 + 1;
4340 uint32_t child_hash = GetKey(child_index)->Hash();
4341 if (child_index + 1 < i) {
4342 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4343 if (right_child_hash > child_hash) {
4344 child_index++;
4345 child_hash = right_child_hash;
4346 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004347 }
Steve Block6ded16b2010-05-10 14:33:55 +01004348 if (child_hash <= parent_hash) break;
4349 Swap(parent_index, child_index);
4350 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004351 }
4352 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004353}
Steve Blocka7e24c12009-10-30 11:49:00 +00004354
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004355
4356void DescriptorArray::Sort() {
4357 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004358 SLOW_ASSERT(IsSortedNoDuplicates());
4359}
4360
4361
4362int DescriptorArray::BinarySearch(String* name, int low, int high) {
4363 uint32_t hash = name->Hash();
4364
4365 while (low <= high) {
4366 int mid = (low + high) / 2;
4367 String* mid_name = GetKey(mid);
4368 uint32_t mid_hash = mid_name->Hash();
4369
4370 if (mid_hash > hash) {
4371 high = mid - 1;
4372 continue;
4373 }
4374 if (mid_hash < hash) {
4375 low = mid + 1;
4376 continue;
4377 }
4378 // Found an element with the same hash-code.
4379 ASSERT(hash == mid_hash);
4380 // There might be more, so we find the first one and
4381 // check them all to see if we have a match.
4382 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4383 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4384 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4385 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4386 }
4387 break;
4388 }
4389 return kNotFound;
4390}
4391
4392
4393int DescriptorArray::LinearSearch(String* name, int len) {
4394 uint32_t hash = name->Hash();
4395 for (int number = 0; number < len; number++) {
4396 String* entry = GetKey(number);
4397 if ((entry->Hash() == hash) &&
4398 name->Equals(entry) &&
4399 !is_null_descriptor(number)) {
4400 return number;
4401 }
4402 }
4403 return kNotFound;
4404}
4405
4406
Ben Murdochb0fe1622011-05-05 13:52:32 +01004407MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4408 PretenureFlag pretenure) {
4409 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004410 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004411 pretenure);
4412}
4413
4414
4415MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
4416 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01004417 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
4418 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004419 pretenure);
4420}
4421
4422
Steve Blocka7e24c12009-10-30 11:49:00 +00004423#ifdef DEBUG
4424bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
4425 if (IsEmpty()) return other->IsEmpty();
4426 if (other->IsEmpty()) return false;
4427 if (length() != other->length()) return false;
4428 for (int i = 0; i < length(); ++i) {
4429 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
4430 }
4431 return GetContentArray()->IsEqualTo(other->GetContentArray());
4432}
4433#endif
4434
4435
Steve Blocka7e24c12009-10-30 11:49:00 +00004436bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01004437 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004438 return true;
4439}
4440
4441
4442int String::Utf8Length() {
4443 if (IsAsciiRepresentation()) return length();
4444 // Attempt to flatten before accessing the string. It probably
4445 // doesn't make Utf8Length faster, but it is very likely that
4446 // the string will be accessed later (for example by WriteUtf8)
4447 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01004448 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01004449 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01004450 Access<StringInputBuffer> buffer(
4451 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004452 buffer->Reset(0, this);
4453 int result = 0;
4454 while (buffer->has_more())
4455 result += unibrow::Utf8::Length(buffer->GetNext());
4456 return result;
4457}
4458
4459
4460Vector<const char> String::ToAsciiVector() {
4461 ASSERT(IsAsciiRepresentation());
4462 ASSERT(IsFlat());
4463
4464 int offset = 0;
4465 int length = this->length();
4466 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4467 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004468 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004469 ConsString* cons = ConsString::cast(string);
4470 ASSERT(cons->second()->length() == 0);
4471 string = cons->first();
4472 string_tag = StringShape(string).representation_tag();
4473 }
4474 if (string_tag == kSeqStringTag) {
4475 SeqAsciiString* seq = SeqAsciiString::cast(string);
4476 char* start = seq->GetChars();
4477 return Vector<const char>(start + offset, length);
4478 }
4479 ASSERT(string_tag == kExternalStringTag);
4480 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
4481 const char* start = ext->resource()->data();
4482 return Vector<const char>(start + offset, length);
4483}
4484
4485
4486Vector<const uc16> String::ToUC16Vector() {
4487 ASSERT(IsTwoByteRepresentation());
4488 ASSERT(IsFlat());
4489
4490 int offset = 0;
4491 int length = this->length();
4492 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4493 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004494 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004495 ConsString* cons = ConsString::cast(string);
4496 ASSERT(cons->second()->length() == 0);
4497 string = cons->first();
4498 string_tag = StringShape(string).representation_tag();
4499 }
4500 if (string_tag == kSeqStringTag) {
4501 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
4502 return Vector<const uc16>(seq->GetChars() + offset, length);
4503 }
4504 ASSERT(string_tag == kExternalStringTag);
4505 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
4506 const uc16* start =
4507 reinterpret_cast<const uc16*>(ext->resource()->data());
4508 return Vector<const uc16>(start + offset, length);
4509}
4510
4511
4512SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4513 RobustnessFlag robust_flag,
4514 int offset,
4515 int length,
4516 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004517 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4518 return SmartPointer<char>(NULL);
4519 }
Steve Block44f0eee2011-05-26 01:26:41 +01004520 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004521
4522 // Negative length means the to the end of the string.
4523 if (length < 0) length = kMaxInt - offset;
4524
4525 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01004526 Access<StringInputBuffer> buffer(
4527 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004528 buffer->Reset(offset, this);
4529 int character_position = offset;
4530 int utf8_bytes = 0;
4531 while (buffer->has_more()) {
4532 uint16_t character = buffer->GetNext();
4533 if (character_position < offset + length) {
4534 utf8_bytes += unibrow::Utf8::Length(character);
4535 }
4536 character_position++;
4537 }
4538
4539 if (length_return) {
4540 *length_return = utf8_bytes;
4541 }
4542
4543 char* result = NewArray<char>(utf8_bytes + 1);
4544
4545 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
4546 buffer->Rewind();
4547 buffer->Seek(offset);
4548 character_position = offset;
4549 int utf8_byte_position = 0;
4550 while (buffer->has_more()) {
4551 uint16_t character = buffer->GetNext();
4552 if (character_position < offset + length) {
4553 if (allow_nulls == DISALLOW_NULLS && character == 0) {
4554 character = ' ';
4555 }
4556 utf8_byte_position +=
4557 unibrow::Utf8::Encode(result + utf8_byte_position, character);
4558 }
4559 character_position++;
4560 }
4561 result[utf8_byte_position] = 0;
4562 return SmartPointer<char>(result);
4563}
4564
4565
4566SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4567 RobustnessFlag robust_flag,
4568 int* length_return) {
4569 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
4570}
4571
4572
4573const uc16* String::GetTwoByteData() {
4574 return GetTwoByteData(0);
4575}
4576
4577
4578const uc16* String::GetTwoByteData(unsigned start) {
4579 ASSERT(!IsAsciiRepresentation());
4580 switch (StringShape(this).representation_tag()) {
4581 case kSeqStringTag:
4582 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
4583 case kExternalStringTag:
4584 return ExternalTwoByteString::cast(this)->
4585 ExternalTwoByteStringGetData(start);
Steve Blocka7e24c12009-10-30 11:49:00 +00004586 case kConsStringTag:
4587 UNREACHABLE();
4588 return NULL;
4589 }
4590 UNREACHABLE();
4591 return NULL;
4592}
4593
4594
4595SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004596 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4597 return SmartPointer<uc16>();
4598 }
Steve Block44f0eee2011-05-26 01:26:41 +01004599 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004600
Steve Block44f0eee2011-05-26 01:26:41 +01004601 Access<StringInputBuffer> buffer(
4602 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004603 buffer->Reset(this);
4604
4605 uc16* result = NewArray<uc16>(length() + 1);
4606
4607 int i = 0;
4608 while (buffer->has_more()) {
4609 uint16_t character = buffer->GetNext();
4610 result[i++] = character;
4611 }
4612 result[i] = 0;
4613 return SmartPointer<uc16>(result);
4614}
4615
4616
4617const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
4618 return reinterpret_cast<uc16*>(
4619 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
4620}
4621
4622
4623void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4624 unsigned* offset_ptr,
4625 unsigned max_chars) {
4626 unsigned chars_read = 0;
4627 unsigned offset = *offset_ptr;
4628 while (chars_read < max_chars) {
4629 uint16_t c = *reinterpret_cast<uint16_t*>(
4630 reinterpret_cast<char*>(this) -
4631 kHeapObjectTag + kHeaderSize + offset * kShortSize);
4632 if (c <= kMaxAsciiCharCode) {
4633 // Fast case for ASCII characters. Cursor is an input output argument.
4634 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4635 rbb->util_buffer,
4636 rbb->capacity,
4637 rbb->cursor)) {
4638 break;
4639 }
4640 } else {
4641 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4642 rbb->util_buffer,
4643 rbb->capacity,
4644 rbb->cursor)) {
4645 break;
4646 }
4647 }
4648 offset++;
4649 chars_read++;
4650 }
4651 *offset_ptr = offset;
4652 rbb->remaining += chars_read;
4653}
4654
4655
4656const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
4657 unsigned* remaining,
4658 unsigned* offset_ptr,
4659 unsigned max_chars) {
4660 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
4661 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
4662 *remaining = max_chars;
4663 *offset_ptr += max_chars;
4664 return b;
4665}
4666
4667
4668// This will iterate unless the block of string data spans two 'halves' of
4669// a ConsString, in which case it will recurse. Since the block of string
4670// data to be read has a maximum size this limits the maximum recursion
4671// depth to something sane. Since C++ does not have tail call recursion
4672// elimination, the iteration must be explicit. Since this is not an
4673// -IntoBuffer method it can delegate to one of the efficient
4674// *AsciiStringReadBlock routines.
4675const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
4676 unsigned* offset_ptr,
4677 unsigned max_chars) {
4678 ConsString* current = this;
4679 unsigned offset = *offset_ptr;
4680 int offset_correction = 0;
4681
4682 while (true) {
4683 String* left = current->first();
4684 unsigned left_length = (unsigned)left->length();
4685 if (left_length > offset &&
4686 (max_chars <= left_length - offset ||
4687 (rbb->capacity <= left_length - offset &&
4688 (max_chars = left_length - offset, true)))) { // comma operator!
4689 // Left hand side only - iterate unless we have reached the bottom of
4690 // the cons tree. The assignment on the left of the comma operator is
4691 // in order to make use of the fact that the -IntoBuffer routines can
4692 // produce at most 'capacity' characters. This enables us to postpone
4693 // the point where we switch to the -IntoBuffer routines (below) in order
4694 // to maximize the chances of delegating a big chunk of work to the
4695 // efficient *AsciiStringReadBlock routines.
4696 if (StringShape(left).IsCons()) {
4697 current = ConsString::cast(left);
4698 continue;
4699 } else {
4700 const unibrow::byte* answer =
4701 String::ReadBlock(left, rbb, &offset, max_chars);
4702 *offset_ptr = offset + offset_correction;
4703 return answer;
4704 }
4705 } else if (left_length <= offset) {
4706 // Right hand side only - iterate unless we have reached the bottom of
4707 // the cons tree.
4708 String* right = current->second();
4709 offset -= left_length;
4710 offset_correction += left_length;
4711 if (StringShape(right).IsCons()) {
4712 current = ConsString::cast(right);
4713 continue;
4714 } else {
4715 const unibrow::byte* answer =
4716 String::ReadBlock(right, rbb, &offset, max_chars);
4717 *offset_ptr = offset + offset_correction;
4718 return answer;
4719 }
4720 } else {
4721 // The block to be read spans two sides of the ConsString, so we call the
4722 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
4723 // are able to assemble data from several part strings because they use
4724 // the util_buffer to store their data and never return direct pointers
4725 // to their storage. We don't try to read more than the buffer capacity
4726 // here or we can get too much recursion.
4727 ASSERT(rbb->remaining == 0);
4728 ASSERT(rbb->cursor == 0);
4729 current->ConsStringReadBlockIntoBuffer(
4730 rbb,
4731 &offset,
4732 max_chars > rbb->capacity ? rbb->capacity : max_chars);
4733 *offset_ptr = offset + offset_correction;
4734 return rbb->util_buffer;
4735 }
4736 }
4737}
4738
4739
Steve Blocka7e24c12009-10-30 11:49:00 +00004740uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
4741 ASSERT(index >= 0 && index < length());
4742 return resource()->data()[index];
4743}
4744
4745
4746const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
4747 unsigned* remaining,
4748 unsigned* offset_ptr,
4749 unsigned max_chars) {
4750 // Cast const char* to unibrow::byte* (signedness difference).
4751 const unibrow::byte* b =
4752 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
4753 *remaining = max_chars;
4754 *offset_ptr += max_chars;
4755 return b;
4756}
4757
4758
4759const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
4760 unsigned start) {
4761 return resource()->data() + start;
4762}
4763
4764
4765uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
4766 ASSERT(index >= 0 && index < length());
4767 return resource()->data()[index];
4768}
4769
4770
4771void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
4772 ReadBlockBuffer* rbb,
4773 unsigned* offset_ptr,
4774 unsigned max_chars) {
4775 unsigned chars_read = 0;
4776 unsigned offset = *offset_ptr;
4777 const uint16_t* data = resource()->data();
4778 while (chars_read < max_chars) {
4779 uint16_t c = data[offset];
4780 if (c <= kMaxAsciiCharCode) {
4781 // Fast case for ASCII characters. Cursor is an input output argument.
4782 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4783 rbb->util_buffer,
4784 rbb->capacity,
4785 rbb->cursor))
4786 break;
4787 } else {
4788 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4789 rbb->util_buffer,
4790 rbb->capacity,
4791 rbb->cursor))
4792 break;
4793 }
4794 offset++;
4795 chars_read++;
4796 }
4797 *offset_ptr = offset;
4798 rbb->remaining += chars_read;
4799}
4800
4801
4802void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4803 unsigned* offset_ptr,
4804 unsigned max_chars) {
4805 unsigned capacity = rbb->capacity - rbb->cursor;
4806 if (max_chars > capacity) max_chars = capacity;
4807 memcpy(rbb->util_buffer + rbb->cursor,
4808 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
4809 *offset_ptr * kCharSize,
4810 max_chars);
4811 rbb->remaining += max_chars;
4812 *offset_ptr += max_chars;
4813 rbb->cursor += max_chars;
4814}
4815
4816
4817void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
4818 ReadBlockBuffer* rbb,
4819 unsigned* offset_ptr,
4820 unsigned max_chars) {
4821 unsigned capacity = rbb->capacity - rbb->cursor;
4822 if (max_chars > capacity) max_chars = capacity;
4823 memcpy(rbb->util_buffer + rbb->cursor,
4824 resource()->data() + *offset_ptr,
4825 max_chars);
4826 rbb->remaining += max_chars;
4827 *offset_ptr += max_chars;
4828 rbb->cursor += max_chars;
4829}
4830
4831
4832// This method determines the type of string involved and then copies
4833// a whole chunk of characters into a buffer, or returns a pointer to a buffer
4834// where they can be found. The pointer is not necessarily valid across a GC
4835// (see AsciiStringReadBlock).
4836const unibrow::byte* String::ReadBlock(String* input,
4837 ReadBlockBuffer* rbb,
4838 unsigned* offset_ptr,
4839 unsigned max_chars) {
4840 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
4841 if (max_chars == 0) {
4842 rbb->remaining = 0;
4843 return NULL;
4844 }
4845 switch (StringShape(input).representation_tag()) {
4846 case kSeqStringTag:
4847 if (input->IsAsciiRepresentation()) {
4848 SeqAsciiString* str = SeqAsciiString::cast(input);
4849 return str->SeqAsciiStringReadBlock(&rbb->remaining,
4850 offset_ptr,
4851 max_chars);
4852 } else {
4853 SeqTwoByteString* str = SeqTwoByteString::cast(input);
4854 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
4855 offset_ptr,
4856 max_chars);
4857 return rbb->util_buffer;
4858 }
4859 case kConsStringTag:
4860 return ConsString::cast(input)->ConsStringReadBlock(rbb,
4861 offset_ptr,
4862 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00004863 case kExternalStringTag:
4864 if (input->IsAsciiRepresentation()) {
4865 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
4866 &rbb->remaining,
4867 offset_ptr,
4868 max_chars);
4869 } else {
4870 ExternalTwoByteString::cast(input)->
4871 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
4872 offset_ptr,
4873 max_chars);
4874 return rbb->util_buffer;
4875 }
4876 default:
4877 break;
4878 }
4879
4880 UNREACHABLE();
4881 return 0;
4882}
4883
4884
Steve Blocka7e24c12009-10-30 11:49:00 +00004885void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01004886 Isolate* isolate = Isolate::Current();
4887 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00004888 while (current != NULL) {
4889 current->PostGarbageCollection();
4890 current = current->prev_;
4891 }
4892}
4893
4894
4895// Reserve space for statics needing saving and restoring.
4896int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01004897 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00004898}
4899
4900
4901// Archive statics that are thread local.
4902char* Relocatable::ArchiveState(char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01004903 Isolate* isolate = Isolate::Current();
4904 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
4905 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00004906 return to + ArchiveSpacePerThread();
4907}
4908
4909
4910// Restore statics that are thread local.
4911char* Relocatable::RestoreState(char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01004912 Isolate* isolate = Isolate::Current();
4913 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00004914 return from + ArchiveSpacePerThread();
4915}
4916
4917
4918char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
4919 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
4920 Iterate(v, top);
4921 return thread_storage + ArchiveSpacePerThread();
4922}
4923
4924
4925void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01004926 Isolate* isolate = Isolate::Current();
4927 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00004928}
4929
4930
4931void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
4932 Relocatable* current = top;
4933 while (current != NULL) {
4934 current->IterateInstance(v);
4935 current = current->prev_;
4936 }
4937}
4938
4939
Steve Block44f0eee2011-05-26 01:26:41 +01004940FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
4941 : Relocatable(isolate),
4942 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00004943 length_(str->length()) {
4944 PostGarbageCollection();
4945}
4946
4947
Steve Block44f0eee2011-05-26 01:26:41 +01004948FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
4949 : Relocatable(isolate),
4950 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00004951 is_ascii_(true),
4952 length_(input.length()),
4953 start_(input.start()) { }
4954
4955
4956void FlatStringReader::PostGarbageCollection() {
4957 if (str_ == NULL) return;
4958 Handle<String> str(str_);
4959 ASSERT(str->IsFlat());
4960 is_ascii_ = str->IsAsciiRepresentation();
4961 if (is_ascii_) {
4962 start_ = str->ToAsciiVector().start();
4963 } else {
4964 start_ = str->ToUC16Vector().start();
4965 }
4966}
4967
4968
4969void StringInputBuffer::Seek(unsigned pos) {
4970 Reset(pos, input_);
4971}
4972
4973
4974void SafeStringInputBuffer::Seek(unsigned pos) {
4975 Reset(pos, input_);
4976}
4977
4978
4979// This method determines the type of string involved and then copies
4980// a whole chunk of characters into a buffer. It can be used with strings
4981// that have been glued together to form a ConsString and which must cooperate
4982// to fill up a buffer.
4983void String::ReadBlockIntoBuffer(String* input,
4984 ReadBlockBuffer* rbb,
4985 unsigned* offset_ptr,
4986 unsigned max_chars) {
4987 ASSERT(*offset_ptr <= (unsigned)input->length());
4988 if (max_chars == 0) return;
4989
4990 switch (StringShape(input).representation_tag()) {
4991 case kSeqStringTag:
4992 if (input->IsAsciiRepresentation()) {
4993 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
4994 offset_ptr,
4995 max_chars);
4996 return;
4997 } else {
4998 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
4999 offset_ptr,
5000 max_chars);
5001 return;
5002 }
5003 case kConsStringTag:
5004 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5005 offset_ptr,
5006 max_chars);
5007 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005008 case kExternalStringTag:
5009 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005010 ExternalAsciiString::cast(input)->
5011 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5012 } else {
5013 ExternalTwoByteString::cast(input)->
5014 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5015 offset_ptr,
5016 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005017 }
5018 return;
5019 default:
5020 break;
5021 }
5022
5023 UNREACHABLE();
5024 return;
5025}
5026
5027
5028const unibrow::byte* String::ReadBlock(String* input,
5029 unibrow::byte* util_buffer,
5030 unsigned capacity,
5031 unsigned* remaining,
5032 unsigned* offset_ptr) {
5033 ASSERT(*offset_ptr <= (unsigned)input->length());
5034 unsigned chars = input->length() - *offset_ptr;
5035 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5036 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5037 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5038 *remaining = rbb.remaining;
5039 return answer;
5040}
5041
5042
5043const unibrow::byte* String::ReadBlock(String** raw_input,
5044 unibrow::byte* util_buffer,
5045 unsigned capacity,
5046 unsigned* remaining,
5047 unsigned* offset_ptr) {
5048 Handle<String> input(raw_input);
5049 ASSERT(*offset_ptr <= (unsigned)input->length());
5050 unsigned chars = input->length() - *offset_ptr;
5051 if (chars > capacity) chars = capacity;
5052 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5053 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5054 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5055 *remaining = rbb.remaining;
5056 return rbb.util_buffer;
5057}
5058
5059
5060// This will iterate unless the block of string data spans two 'halves' of
5061// a ConsString, in which case it will recurse. Since the block of string
5062// data to be read has a maximum size this limits the maximum recursion
5063// depth to something sane. Since C++ does not have tail call recursion
5064// elimination, the iteration must be explicit.
5065void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5066 unsigned* offset_ptr,
5067 unsigned max_chars) {
5068 ConsString* current = this;
5069 unsigned offset = *offset_ptr;
5070 int offset_correction = 0;
5071
5072 while (true) {
5073 String* left = current->first();
5074 unsigned left_length = (unsigned)left->length();
5075 if (left_length > offset &&
5076 max_chars <= left_length - offset) {
5077 // Left hand side only - iterate unless we have reached the bottom of
5078 // the cons tree.
5079 if (StringShape(left).IsCons()) {
5080 current = ConsString::cast(left);
5081 continue;
5082 } else {
5083 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5084 *offset_ptr = offset + offset_correction;
5085 return;
5086 }
5087 } else if (left_length <= offset) {
5088 // Right hand side only - iterate unless we have reached the bottom of
5089 // the cons tree.
5090 offset -= left_length;
5091 offset_correction += left_length;
5092 String* right = current->second();
5093 if (StringShape(right).IsCons()) {
5094 current = ConsString::cast(right);
5095 continue;
5096 } else {
5097 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5098 *offset_ptr = offset + offset_correction;
5099 return;
5100 }
5101 } else {
5102 // The block to be read spans two sides of the ConsString, so we recurse.
5103 // First recurse on the left.
5104 max_chars -= left_length - offset;
5105 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5106 // We may have reached the max or there may not have been enough space
5107 // in the buffer for the characters in the left hand side.
5108 if (offset == left_length) {
5109 // Recurse on the right.
5110 String* right = String::cast(current->second());
5111 offset -= left_length;
5112 offset_correction += left_length;
5113 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5114 }
5115 *offset_ptr = offset + offset_correction;
5116 return;
5117 }
5118 }
5119}
5120
5121
Steve Blocka7e24c12009-10-30 11:49:00 +00005122uint16_t ConsString::ConsStringGet(int index) {
5123 ASSERT(index >= 0 && index < this->length());
5124
5125 // Check for a flattened cons string
5126 if (second()->length() == 0) {
5127 String* left = first();
5128 return left->Get(index);
5129 }
5130
5131 String* string = String::cast(this);
5132
5133 while (true) {
5134 if (StringShape(string).IsCons()) {
5135 ConsString* cons_string = ConsString::cast(string);
5136 String* left = cons_string->first();
5137 if (left->length() > index) {
5138 string = left;
5139 } else {
5140 index -= left->length();
5141 string = cons_string->second();
5142 }
5143 } else {
5144 return string->Get(index);
5145 }
5146 }
5147
5148 UNREACHABLE();
5149 return 0;
5150}
5151
5152
5153template <typename sinkchar>
5154void String::WriteToFlat(String* src,
5155 sinkchar* sink,
5156 int f,
5157 int t) {
5158 String* source = src;
5159 int from = f;
5160 int to = t;
5161 while (true) {
5162 ASSERT(0 <= from && from <= to && to <= source->length());
5163 switch (StringShape(source).full_representation_tag()) {
5164 case kAsciiStringTag | kExternalStringTag: {
5165 CopyChars(sink,
5166 ExternalAsciiString::cast(source)->resource()->data() + from,
5167 to - from);
5168 return;
5169 }
5170 case kTwoByteStringTag | kExternalStringTag: {
5171 const uc16* data =
5172 ExternalTwoByteString::cast(source)->resource()->data();
5173 CopyChars(sink,
5174 data + from,
5175 to - from);
5176 return;
5177 }
5178 case kAsciiStringTag | kSeqStringTag: {
5179 CopyChars(sink,
5180 SeqAsciiString::cast(source)->GetChars() + from,
5181 to - from);
5182 return;
5183 }
5184 case kTwoByteStringTag | kSeqStringTag: {
5185 CopyChars(sink,
5186 SeqTwoByteString::cast(source)->GetChars() + from,
5187 to - from);
5188 return;
5189 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005190 case kAsciiStringTag | kConsStringTag:
5191 case kTwoByteStringTag | kConsStringTag: {
5192 ConsString* cons_string = ConsString::cast(source);
5193 String* first = cons_string->first();
5194 int boundary = first->length();
5195 if (to - boundary >= boundary - from) {
5196 // Right hand side is longer. Recurse over left.
5197 if (from < boundary) {
5198 WriteToFlat(first, sink, from, boundary);
5199 sink += boundary - from;
5200 from = 0;
5201 } else {
5202 from -= boundary;
5203 }
5204 to -= boundary;
5205 source = cons_string->second();
5206 } else {
5207 // Left hand side is longer. Recurse over right.
5208 if (to > boundary) {
5209 String* second = cons_string->second();
5210 WriteToFlat(second,
5211 sink + boundary - from,
5212 0,
5213 to - boundary);
5214 to = boundary;
5215 }
5216 source = first;
5217 }
5218 break;
5219 }
5220 }
5221 }
5222}
5223
5224
Steve Blocka7e24c12009-10-30 11:49:00 +00005225template <typename IteratorA, typename IteratorB>
5226static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5227 // General slow case check. We know that the ia and ib iterators
5228 // have the same length.
5229 while (ia->has_more()) {
5230 uc32 ca = ia->GetNext();
5231 uc32 cb = ib->GetNext();
5232 if (ca != cb)
5233 return false;
5234 }
5235 return true;
5236}
5237
5238
5239// Compares the contents of two strings by reading and comparing
5240// int-sized blocks of characters.
5241template <typename Char>
5242static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5243 int length = a.length();
5244 ASSERT_EQ(length, b.length());
5245 const Char* pa = a.start();
5246 const Char* pb = b.start();
5247 int i = 0;
5248#ifndef V8_HOST_CAN_READ_UNALIGNED
5249 // If this architecture isn't comfortable reading unaligned ints
5250 // then we have to check that the strings are aligned before
5251 // comparing them blockwise.
5252 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5253 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5254 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5255 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5256#endif
5257 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5258 int endpoint = length - kStepSize;
5259 // Compare blocks until we reach near the end of the string.
5260 for (; i <= endpoint; i += kStepSize) {
5261 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5262 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5263 if (wa != wb) {
5264 return false;
5265 }
5266 }
5267#ifndef V8_HOST_CAN_READ_UNALIGNED
5268 }
5269#endif
5270 // Compare the remaining characters that didn't fit into a block.
5271 for (; i < length; i++) {
5272 if (a[i] != b[i]) {
5273 return false;
5274 }
5275 }
5276 return true;
5277}
5278
5279
Steve Blocka7e24c12009-10-30 11:49:00 +00005280template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005281static inline bool CompareStringContentsPartial(Isolate* isolate,
5282 IteratorA* ia,
5283 String* b) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005284 if (b->IsFlat()) {
5285 if (b->IsAsciiRepresentation()) {
5286 VectorIterator<char> ib(b->ToAsciiVector());
5287 return CompareStringContents(ia, &ib);
5288 } else {
5289 VectorIterator<uc16> ib(b->ToUC16Vector());
5290 return CompareStringContents(ia, &ib);
5291 }
5292 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005293 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5294 return CompareStringContents(ia,
5295 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005296 }
5297}
5298
5299
Steve Blocka7e24c12009-10-30 11:49:00 +00005300bool String::SlowEquals(String* other) {
5301 // Fast check: negative check with lengths.
5302 int len = length();
5303 if (len != other->length()) return false;
5304 if (len == 0) return true;
5305
5306 // Fast check: if hash code is computed for both strings
5307 // a fast negative check can be performed.
5308 if (HasHashCode() && other->HasHashCode()) {
5309 if (Hash() != other->Hash()) return false;
5310 }
5311
Leon Clarkef7060e22010-06-03 12:02:55 +01005312 // We know the strings are both non-empty. Compare the first chars
5313 // before we try to flatten the strings.
5314 if (this->Get(0) != other->Get(0)) return false;
5315
5316 String* lhs = this->TryFlattenGetString();
5317 String* rhs = other->TryFlattenGetString();
5318
5319 if (StringShape(lhs).IsSequentialAscii() &&
5320 StringShape(rhs).IsSequentialAscii()) {
5321 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5322 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005323 return CompareRawStringContents(Vector<const char>(str1, len),
5324 Vector<const char>(str2, len));
5325 }
5326
Steve Block44f0eee2011-05-26 01:26:41 +01005327 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01005328 if (lhs->IsFlat()) {
Ben Murdochbb769b22010-08-11 14:56:33 +01005329 if (lhs->IsAsciiRepresentation()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01005330 Vector<const char> vec1 = lhs->ToAsciiVector();
5331 if (rhs->IsFlat()) {
5332 if (rhs->IsAsciiRepresentation()) {
5333 Vector<const char> vec2 = rhs->ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005334 return CompareRawStringContents(vec1, vec2);
5335 } else {
5336 VectorIterator<char> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005337 VectorIterator<uc16> ib(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005338 return CompareStringContents(&buf1, &ib);
5339 }
5340 } else {
5341 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005342 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5343 return CompareStringContents(&buf1,
5344 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005345 }
5346 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005347 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5348 if (rhs->IsFlat()) {
5349 if (rhs->IsAsciiRepresentation()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005350 VectorIterator<uc16> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005351 VectorIterator<char> ib(rhs->ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005352 return CompareStringContents(&buf1, &ib);
5353 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005354 Vector<const uc16> vec2(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005355 return CompareRawStringContents(vec1, vec2);
5356 }
5357 } else {
5358 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005359 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5360 return CompareStringContents(&buf1,
5361 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005362 }
5363 }
5364 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005365 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5366 return CompareStringContentsPartial(isolate,
5367 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00005368 }
5369}
5370
5371
5372bool String::MarkAsUndetectable() {
5373 if (StringShape(this).IsSymbol()) return false;
5374
5375 Map* map = this->map();
Steve Block44f0eee2011-05-26 01:26:41 +01005376 Heap* heap = map->GetHeap();
5377 if (map == heap->string_map()) {
5378 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005379 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01005380 } else if (map == heap->ascii_string_map()) {
5381 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005382 return true;
5383 }
5384 // Rest cannot be marked as undetectable
5385 return false;
5386}
5387
5388
5389bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01005390 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00005391 int slen = length();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08005392 Access<ScannerConstants::Utf8Decoder>
Steve Block44f0eee2011-05-26 01:26:41 +01005393 decoder(isolate->scanner_constants()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00005394 decoder->Reset(str.start(), str.length());
5395 int i;
5396 for (i = 0; i < slen && decoder->has_more(); i++) {
5397 uc32 r = decoder->GetNext();
5398 if (Get(i) != r) return false;
5399 }
5400 return i == slen && !decoder->has_more();
5401}
5402
5403
Steve Block9fac8402011-05-12 15:51:54 +01005404bool String::IsAsciiEqualTo(Vector<const char> str) {
5405 int slen = length();
5406 if (str.length() != slen) return false;
5407 for (int i = 0; i < slen; i++) {
5408 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
5409 }
5410 return true;
5411}
5412
5413
5414bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
5415 int slen = length();
5416 if (str.length() != slen) return false;
5417 for (int i = 0; i < slen; i++) {
5418 if (Get(i) != str[i]) return false;
5419 }
5420 return true;
5421}
5422
5423
Steve Blocka7e24c12009-10-30 11:49:00 +00005424uint32_t String::ComputeAndSetHash() {
5425 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005426 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005427
Steve Block6ded16b2010-05-10 14:33:55 +01005428 const int len = length();
5429
Steve Blocka7e24c12009-10-30 11:49:00 +00005430 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01005431 uint32_t field = 0;
5432 if (StringShape(this).IsSequentialAscii()) {
5433 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
5434 } else if (StringShape(this).IsSequentialTwoByte()) {
5435 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
5436 } else {
5437 StringInputBuffer buffer(this);
5438 field = ComputeHashField(&buffer, len);
5439 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005440
5441 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00005442 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00005443
5444 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005445 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005446 uint32_t result = field >> kHashShift;
5447 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
5448 return result;
5449}
5450
5451
5452bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
5453 uint32_t* index,
5454 int length) {
5455 if (length == 0 || length > kMaxArrayIndexSize) return false;
5456 uc32 ch = buffer->GetNext();
5457
5458 // If the string begins with a '0' character, it must only consist
5459 // of it to be a legal array index.
5460 if (ch == '0') {
5461 *index = 0;
5462 return length == 1;
5463 }
5464
5465 // Convert string to uint32 array index; character by character.
5466 int d = ch - '0';
5467 if (d < 0 || d > 9) return false;
5468 uint32_t result = d;
5469 while (buffer->has_more()) {
5470 d = buffer->GetNext() - '0';
5471 if (d < 0 || d > 9) return false;
5472 // Check that the new result is below the 32 bit limit.
5473 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
5474 result = (result * 10) + d;
5475 }
5476
5477 *index = result;
5478 return true;
5479}
5480
5481
5482bool String::SlowAsArrayIndex(uint32_t* index) {
5483 if (length() <= kMaxCachedArrayIndexLength) {
5484 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00005485 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005486 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00005487 // Isolate the array index form the full hash field.
5488 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00005489 return true;
5490 } else {
5491 StringInputBuffer buffer(this);
5492 return ComputeArrayIndex(&buffer, index, length());
5493 }
5494}
5495
5496
Iain Merrick9ac36c92010-09-13 15:29:50 +01005497uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005498 // For array indexes mix the length into the hash as an array index could
5499 // be zero.
5500 ASSERT(length > 0);
5501 ASSERT(length <= String::kMaxArrayIndexSize);
5502 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5503 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01005504
5505 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005506 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01005507
5508 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
5509 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
5510 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005511 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00005512}
5513
5514
5515uint32_t StringHasher::GetHashField() {
5516 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00005517 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005518 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005519 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00005520 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005521 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005522 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005523 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005524 }
5525}
5526
5527
Steve Blockd0582a62009-12-15 09:54:21 +00005528uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
5529 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005530 StringHasher hasher(length);
5531
5532 // Very long strings have a trivial hash that doesn't inspect the
5533 // string contents.
5534 if (hasher.has_trivial_hash()) {
5535 return hasher.GetHashField();
5536 }
5537
5538 // Do the iterative array index computation as long as there is a
5539 // chance this is an array index.
5540 while (buffer->has_more() && hasher.is_array_index()) {
5541 hasher.AddCharacter(buffer->GetNext());
5542 }
5543
5544 // Process the remaining characters without updating the array
5545 // index.
5546 while (buffer->has_more()) {
5547 hasher.AddCharacterNoIndex(buffer->GetNext());
5548 }
5549
5550 return hasher.GetHashField();
5551}
5552
5553
John Reck59135872010-11-02 12:39:01 -07005554MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005555 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005556 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01005557 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00005558 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005559}
5560
5561
5562void String::PrintOn(FILE* file) {
5563 int length = this->length();
5564 for (int i = 0; i < length; i++) {
5565 fprintf(file, "%c", Get(i));
5566 }
5567}
5568
5569
5570void Map::CreateBackPointers() {
5571 DescriptorArray* descriptors = instance_descriptors();
5572 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01005573 if (descriptors->GetType(i) == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005574 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005575 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005576 // Get target.
5577 Map* target = Map::cast(descriptors->GetValue(i));
5578#ifdef DEBUG
5579 // Verify target.
5580 Object* source_prototype = prototype();
5581 Object* target_prototype = target->prototype();
5582 ASSERT(source_prototype->IsJSObject() ||
5583 source_prototype->IsMap() ||
5584 source_prototype->IsNull());
5585 ASSERT(target_prototype->IsJSObject() ||
5586 target_prototype->IsNull());
5587 ASSERT(source_prototype->IsMap() ||
5588 source_prototype == target_prototype);
5589#endif
5590 // Point target back to source. set_prototype() will not let us set
5591 // the prototype to a map, as we do here.
5592 *RawField(target, kPrototypeOffset) = this;
5593 }
5594 }
5595}
5596
5597
Steve Block44f0eee2011-05-26 01:26:41 +01005598void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005599 // Live DescriptorArray objects will be marked, so we must use
5600 // low-level accessors to get and modify their data.
5601 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
5602 *RawField(this, Map::kInstanceDescriptorsOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01005603 if (d == heap->raw_unchecked_empty_descriptor_array()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005604 Smi* NullDescriptorDetails =
5605 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
5606 FixedArray* contents = reinterpret_cast<FixedArray*>(
5607 d->get(DescriptorArray::kContentArrayIndex));
5608 ASSERT(contents->length() >= 2);
5609 for (int i = 0; i < contents->length(); i += 2) {
5610 // If the pair (value, details) is a map transition,
5611 // check if the target is live. If not, null the descriptor.
5612 // Also drop the back pointer for that map transition, so that this
5613 // map is not reached again by following a back pointer from a
5614 // non-live object.
5615 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01005616 if (details.type() == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005617 details.type() == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005618 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005619 Map* target = reinterpret_cast<Map*>(contents->get(i));
5620 ASSERT(target->IsHeapObject());
5621 if (!target->IsMarked()) {
5622 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01005623 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01005624 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00005625 ASSERT(target->prototype() == this ||
5626 target->prototype() == real_prototype);
5627 // Getter prototype() is read-only, set_prototype() has side effects.
5628 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5629 }
5630 }
5631 }
5632}
5633
5634
Steve Block791712a2010-08-27 10:21:07 +01005635void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5636 // Iterate over all fields in the body but take care in dealing with
5637 // the code entry.
5638 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5639 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5640 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5641}
5642
5643
Ben Murdochb0fe1622011-05-05 13:52:32 +01005644void JSFunction::MarkForLazyRecompilation() {
5645 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005646 ASSERT(shared()->allows_lazy_compilation() ||
5647 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01005648 Builtins* builtins = GetIsolate()->builtins();
5649 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005650}
5651
5652
5653uint32_t JSFunction::SourceHash() {
5654 uint32_t hash = 0;
5655 Object* script = shared()->script();
5656 if (!script->IsUndefined()) {
5657 Object* source = Script::cast(script)->source();
5658 if (source->IsUndefined()) hash = String::cast(source)->Hash();
5659 }
5660 hash ^= ComputeIntegerHash(shared()->start_position_and_type());
5661 hash += ComputeIntegerHash(shared()->end_position());
5662 return hash;
5663}
5664
5665
5666bool JSFunction::IsInlineable() {
5667 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005668 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005669 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005670 if (!shared_info->script()->IsScript()) return false;
5671 if (shared_info->optimization_disabled()) return false;
5672 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005673 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
5674 // If we never ran this (unlikely) then lets try to optimize it.
5675 if (code->kind() != Code::FUNCTION) return true;
5676 return code->optimizable();
5677}
5678
5679
Steve Blocka7e24c12009-10-30 11:49:00 +00005680Object* JSFunction::SetInstancePrototype(Object* value) {
5681 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01005682 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005683 if (has_initial_map()) {
5684 initial_map()->set_prototype(value);
5685 } else {
5686 // Put the value in the initial map field until an initial map is
5687 // needed. At that point, a new initial map is created and the
5688 // prototype is put into the initial map where it belongs.
5689 set_prototype_or_initial_map(value);
5690 }
Steve Block44f0eee2011-05-26 01:26:41 +01005691 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005692 return value;
5693}
5694
5695
John Reck59135872010-11-02 12:39:01 -07005696MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01005697 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00005698 Object* construct_prototype = value;
5699
5700 // If the value is not a JSObject, store the value in the map's
5701 // constructor field so it can be accessed. Also, set the prototype
5702 // used for constructing objects to the original object prototype.
5703 // See ECMA-262 13.2.2.
5704 if (!value->IsJSObject()) {
Steve Block44f0eee2011-05-26 01:26:41 +01005705 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005706 // Copy the map so this does not affect unrelated functions.
5707 // Remove map transitions because they point to maps with a
5708 // different prototype.
John Reck59135872010-11-02 12:39:01 -07005709 Object* new_map;
5710 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
5711 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
5712 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005713 set_map(Map::cast(new_map));
5714 map()->set_constructor(value);
5715 map()->set_non_instance_prototype(true);
5716 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01005717 heap->isolate()->context()->global_context()->
5718 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00005719 } else {
5720 map()->set_non_instance_prototype(false);
5721 }
5722
5723 return SetInstancePrototype(construct_prototype);
5724}
5725
5726
Steve Block6ded16b2010-05-10 14:33:55 +01005727Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01005728 Context* global_context = context()->global_context();
5729 Map* no_prototype_map = shared()->strict_mode()
5730 ? global_context->strict_mode_function_without_prototype_map()
5731 : global_context->function_without_prototype_map();
5732
5733 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005734 // Be idempotent.
5735 return this;
5736 }
Steve Block44f0eee2011-05-26 01:26:41 +01005737
5738 ASSERT(!shared()->strict_mode() ||
5739 map() == global_context->strict_mode_function_map());
5740 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
5741
5742 set_map(no_prototype_map);
5743 set_prototype_or_initial_map(GetHeap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005744 return this;
5745}
5746
5747
Steve Blocka7e24c12009-10-30 11:49:00 +00005748Object* JSFunction::SetInstanceClassName(String* name) {
5749 shared()->set_instance_class_name(name);
5750 return this;
5751}
5752
5753
Ben Murdochb0fe1622011-05-05 13:52:32 +01005754void JSFunction::PrintName(FILE* out) {
5755 SmartPointer<char> name = shared()->DebugName()->ToCString();
5756 PrintF(out, "%s", *name);
5757}
5758
5759
Steve Blocka7e24c12009-10-30 11:49:00 +00005760Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
5761 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
5762}
5763
5764
Steve Block44f0eee2011-05-26 01:26:41 +01005765MaybeObject* Oddball::Initialize(const char* to_string,
5766 Object* to_number,
5767 byte kind) {
John Reck59135872010-11-02 12:39:01 -07005768 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01005769 { MaybeObject* maybe_symbol =
5770 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07005771 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
5772 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005773 set_to_string(String::cast(symbol));
5774 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01005775 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00005776 return this;
5777}
5778
5779
Ben Murdochf87a2032010-10-22 12:50:53 +01005780String* SharedFunctionInfo::DebugName() {
5781 Object* n = name();
5782 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
5783 return String::cast(n);
5784}
5785
5786
Steve Blocka7e24c12009-10-30 11:49:00 +00005787bool SharedFunctionInfo::HasSourceCode() {
5788 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01005789 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00005790}
5791
5792
5793Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01005794 Isolate* isolate = GetIsolate();
5795 if (!HasSourceCode()) return isolate->heap()->undefined_value();
5796 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005797 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01005798 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00005799 start_position(), end_position());
5800}
5801
5802
Ben Murdochb0fe1622011-05-05 13:52:32 +01005803int SharedFunctionInfo::SourceSize() {
5804 return end_position() - start_position();
5805}
5806
5807
Steve Blocka7e24c12009-10-30 11:49:00 +00005808int SharedFunctionInfo::CalculateInstanceSize() {
5809 int instance_size =
5810 JSObject::kHeaderSize +
5811 expected_nof_properties() * kPointerSize;
5812 if (instance_size > JSObject::kMaxInstanceSize) {
5813 instance_size = JSObject::kMaxInstanceSize;
5814 }
5815 return instance_size;
5816}
5817
5818
5819int SharedFunctionInfo::CalculateInObjectProperties() {
5820 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
5821}
5822
5823
Andrei Popescu402d9372010-02-26 13:31:12 +00005824bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01005825 Heap* heap = GetHeap();
5826
Andrei Popescu402d9372010-02-26 13:31:12 +00005827 // Check the basic conditions for generating inline constructor code.
5828 if (!FLAG_inline_new
5829 || !has_only_simple_this_property_assignments()
5830 || this_property_assignments_count() == 0) {
5831 return false;
5832 }
5833
5834 // If the prototype is null inline constructors cause no problems.
5835 if (!prototype->IsJSObject()) {
5836 ASSERT(prototype->IsNull());
5837 return true;
5838 }
5839
5840 // Traverse the proposed prototype chain looking for setters for properties of
5841 // the same names as are set by the inline constructor.
5842 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01005843 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00005844 obj = obj->GetPrototype()) {
5845 JSObject* js_object = JSObject::cast(obj);
5846 for (int i = 0; i < this_property_assignments_count(); i++) {
5847 LookupResult result;
5848 String* name = GetThisPropertyAssignmentName(i);
5849 js_object->LocalLookupRealNamedProperty(name, &result);
5850 if (result.IsProperty() && result.type() == CALLBACKS) {
5851 return false;
5852 }
5853 }
5854 }
5855
5856 return true;
5857}
5858
5859
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005860void SharedFunctionInfo::ForbidInlineConstructor() {
5861 set_compiler_hints(BooleanBit::set(compiler_hints(),
5862 kHasOnlySimpleThisPropertyAssignments,
5863 false));
5864}
5865
5866
Steve Blocka7e24c12009-10-30 11:49:00 +00005867void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00005868 bool only_simple_this_property_assignments,
5869 FixedArray* assignments) {
5870 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00005871 kHasOnlySimpleThisPropertyAssignments,
5872 only_simple_this_property_assignments));
5873 set_this_property_assignments(assignments);
5874 set_this_property_assignments_count(assignments->length() / 3);
5875}
5876
5877
5878void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01005879 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005880 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00005881 kHasOnlySimpleThisPropertyAssignments,
5882 false));
Steve Block44f0eee2011-05-26 01:26:41 +01005883 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00005884 set_this_property_assignments_count(0);
5885}
5886
5887
5888String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
5889 Object* obj = this_property_assignments();
5890 ASSERT(obj->IsFixedArray());
5891 ASSERT(index < this_property_assignments_count());
5892 obj = FixedArray::cast(obj)->get(index * 3);
5893 ASSERT(obj->IsString());
5894 return String::cast(obj);
5895}
5896
5897
5898bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
5899 Object* obj = this_property_assignments();
5900 ASSERT(obj->IsFixedArray());
5901 ASSERT(index < this_property_assignments_count());
5902 obj = FixedArray::cast(obj)->get(index * 3 + 1);
5903 return Smi::cast(obj)->value() != -1;
5904}
5905
5906
5907int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
5908 ASSERT(IsThisPropertyAssignmentArgument(index));
5909 Object* obj =
5910 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
5911 return Smi::cast(obj)->value();
5912}
5913
5914
5915Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
5916 ASSERT(!IsThisPropertyAssignmentArgument(index));
5917 Object* obj =
5918 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
5919 return obj;
5920}
5921
5922
Steve Blocka7e24c12009-10-30 11:49:00 +00005923// Support function for printing the source code to a StringStream
5924// without any allocation in the heap.
5925void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
5926 int max_length) {
5927 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01005928 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005929 accumulator->Add("<No Source>");
5930 return;
5931 }
5932
Steve Blockd0582a62009-12-15 09:54:21 +00005933 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00005934 // Don't use String::cast because we don't want more assertion errors while
5935 // we are already creating a stack dump.
5936 String* script_source =
5937 reinterpret_cast<String*>(Script::cast(script())->source());
5938
5939 if (!script_source->LooksValid()) {
5940 accumulator->Add("<Invalid Source>");
5941 return;
5942 }
5943
5944 if (!is_toplevel()) {
5945 accumulator->Add("function ");
5946 Object* name = this->name();
5947 if (name->IsString() && String::cast(name)->length() > 0) {
5948 accumulator->PrintName(name);
5949 }
5950 }
5951
5952 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005953 if (len <= max_length || max_length < 0) {
5954 accumulator->Put(script_source, start_position(), end_position());
5955 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00005956 accumulator->Put(script_source,
5957 start_position(),
5958 start_position() + max_length);
5959 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00005960 }
5961}
5962
5963
Ben Murdochb0fe1622011-05-05 13:52:32 +01005964static bool IsCodeEquivalent(Code* code, Code* recompiled) {
5965 if (code->instruction_size() != recompiled->instruction_size()) return false;
5966 ByteArray* code_relocation = code->relocation_info();
5967 ByteArray* recompiled_relocation = recompiled->relocation_info();
5968 int length = code_relocation->length();
5969 if (length != recompiled_relocation->length()) return false;
5970 int compare = memcmp(code_relocation->GetDataStartAddress(),
5971 recompiled_relocation->GetDataStartAddress(),
5972 length);
5973 return compare == 0;
5974}
5975
5976
5977void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
5978 ASSERT(!has_deoptimization_support());
5979 AssertNoAllocation no_allocation;
5980 Code* code = this->code();
5981 if (IsCodeEquivalent(code, recompiled)) {
5982 // Copy the deoptimization data from the recompiled code.
5983 code->set_deoptimization_data(recompiled->deoptimization_data());
5984 code->set_has_deoptimization_support(true);
5985 } else {
5986 // TODO(3025757): In case the recompiled isn't equivalent to the
5987 // old code, we have to replace it. We should try to avoid this
5988 // altogether because it flushes valuable type feedback by
5989 // effectively resetting all IC state.
5990 set_code(recompiled);
5991 }
5992 ASSERT(has_deoptimization_support());
5993}
5994
5995
5996bool SharedFunctionInfo::VerifyBailoutId(int id) {
5997 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
5998 // we are always bailing out on ARM.
5999
6000 ASSERT(id != AstNode::kNoNumber);
6001 Code* unoptimized = code();
6002 DeoptimizationOutputData* data =
6003 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6004 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6005 USE(ignore);
6006 return true; // Return true if there was no ASSERT.
6007}
6008
6009
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006010void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6011 ASSERT(!IsInobjectSlackTrackingInProgress());
6012
6013 // Only initiate the tracking the first time.
6014 if (live_objects_may_exist()) return;
6015 set_live_objects_may_exist(true);
6016
6017 // No tracking during the snapshot construction phase.
6018 if (Serializer::enabled()) return;
6019
6020 if (map->unused_property_fields() == 0) return;
6021
6022 // Nonzero counter is a leftover from the previous attempt interrupted
6023 // by GC, keep it.
6024 if (construction_count() == 0) {
6025 set_construction_count(kGenerousAllocationCount);
6026 }
6027 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006028 Builtins* builtins = map->heap()->isolate()->builtins();
6029 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006030 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006031 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006032}
6033
6034
6035// Called from GC, hence reinterpret_cast and unchecked accessors.
6036void SharedFunctionInfo::DetachInitialMap() {
6037 Map* map = reinterpret_cast<Map*>(initial_map());
6038
6039 // Make the map remember to restore the link if it survives the GC.
6040 map->set_bit_field2(
6041 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6042
6043 // Undo state changes made by StartInobjectTracking (except the
6044 // construction_count). This way if the initial map does not survive the GC
6045 // then StartInobjectTracking will be called again the next time the
6046 // constructor is called. The countdown will continue and (possibly after
6047 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006048 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6049 Builtins* builtins = map->heap()->isolate()->builtins();
6050 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006051 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006052 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006053 // It is safe to clear the flag: it will be set again if the map is live.
6054 set_live_objects_may_exist(false);
6055}
6056
6057
6058// Called from GC, hence reinterpret_cast and unchecked accessors.
6059void SharedFunctionInfo::AttachInitialMap(Map* map) {
6060 map->set_bit_field2(
6061 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6062
6063 // Resume inobject slack tracking.
6064 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006065 Builtins* builtins = map->heap()->isolate()->builtins();
6066 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006067 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006068 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006069 // The map survived the gc, so there may be objects referencing it.
6070 set_live_objects_may_exist(true);
6071}
6072
6073
6074static void GetMinInobjectSlack(Map* map, void* data) {
6075 int slack = map->unused_property_fields();
6076 if (*reinterpret_cast<int*>(data) > slack) {
6077 *reinterpret_cast<int*>(data) = slack;
6078 }
6079}
6080
6081
6082static void ShrinkInstanceSize(Map* map, void* data) {
6083 int slack = *reinterpret_cast<int*>(data);
6084 map->set_inobject_properties(map->inobject_properties() - slack);
6085 map->set_unused_property_fields(map->unused_property_fields() - slack);
6086 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6087
6088 // Visitor id might depend on the instance size, recalculate it.
6089 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6090}
6091
6092
6093void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6094 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6095 Map* map = Map::cast(initial_map());
6096
Steve Block44f0eee2011-05-26 01:26:41 +01006097 Heap* heap = map->heap();
6098 set_initial_map(heap->undefined_value());
6099 Builtins* builtins = heap->isolate()->builtins();
6100 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006101 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006102 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006103
6104 int slack = map->unused_property_fields();
6105 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6106 if (slack != 0) {
6107 // Resize the initial map and all maps in its transition tree.
6108 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
6109 // Give the correct expected_nof_properties to initial maps created later.
6110 ASSERT(expected_nof_properties() >= slack);
6111 set_expected_nof_properties(expected_nof_properties() - slack);
6112 }
6113}
6114
6115
Steve Blocka7e24c12009-10-30 11:49:00 +00006116void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6117 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6118 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6119 Object* old_target = target;
6120 VisitPointer(&target);
6121 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6122}
6123
6124
Steve Block791712a2010-08-27 10:21:07 +01006125void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6126 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6127 Object* old_code = code;
6128 VisitPointer(&code);
6129 if (code != old_code) {
6130 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6131 }
6132}
6133
6134
Ben Murdochb0fe1622011-05-05 13:52:32 +01006135void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6136 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6137 Object* cell = rinfo->target_cell();
6138 Object* old_cell = cell;
6139 VisitPointer(&cell);
6140 if (cell != old_cell) {
6141 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6142 }
6143}
6144
6145
Steve Blocka7e24c12009-10-30 11:49:00 +00006146void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006147 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6148 rinfo->IsPatchedReturnSequence()) ||
6149 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6150 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006151 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6152 Object* old_target = target;
6153 VisitPointer(&target);
6154 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6155}
6156
6157
Ben Murdochb0fe1622011-05-05 13:52:32 +01006158void Code::InvalidateRelocation() {
Steve Block44f0eee2011-05-26 01:26:41 +01006159 set_relocation_info(GetHeap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006160}
6161
6162
Steve Blockd0582a62009-12-15 09:54:21 +00006163void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006164 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6165 it.rinfo()->apply(delta);
6166 }
6167 CPU::FlushICache(instruction_start(), instruction_size());
6168}
6169
6170
6171void Code::CopyFrom(const CodeDesc& desc) {
6172 // copy code
6173 memmove(instruction_start(), desc.buffer, desc.instr_size);
6174
Steve Blocka7e24c12009-10-30 11:49:00 +00006175 // copy reloc info
6176 memmove(relocation_start(),
6177 desc.buffer + desc.buffer_size - desc.reloc_size,
6178 desc.reloc_size);
6179
6180 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006181 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006182 int mode_mask = RelocInfo::kCodeTargetMask |
6183 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006184 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006185 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006186 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006187 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6188 RelocInfo::Mode mode = it.rinfo()->rmode();
6189 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006190 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006191 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006192 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006193 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006194 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006195 } else if (RelocInfo::IsCodeTarget(mode)) {
6196 // rewrite code handles in inline cache targets to direct
6197 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006198 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006199 Code* code = Code::cast(*p);
6200 it.rinfo()->set_target_address(code->instruction_start());
6201 } else {
6202 it.rinfo()->apply(delta);
6203 }
6204 }
6205 CPU::FlushICache(instruction_start(), instruction_size());
6206}
6207
6208
6209// Locate the source position which is closest to the address in the code. This
6210// is using the source position information embedded in the relocation info.
6211// The position returned is relative to the beginning of the script where the
6212// source for this function is found.
6213int Code::SourcePosition(Address pc) {
6214 int distance = kMaxInt;
6215 int position = RelocInfo::kNoPosition; // Initially no position found.
6216 // Run through all the relocation info to find the best matching source
6217 // position. All the code needs to be considered as the sequence of the
6218 // instructions in the code does not necessarily follow the same order as the
6219 // source.
6220 RelocIterator it(this, RelocInfo::kPositionMask);
6221 while (!it.done()) {
6222 // Only look at positions after the current pc.
6223 if (it.rinfo()->pc() < pc) {
6224 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006225
6226 int dist = static_cast<int>(pc - it.rinfo()->pc());
6227 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006228 // If this position is closer than the current candidate or if it has the
6229 // same distance as the current candidate and the position is higher then
6230 // this position is the new candidate.
6231 if ((dist < distance) ||
6232 (dist == distance && pos > position)) {
6233 position = pos;
6234 distance = dist;
6235 }
6236 }
6237 it.next();
6238 }
6239 return position;
6240}
6241
6242
6243// Same as Code::SourcePosition above except it only looks for statement
6244// positions.
6245int Code::SourceStatementPosition(Address pc) {
6246 // First find the position as close as possible using all position
6247 // information.
6248 int position = SourcePosition(pc);
6249 // Now find the closest statement position before the position.
6250 int statement_position = 0;
6251 RelocIterator it(this, RelocInfo::kPositionMask);
6252 while (!it.done()) {
6253 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006254 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006255 if (statement_position < p && p <= position) {
6256 statement_position = p;
6257 }
6258 }
6259 it.next();
6260 }
6261 return statement_position;
6262}
6263
6264
Ben Murdochb8e0da22011-05-16 14:20:40 +01006265SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006266 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006267 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006268}
6269
6270
6271void Code::SetNoStackCheckTable() {
6272 // Indicate the absence of a stack-check table by a table start after the
6273 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006274 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006275}
6276
6277
6278Map* Code::FindFirstMap() {
6279 ASSERT(is_inline_cache_stub());
6280 AssertNoAllocation no_allocation;
6281 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6282 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6283 RelocInfo* info = it.rinfo();
6284 Object* object = info->target_object();
6285 if (object->IsMap()) return Map::cast(object);
6286 }
6287 return NULL;
6288}
6289
6290
Steve Blocka7e24c12009-10-30 11:49:00 +00006291#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006292
6293#ifdef OBJECT_PRINT
6294
6295void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6296 disasm::NameConverter converter;
6297 int deopt_count = DeoptCount();
6298 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6299 if (0 == deopt_count) return;
6300
6301 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
6302 for (int i = 0; i < deopt_count; i++) {
6303 int command_count = 0;
6304 PrintF(out, "%6d %6d %6d",
6305 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
6306 int translation_index = TranslationIndex(i)->value();
6307 TranslationIterator iterator(TranslationByteArray(), translation_index);
6308 Translation::Opcode opcode =
6309 static_cast<Translation::Opcode>(iterator.Next());
6310 ASSERT(Translation::BEGIN == opcode);
6311 int frame_count = iterator.Next();
6312 if (FLAG_print_code_verbose) {
6313 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6314 frame_count);
6315 }
6316
6317 for (int i = 0; i < frame_count; ++i) {
6318 opcode = static_cast<Translation::Opcode>(iterator.Next());
6319 ASSERT(Translation::FRAME == opcode);
6320 int ast_id = iterator.Next();
6321 int function_id = iterator.Next();
6322 JSFunction* function =
6323 JSFunction::cast(LiteralArray()->get(function_id));
6324 unsigned height = iterator.Next();
6325 if (FLAG_print_code_verbose) {
6326 PrintF(out, "%24s %s {ast_id=%d, function=",
6327 "", Translation::StringFor(opcode), ast_id);
6328 function->PrintName(out);
6329 PrintF(out, ", height=%u}\n", height);
6330 }
6331
6332 // Size of translation is height plus all incoming arguments including
6333 // receiver.
6334 int size = height + function->shared()->formal_parameter_count() + 1;
6335 command_count += size;
6336 for (int j = 0; j < size; ++j) {
6337 opcode = static_cast<Translation::Opcode>(iterator.Next());
6338 if (FLAG_print_code_verbose) {
6339 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
6340 }
6341
6342 if (opcode == Translation::DUPLICATE) {
6343 opcode = static_cast<Translation::Opcode>(iterator.Next());
6344 if (FLAG_print_code_verbose) {
6345 PrintF(out, "%s ", Translation::StringFor(opcode));
6346 }
6347 --j; // Two commands share the same frame index.
6348 }
6349
6350 switch (opcode) {
6351 case Translation::BEGIN:
6352 case Translation::FRAME:
6353 case Translation::DUPLICATE:
6354 UNREACHABLE();
6355 break;
6356
6357 case Translation::REGISTER: {
6358 int reg_code = iterator.Next();
6359 if (FLAG_print_code_verbose) {
6360 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6361 }
6362 break;
6363 }
6364
6365 case Translation::INT32_REGISTER: {
6366 int reg_code = iterator.Next();
6367 if (FLAG_print_code_verbose) {
6368 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6369 }
6370 break;
6371 }
6372
6373 case Translation::DOUBLE_REGISTER: {
6374 int reg_code = iterator.Next();
6375 if (FLAG_print_code_verbose) {
6376 PrintF(out, "{input=%s}",
6377 DoubleRegister::AllocationIndexToString(reg_code));
6378 }
6379 break;
6380 }
6381
6382 case Translation::STACK_SLOT: {
6383 int input_slot_index = iterator.Next();
6384 if (FLAG_print_code_verbose) {
6385 PrintF(out, "{input=%d}", input_slot_index);
6386 }
6387 break;
6388 }
6389
6390 case Translation::INT32_STACK_SLOT: {
6391 int input_slot_index = iterator.Next();
6392 if (FLAG_print_code_verbose) {
6393 PrintF(out, "{input=%d}", input_slot_index);
6394 }
6395 break;
6396 }
6397
6398 case Translation::DOUBLE_STACK_SLOT: {
6399 int input_slot_index = iterator.Next();
6400 if (FLAG_print_code_verbose) {
6401 PrintF(out, "{input=%d}", input_slot_index);
6402 }
6403 break;
6404 }
6405
6406 case Translation::LITERAL: {
6407 unsigned literal_index = iterator.Next();
6408 if (FLAG_print_code_verbose) {
6409 PrintF(out, "{literal_id=%u}", literal_index);
6410 }
6411 break;
6412 }
6413
6414 case Translation::ARGUMENTS_OBJECT:
6415 break;
6416 }
6417 if (FLAG_print_code_verbose) PrintF(out, "\n");
6418 }
6419 }
6420 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
6421 }
6422}
6423
6424
6425void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
6426 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
6427 this->DeoptPoints());
6428 if (this->DeoptPoints() == 0) return;
6429
6430 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
6431 for (int i = 0; i < this->DeoptPoints(); i++) {
6432 int pc_and_state = this->PcAndState(i)->value();
6433 PrintF("%6d %8d %s\n",
6434 this->AstId(i)->value(),
6435 FullCodeGenerator::PcField::decode(pc_and_state),
6436 FullCodeGenerator::State2String(
6437 FullCodeGenerator::StateField::decode(pc_and_state)));
6438 }
6439}
6440
6441#endif
6442
6443
Steve Blocka7e24c12009-10-30 11:49:00 +00006444// Identify kind of code.
6445const char* Code::Kind2String(Kind kind) {
6446 switch (kind) {
6447 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006448 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006449 case STUB: return "STUB";
6450 case BUILTIN: return "BUILTIN";
6451 case LOAD_IC: return "LOAD_IC";
6452 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
Steve Block44f0eee2011-05-26 01:26:41 +01006453 case KEYED_EXTERNAL_ARRAY_LOAD_IC: return "KEYED_EXTERNAL_ARRAY_LOAD_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006454 case STORE_IC: return "STORE_IC";
6455 case KEYED_STORE_IC: return "KEYED_STORE_IC";
Steve Block44f0eee2011-05-26 01:26:41 +01006456 case KEYED_EXTERNAL_ARRAY_STORE_IC: return "KEYED_EXTERNAL_ARRAY_STORE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006457 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006458 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Steve Block6ded16b2010-05-10 14:33:55 +01006459 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006460 case TYPE_RECORDING_BINARY_OP_IC: return "TYPE_RECORDING_BINARY_OP_IC";
6461 case COMPARE_IC: return "COMPARE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006462 }
6463 UNREACHABLE();
6464 return NULL;
6465}
6466
6467
6468const char* Code::ICState2String(InlineCacheState state) {
6469 switch (state) {
6470 case UNINITIALIZED: return "UNINITIALIZED";
6471 case PREMONOMORPHIC: return "PREMONOMORPHIC";
6472 case MONOMORPHIC: return "MONOMORPHIC";
6473 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
6474 case MEGAMORPHIC: return "MEGAMORPHIC";
6475 case DEBUG_BREAK: return "DEBUG_BREAK";
6476 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
6477 }
6478 UNREACHABLE();
6479 return NULL;
6480}
6481
6482
6483const char* Code::PropertyType2String(PropertyType type) {
6484 switch (type) {
6485 case NORMAL: return "NORMAL";
6486 case FIELD: return "FIELD";
6487 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
6488 case CALLBACKS: return "CALLBACKS";
6489 case INTERCEPTOR: return "INTERCEPTOR";
6490 case MAP_TRANSITION: return "MAP_TRANSITION";
Steve Block44f0eee2011-05-26 01:26:41 +01006491 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006492 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
6493 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
6494 }
6495 UNREACHABLE();
6496 return NULL;
6497}
6498
Ben Murdochb0fe1622011-05-05 13:52:32 +01006499
Steve Block1e0659c2011-05-24 12:43:12 +01006500void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
6501 const char* name = NULL;
6502 switch (kind) {
6503 case CALL_IC:
6504 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
6505 name = "STRING_INDEX_OUT_OF_BOUNDS";
6506 }
6507 break;
6508 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006509 case KEYED_STORE_IC:
6510 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01006511 name = "STRICT";
6512 }
6513 break;
6514 default:
6515 break;
6516 }
6517 if (name != NULL) {
6518 PrintF(out, "extra_ic_state = %s\n", name);
6519 } else {
6520 PrintF(out, "etra_ic_state = %d\n", extra);
6521 }
6522}
6523
6524
Ben Murdochb0fe1622011-05-05 13:52:32 +01006525void Code::Disassemble(const char* name, FILE* out) {
6526 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006527 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006528 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01006529 PrintExtraICState(out, kind(), extra_ic_state());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006530 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
Steve Blocka7e24c12009-10-30 11:49:00 +00006531 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006532 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006533 }
6534 }
6535 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006536 PrintF(out, "name = %s\n", name);
6537 }
6538 if (kind() == OPTIMIZED_FUNCTION) {
6539 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00006540 }
6541
Ben Murdochb0fe1622011-05-05 13:52:32 +01006542 PrintF(out, "Instructions (size = %d)\n", instruction_size());
6543 Disassembler::Decode(out, this);
6544 PrintF(out, "\n");
6545
6546#ifdef DEBUG
6547 if (kind() == FUNCTION) {
6548 DeoptimizationOutputData* data =
6549 DeoptimizationOutputData::cast(this->deoptimization_data());
6550 data->DeoptimizationOutputDataPrint(out);
6551 } else if (kind() == OPTIMIZED_FUNCTION) {
6552 DeoptimizationInputData* data =
6553 DeoptimizationInputData::cast(this->deoptimization_data());
6554 data->DeoptimizationInputDataPrint(out);
6555 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006556 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006557#endif
6558
6559 if (kind() == OPTIMIZED_FUNCTION) {
6560 SafepointTable table(this);
6561 PrintF(out, "Safepoints (size = %u)\n", table.size());
6562 for (unsigned i = 0; i < table.length(); i++) {
6563 unsigned pc_offset = table.GetPcOffset(i);
6564 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
6565 table.PrintEntry(i);
6566 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01006567 SafepointEntry entry = table.GetEntry(i);
6568 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
6569 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006570 } else {
6571 PrintF(out, " <none>");
6572 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01006573 if (entry.argument_count() > 0) {
6574 PrintF(out, " argc: %d", entry.argument_count());
6575 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006576 PrintF(out, "\n");
6577 }
6578 PrintF(out, "\n");
6579 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01006580 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006581 // If there is no stack check table, the "table start" will at or after
6582 // (due to alignment) the end of the instruction stream.
6583 if (static_cast<int>(offset) < instruction_size()) {
6584 unsigned* address =
6585 reinterpret_cast<unsigned*>(instruction_start() + offset);
6586 unsigned length = address[0];
6587 PrintF(out, "Stack checks (size = %u)\n", length);
6588 PrintF(out, "ast_id pc_offset\n");
6589 for (unsigned i = 0; i < length; ++i) {
6590 unsigned index = (2 * i) + 1;
6591 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
6592 }
6593 PrintF(out, "\n");
6594 }
6595 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006596
6597 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006598 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
6599 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006600}
6601#endif // ENABLE_DISASSEMBLER
6602
6603
John Reck59135872010-11-02 12:39:01 -07006604MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
6605 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006606 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00006607 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006608 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01006609
John Reck59135872010-11-02 12:39:01 -07006610 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006611 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006612 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6613 }
Steve Block8defd9f2010-07-08 12:39:36 +01006614 FixedArray* elems = FixedArray::cast(obj);
6615
John Reck59135872010-11-02 12:39:01 -07006616 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
6617 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6618 }
Steve Block8defd9f2010-07-08 12:39:36 +01006619 Map* new_map = Map::cast(obj);
6620
Leon Clarke4515c472010-02-03 11:58:03 +00006621 AssertNoAllocation no_gc;
6622 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00006623 switch (GetElementsKind()) {
6624 case FAST_ELEMENTS: {
6625 FixedArray* old_elements = FixedArray::cast(elements());
6626 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
6627 // Fill out the new array with this content and array holes.
6628 for (uint32_t i = 0; i < old_length; i++) {
6629 elems->set(i, old_elements->get(i), mode);
6630 }
6631 break;
6632 }
6633 case DICTIONARY_ELEMENTS: {
6634 NumberDictionary* dictionary = NumberDictionary::cast(elements());
6635 for (int i = 0; i < dictionary->Capacity(); i++) {
6636 Object* key = dictionary->KeyAt(i);
6637 if (key->IsNumber()) {
6638 uint32_t entry = static_cast<uint32_t>(key->Number());
6639 elems->set(entry, dictionary->ValueAt(i), mode);
6640 }
6641 }
6642 break;
6643 }
6644 default:
6645 UNREACHABLE();
6646 break;
6647 }
Steve Block8defd9f2010-07-08 12:39:36 +01006648
6649 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00006650 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01006651
6652 if (IsJSArray()) {
6653 JSArray::cast(this)->set_length(Smi::FromInt(length));
6654 }
6655
6656 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00006657}
6658
6659
John Reck59135872010-11-02 12:39:01 -07006660MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006661 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006662 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00006663
6664 uint32_t new_length = static_cast<uint32_t>(len->Number());
6665
6666 switch (GetElementsKind()) {
6667 case FAST_ELEMENTS: {
6668 // Make sure we never try to shrink dense arrays into sparse arrays.
6669 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
6670 new_length);
John Reck59135872010-11-02 12:39:01 -07006671 Object* obj;
6672 { MaybeObject* maybe_obj = NormalizeElements();
6673 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6674 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006675
6676 // Update length for JSArrays.
6677 if (IsJSArray()) JSArray::cast(this)->set_length(len);
6678 break;
6679 }
6680 case DICTIONARY_ELEMENTS: {
6681 if (IsJSArray()) {
6682 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01006683 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00006684 element_dictionary()->RemoveNumberEntries(new_length, old_length),
6685 JSArray::cast(this)->set_length(len);
6686 }
6687 break;
6688 }
6689 default:
6690 UNREACHABLE();
6691 break;
6692 }
6693 return this;
6694}
6695
6696
John Reck59135872010-11-02 12:39:01 -07006697MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01006698 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006699 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00006700 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00006701 FixedArray* new_elements;
6702 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006703 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00006704 } else {
John Reck59135872010-11-02 12:39:01 -07006705 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006706 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006707 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6708 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006709 new_elements = FixedArray::cast(obj);
6710 }
6711 set_elements(new_elements);
6712 return this;
6713}
6714
6715
6716void JSArray::Expand(int required_size) {
6717 Handle<JSArray> self(this);
6718 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
6719 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00006720 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01006721 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00006722 // Can't use this any more now because we may have had a GC!
6723 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
6724 self->SetContent(*new_backing);
6725}
6726
6727
Steve Block44f0eee2011-05-26 01:26:41 +01006728static Failure* ArrayLengthRangeError(Heap* heap) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006729 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006730 return heap->isolate()->Throw(
6731 *FACTORY->NewRangeError("invalid_array_length",
6732 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00006733}
6734
6735
John Reck59135872010-11-02 12:39:01 -07006736MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block44f0eee2011-05-26 01:26:41 +01006737 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00006738 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01006739 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00006740
John Reck59135872010-11-02 12:39:01 -07006741 MaybeObject* maybe_smi_length = len->ToSmi();
6742 Object* smi_length = Smi::FromInt(0);
6743 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01006744 const int value = Smi::cast(smi_length)->value();
Steve Block44f0eee2011-05-26 01:26:41 +01006745 if (value < 0) return ArrayLengthRangeError(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00006746 switch (GetElementsKind()) {
6747 case FAST_ELEMENTS: {
6748 int old_capacity = FixedArray::cast(elements())->length();
6749 if (value <= old_capacity) {
6750 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07006751 Object* obj;
6752 { MaybeObject* maybe_obj = EnsureWritableFastElements();
6753 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6754 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006755 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
6756 // NOTE: We may be able to optimize this by removing the
6757 // last part of the elements backing storage array and
6758 // setting the capacity to the new size.
6759 for (int i = value; i < old_length; i++) {
6760 FixedArray::cast(elements())->set_the_hole(i);
6761 }
Leon Clarke4515c472010-02-03 11:58:03 +00006762 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006763 }
6764 return this;
6765 }
6766 int min = NewElementsCapacity(old_capacity);
6767 int new_capacity = value > min ? value : min;
6768 if (new_capacity <= kMaxFastElementsLength ||
6769 !ShouldConvertToSlowElements(new_capacity)) {
John Reck59135872010-11-02 12:39:01 -07006770 Object* obj;
6771 { MaybeObject* maybe_obj =
6772 SetFastElementsCapacityAndLength(new_capacity, value);
6773 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6774 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006775 return this;
6776 }
6777 break;
6778 }
6779 case DICTIONARY_ELEMENTS: {
6780 if (IsJSArray()) {
6781 if (value == 0) {
6782 // If the length of a slow array is reset to zero, we clear
6783 // the array and flush backing storage. This has the added
6784 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07006785 Object* obj;
6786 { MaybeObject* maybe_obj = ResetElements();
6787 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6788 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006789 } else {
6790 // Remove deleted elements.
6791 uint32_t old_length =
6792 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
6793 element_dictionary()->RemoveNumberEntries(value, old_length);
6794 }
Leon Clarke4515c472010-02-03 11:58:03 +00006795 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006796 }
6797 return this;
6798 }
6799 default:
6800 UNREACHABLE();
6801 break;
6802 }
6803 }
6804
6805 // General slow case.
6806 if (len->IsNumber()) {
6807 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006808 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006809 return SetSlowElements(len);
6810 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006811 return ArrayLengthRangeError(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00006812 }
6813 }
6814
6815 // len is not a number so make the array size one and
6816 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07006817 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006818 { MaybeObject* maybe_obj = heap->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07006819 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6820 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006821 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00006822 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006823 set_elements(FixedArray::cast(obj));
6824 return this;
6825}
6826
6827
John Reck59135872010-11-02 12:39:01 -07006828MaybeObject* JSObject::SetPrototype(Object* value,
6829 bool skip_hidden_prototypes) {
Steve Block44f0eee2011-05-26 01:26:41 +01006830 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00006831 // Silently ignore the change if value is not a JSObject or null.
6832 // SpiderMonkey behaves this way.
6833 if (!value->IsJSObject() && !value->IsNull()) return value;
6834
6835 // Before we can set the prototype we need to be sure
6836 // prototype cycles are prevented.
6837 // It is sufficient to validate that the receiver is not in the new prototype
6838 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01006839 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00006840 if (JSObject::cast(pt) == this) {
6841 // Cycle detected.
6842 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006843 return heap->isolate()->Throw(
6844 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00006845 }
6846 }
6847
6848 JSObject* real_receiver = this;
6849
6850 if (skip_hidden_prototypes) {
6851 // Find the first object in the chain whose prototype object is not
6852 // hidden and set the new prototype on that object.
6853 Object* current_proto = real_receiver->GetPrototype();
6854 while (current_proto->IsJSObject() &&
6855 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
6856 real_receiver = JSObject::cast(current_proto);
6857 current_proto = current_proto->GetPrototype();
6858 }
6859 }
6860
6861 // Set the new prototype of the object.
John Reck59135872010-11-02 12:39:01 -07006862 Object* new_map;
6863 { MaybeObject* maybe_new_map = real_receiver->map()->CopyDropTransitions();
6864 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
6865 }
Andrei Popescu402d9372010-02-26 13:31:12 +00006866 Map::cast(new_map)->set_prototype(value);
6867 real_receiver->set_map(Map::cast(new_map));
6868
Steve Block44f0eee2011-05-26 01:26:41 +01006869 heap->ClearInstanceofCache();
Kristian Monsen25f61362010-05-21 11:50:48 +01006870
Andrei Popescu402d9372010-02-26 13:31:12 +00006871 return value;
6872}
6873
6874
Steve Blocka7e24c12009-10-30 11:49:00 +00006875bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
6876 switch (GetElementsKind()) {
6877 case FAST_ELEMENTS: {
6878 uint32_t length = IsJSArray() ?
6879 static_cast<uint32_t>
6880 (Smi::cast(JSArray::cast(this)->length())->value()) :
6881 static_cast<uint32_t>(FixedArray::cast(elements())->length());
6882 if ((index < length) &&
6883 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
6884 return true;
6885 }
6886 break;
6887 }
Steve Block44f0eee2011-05-26 01:26:41 +01006888 case EXTERNAL_PIXEL_ELEMENTS: {
6889 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00006890 if (index < static_cast<uint32_t>(pixels->length())) {
6891 return true;
6892 }
6893 break;
6894 }
Steve Block3ce2e202009-11-05 08:53:23 +00006895 case EXTERNAL_BYTE_ELEMENTS:
6896 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
6897 case EXTERNAL_SHORT_ELEMENTS:
6898 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
6899 case EXTERNAL_INT_ELEMENTS:
6900 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
6901 case EXTERNAL_FLOAT_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00006902 ExternalArray* array = ExternalArray::cast(elements());
6903 if (index < static_cast<uint32_t>(array->length())) {
6904 return true;
6905 }
6906 break;
6907 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006908 case DICTIONARY_ELEMENTS: {
6909 if (element_dictionary()->FindEntry(index)
6910 != NumberDictionary::kNotFound) {
6911 return true;
6912 }
6913 break;
6914 }
6915 default:
6916 UNREACHABLE();
6917 break;
6918 }
6919
6920 // Handle [] on String objects.
6921 if (this->IsStringObjectWithCharacterAt(index)) return true;
6922
6923 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01006924 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00006925 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
6926}
6927
6928
6929bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01006930 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006931 // Make sure that the top context does not change when doing
6932 // callbacks or interceptor calls.
6933 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01006934 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006935 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
6936 Handle<JSObject> receiver_handle(receiver);
6937 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01006938 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00006939 v8::AccessorInfo info(args.end());
6940 if (!interceptor->query()->IsUndefined()) {
6941 v8::IndexedPropertyQuery query =
6942 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01006943 LOG(isolate,
6944 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01006945 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00006946 {
6947 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01006948 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006949 result = query(index, info);
6950 }
Iain Merrick75681382010-08-19 15:07:18 +01006951 if (!result.IsEmpty()) {
6952 ASSERT(result->IsInt32());
6953 return true; // absence of property is signaled by empty handle.
6954 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006955 } else if (!interceptor->getter()->IsUndefined()) {
6956 v8::IndexedPropertyGetter getter =
6957 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01006958 LOG(isolate,
6959 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00006960 v8::Handle<v8::Value> result;
6961 {
6962 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01006963 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00006964 result = getter(index, info);
6965 }
6966 if (!result.IsEmpty()) return true;
6967 }
6968 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
6969}
6970
6971
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006972JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01006973 Heap* heap = GetHeap();
6974
Steve Blocka7e24c12009-10-30 11:49:00 +00006975 // Check access rights if needed.
6976 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01006977 !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
6978 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006979 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00006980 }
6981
Steve Block1e0659c2011-05-24 12:43:12 +01006982 if (IsJSGlobalProxy()) {
6983 Object* proto = GetPrototype();
6984 if (proto->IsNull()) return UNDEFINED_ELEMENT;
6985 ASSERT(proto->IsJSGlobalObject());
6986 return JSObject::cast(proto)->HasLocalElement(index);
6987 }
6988
Steve Blocka7e24c12009-10-30 11:49:00 +00006989 // Check for lookup interceptor
6990 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006991 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
6992 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00006993 }
6994
6995 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006996 if (this->IsStringObjectWithCharacterAt(index)) {
6997 return STRING_CHARACTER_ELEMENT;
6998 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006999
7000 switch (GetElementsKind()) {
7001 case FAST_ELEMENTS: {
7002 uint32_t length = IsJSArray() ?
7003 static_cast<uint32_t>
7004 (Smi::cast(JSArray::cast(this)->length())->value()) :
7005 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007006 if ((index < length) &&
7007 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7008 return FAST_ELEMENT;
7009 }
7010 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007011 }
Steve Block44f0eee2011-05-26 01:26:41 +01007012 case EXTERNAL_PIXEL_ELEMENTS: {
7013 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007014 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7015 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007016 }
Steve Block3ce2e202009-11-05 08:53:23 +00007017 case EXTERNAL_BYTE_ELEMENTS:
7018 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7019 case EXTERNAL_SHORT_ELEMENTS:
7020 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7021 case EXTERNAL_INT_ELEMENTS:
7022 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7023 case EXTERNAL_FLOAT_ELEMENTS: {
7024 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007025 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7026 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007027 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007028 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007029 if (element_dictionary()->FindEntry(index) !=
7030 NumberDictionary::kNotFound) {
7031 return DICTIONARY_ELEMENT;
7032 }
7033 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007034 }
7035 default:
7036 UNREACHABLE();
7037 break;
7038 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007039
7040 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007041}
7042
7043
7044bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007045 Heap* heap = GetHeap();
7046
Steve Blocka7e24c12009-10-30 11:49:00 +00007047 // Check access rights if needed.
7048 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01007049 !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7050 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +00007051 return false;
7052 }
7053
7054 // Check for lookup interceptor
7055 if (HasIndexedInterceptor()) {
7056 return HasElementWithInterceptor(receiver, index);
7057 }
7058
7059 switch (GetElementsKind()) {
7060 case FAST_ELEMENTS: {
7061 uint32_t length = IsJSArray() ?
7062 static_cast<uint32_t>
7063 (Smi::cast(JSArray::cast(this)->length())->value()) :
7064 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7065 if ((index < length) &&
7066 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
7067 break;
7068 }
Steve Block44f0eee2011-05-26 01:26:41 +01007069 case EXTERNAL_PIXEL_ELEMENTS: {
7070 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007071 if (index < static_cast<uint32_t>(pixels->length())) {
7072 return true;
7073 }
7074 break;
7075 }
Steve Block3ce2e202009-11-05 08:53:23 +00007076 case EXTERNAL_BYTE_ELEMENTS:
7077 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7078 case EXTERNAL_SHORT_ELEMENTS:
7079 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7080 case EXTERNAL_INT_ELEMENTS:
7081 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7082 case EXTERNAL_FLOAT_ELEMENTS: {
7083 ExternalArray* array = ExternalArray::cast(elements());
7084 if (index < static_cast<uint32_t>(array->length())) {
7085 return true;
7086 }
7087 break;
7088 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007089 case DICTIONARY_ELEMENTS: {
7090 if (element_dictionary()->FindEntry(index)
7091 != NumberDictionary::kNotFound) {
7092 return true;
7093 }
7094 break;
7095 }
7096 default:
7097 UNREACHABLE();
7098 break;
7099 }
7100
7101 // Handle [] on String objects.
7102 if (this->IsStringObjectWithCharacterAt(index)) return true;
7103
7104 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007105 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007106 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7107}
7108
7109
John Reck59135872010-11-02 12:39:01 -07007110MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007111 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007112 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007113 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007114 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007115 // Make sure that the top context does not change when doing
7116 // callbacks or interceptor calls.
7117 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007118 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007119 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7120 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007121 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007122 if (!interceptor->setter()->IsUndefined()) {
7123 v8::IndexedPropertySetter setter =
7124 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01007125 LOG(isolate,
7126 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
7127 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007128 v8::AccessorInfo info(args.end());
7129 v8::Handle<v8::Value> result;
7130 {
7131 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007132 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007133 result = setter(index, v8::Utils::ToLocal(value_handle), info);
7134 }
Steve Block44f0eee2011-05-26 01:26:41 +01007135 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007136 if (!result.IsEmpty()) return *value_handle;
7137 }
John Reck59135872010-11-02 12:39:01 -07007138 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01007139 this_handle->SetElementWithoutInterceptor(index,
7140 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007141 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007142 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007143 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007144 return raw_result;
7145}
7146
7147
John Reck59135872010-11-02 12:39:01 -07007148MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
7149 Object* structure,
7150 uint32_t index,
7151 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007152 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01007153 ASSERT(!structure->IsProxy());
7154
7155 // api style callbacks.
7156 if (structure->IsAccessorInfo()) {
7157 AccessorInfo* data = AccessorInfo::cast(structure);
7158 Object* fun_obj = data->getter();
7159 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007160 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007161 Handle<JSObject> self(JSObject::cast(receiver));
7162 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01007163 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7164 Handle<String> key(isolate->factory()->NumberToString(number));
7165 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
7166 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01007167 v8::AccessorInfo info(args.end());
7168 v8::Handle<v8::Value> result;
7169 {
7170 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007171 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007172 result = call_fun(v8::Utils::ToLocal(key), info);
7173 }
Steve Block44f0eee2011-05-26 01:26:41 +01007174 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
7175 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007176 return *v8::Utils::OpenHandle(*result);
7177 }
7178
7179 // __defineGetter__ callback
7180 if (structure->IsFixedArray()) {
7181 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
7182 if (getter->IsJSFunction()) {
7183 return Object::GetPropertyWithDefinedGetter(receiver,
7184 JSFunction::cast(getter));
7185 }
7186 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01007187 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007188 }
7189
7190 UNREACHABLE();
7191 return NULL;
7192}
7193
7194
John Reck59135872010-11-02 12:39:01 -07007195MaybeObject* JSObject::SetElementWithCallback(Object* structure,
7196 uint32_t index,
7197 Object* value,
7198 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007199 Isolate* isolate = GetIsolate();
7200 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007201
7202 // We should never get here to initialize a const with the hole
7203 // value since a const declaration would conflict with the setter.
7204 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01007205 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007206
7207 // To accommodate both the old and the new api we switch on the
7208 // data structure used to store the callbacks. Eventually proxy
7209 // callbacks should be phased out.
7210 ASSERT(!structure->IsProxy());
7211
7212 if (structure->IsAccessorInfo()) {
7213 // api style callbacks
7214 AccessorInfo* data = AccessorInfo::cast(structure);
7215 Object* call_obj = data->setter();
7216 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
7217 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01007218 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7219 Handle<String> key(isolate->factory()->NumberToString(number));
7220 LOG(isolate, ApiNamedPropertyAccess("store", this, *key));
7221 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Leon Clarkef7060e22010-06-03 12:02:55 +01007222 v8::AccessorInfo info(args.end());
7223 {
7224 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007225 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007226 call_fun(v8::Utils::ToLocal(key),
7227 v8::Utils::ToLocal(value_handle),
7228 info);
7229 }
Steve Block44f0eee2011-05-26 01:26:41 +01007230 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007231 return *value_handle;
7232 }
7233
7234 if (structure->IsFixedArray()) {
7235 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
7236 if (setter->IsJSFunction()) {
7237 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
7238 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007239 Handle<Object> holder_handle(holder, isolate);
7240 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01007241 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01007242 return isolate->Throw(
7243 *isolate->factory()->NewTypeError("no_setter_in_callback",
7244 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01007245 }
7246 }
7247
7248 UNREACHABLE();
7249 return NULL;
7250}
7251
7252
Steve Blocka7e24c12009-10-30 11:49:00 +00007253// Adding n elements in fast case is O(n*n).
7254// Note: revisit design to have dual undefined values to capture absent
7255// elements.
Steve Block9fac8402011-05-12 15:51:54 +01007256MaybeObject* JSObject::SetFastElement(uint32_t index,
7257 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007258 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007259 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007260 ASSERT(HasFastElements());
7261
John Reck59135872010-11-02 12:39:01 -07007262 Object* elms_obj;
7263 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements();
7264 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
7265 }
Iain Merrick75681382010-08-19 15:07:18 +01007266 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007267 uint32_t elms_length = static_cast<uint32_t>(elms->length());
7268
Steve Block9fac8402011-05-12 15:51:54 +01007269 if (check_prototype &&
Steve Block1e0659c2011-05-24 12:43:12 +01007270 (index >= elms_length || elms->get(index)->IsTheHole())) {
7271 bool found;
7272 MaybeObject* result =
7273 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7274 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007275 }
7276
Steve Block9fac8402011-05-12 15:51:54 +01007277
Steve Blocka7e24c12009-10-30 11:49:00 +00007278 // Check whether there is extra space in fixed array..
7279 if (index < elms_length) {
7280 elms->set(index, value);
7281 if (IsJSArray()) {
7282 // Update the length of the array if needed.
7283 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007284 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007285 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00007286 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007287 }
7288 }
7289 return value;
7290 }
7291
7292 // Allow gap in fast case.
7293 if ((index - elms_length) < kMaxGap) {
7294 // Try allocating extra space.
7295 int new_capacity = NewElementsCapacity(index+1);
7296 if (new_capacity <= kMaxFastElementsLength ||
7297 !ShouldConvertToSlowElements(new_capacity)) {
7298 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07007299 Object* obj;
7300 { MaybeObject* maybe_obj =
7301 SetFastElementsCapacityAndLength(new_capacity, index + 1);
7302 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7303 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007304 FixedArray::cast(elements())->set(index, value);
7305 return value;
7306 }
7307 }
7308
7309 // Otherwise default to slow case.
John Reck59135872010-11-02 12:39:01 -07007310 Object* obj;
7311 { MaybeObject* maybe_obj = NormalizeElements();
7312 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7313 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007314 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007315 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007316}
7317
Iain Merrick75681382010-08-19 15:07:18 +01007318
Steve Block9fac8402011-05-12 15:51:54 +01007319MaybeObject* JSObject::SetElement(uint32_t index,
7320 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007321 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007322 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007323 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007324 // Check access rights if needed.
7325 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01007326 !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Iain Merrick75681382010-08-19 15:07:18 +01007327 HandleScope scope;
7328 Handle<Object> value_handle(value);
Steve Block44f0eee2011-05-26 01:26:41 +01007329 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01007330 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00007331 }
7332
7333 if (IsJSGlobalProxy()) {
7334 Object* proto = GetPrototype();
7335 if (proto->IsNull()) return value;
7336 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007337 return JSObject::cast(proto)->SetElement(index,
7338 value,
7339 strict_mode,
7340 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007341 }
7342
7343 // Check for lookup interceptor
7344 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007345 return SetElementWithInterceptor(index,
7346 value,
7347 strict_mode,
7348 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007349 }
7350
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007351 return SetElementWithoutInterceptor(index,
7352 value,
7353 strict_mode,
7354 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007355}
7356
7357
John Reck59135872010-11-02 12:39:01 -07007358MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007359 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007360 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007361 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007362 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007363 switch (GetElementsKind()) {
7364 case FAST_ELEMENTS:
7365 // Fast case.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007366 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007367 case EXTERNAL_PIXEL_ELEMENTS: {
7368 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007369 return pixels->SetValue(index, value);
7370 }
Steve Block3ce2e202009-11-05 08:53:23 +00007371 case EXTERNAL_BYTE_ELEMENTS: {
7372 ExternalByteArray* array = ExternalByteArray::cast(elements());
7373 return array->SetValue(index, value);
7374 }
7375 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7376 ExternalUnsignedByteArray* array =
7377 ExternalUnsignedByteArray::cast(elements());
7378 return array->SetValue(index, value);
7379 }
7380 case EXTERNAL_SHORT_ELEMENTS: {
7381 ExternalShortArray* array = ExternalShortArray::cast(elements());
7382 return array->SetValue(index, value);
7383 }
7384 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7385 ExternalUnsignedShortArray* array =
7386 ExternalUnsignedShortArray::cast(elements());
7387 return array->SetValue(index, value);
7388 }
7389 case EXTERNAL_INT_ELEMENTS: {
7390 ExternalIntArray* array = ExternalIntArray::cast(elements());
7391 return array->SetValue(index, value);
7392 }
7393 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7394 ExternalUnsignedIntArray* array =
7395 ExternalUnsignedIntArray::cast(elements());
7396 return array->SetValue(index, value);
7397 }
7398 case EXTERNAL_FLOAT_ELEMENTS: {
7399 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7400 return array->SetValue(index, value);
7401 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007402 case DICTIONARY_ELEMENTS: {
7403 // Insert element in the dictionary.
7404 FixedArray* elms = FixedArray::cast(elements());
7405 NumberDictionary* dictionary = NumberDictionary::cast(elms);
7406
7407 int entry = dictionary->FindEntry(index);
7408 if (entry != NumberDictionary::kNotFound) {
7409 Object* element = dictionary->ValueAt(entry);
7410 PropertyDetails details = dictionary->DetailsAt(entry);
7411 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007412 return SetElementWithCallback(element, index, value, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007413 } else {
7414 dictionary->UpdateMaxNumberKey(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007415 // If put fails instrict mode, throw exception.
7416 if (!dictionary->ValueAtPut(entry, value) &&
7417 strict_mode == kStrictMode) {
Steve Block44f0eee2011-05-26 01:26:41 +01007418 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007419 Handle<Object> holder(this);
7420 Handle<Object> args[2] = { number, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01007421 return isolate->Throw(
7422 *isolate->factory()->NewTypeError("strict_read_only_property",
7423 HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007424 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007425 }
7426 } else {
7427 // Index not already used. Look for an accessor in the prototype chain.
Steve Block1e0659c2011-05-24 12:43:12 +01007428 if (check_prototype) {
7429 bool found;
7430 MaybeObject* result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007431 // Strict mode not needed. No-setter case already handled.
Steve Block1e0659c2011-05-24 12:43:12 +01007432 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7433 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007434 }
Steve Block8defd9f2010-07-08 12:39:36 +01007435 // When we set the is_extensible flag to false we always force
7436 // the element into dictionary mode (and force them to stay there).
7437 if (!map()->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007438 if (strict_mode == kNonStrictMode) {
7439 return isolate->heap()->undefined_value();
7440 } else {
7441 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
7442 Handle<String> index_string(
7443 isolate->factory()->NumberToString(number));
7444 Handle<Object> args[1] = { index_string };
7445 return isolate->Throw(
7446 *isolate->factory()->NewTypeError("object_not_extensible",
7447 HandleVector(args, 1)));
7448 }
Steve Block8defd9f2010-07-08 12:39:36 +01007449 }
John Reck59135872010-11-02 12:39:01 -07007450 Object* result;
7451 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
7452 if (!maybe_result->ToObject(&result)) return maybe_result;
7453 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007454 if (elms != FixedArray::cast(result)) {
7455 set_elements(FixedArray::cast(result));
7456 }
7457 }
7458
7459 // Update the array length if this JSObject is an array.
7460 if (IsJSArray()) {
7461 JSArray* array = JSArray::cast(this);
John Reck59135872010-11-02 12:39:01 -07007462 Object* return_value;
7463 { MaybeObject* maybe_return_value =
7464 array->JSArrayUpdateLengthFromIndex(index, value);
7465 if (!maybe_return_value->ToObject(&return_value)) {
7466 return maybe_return_value;
7467 }
7468 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007469 }
7470
7471 // Attempt to put this object back in fast case.
7472 if (ShouldConvertToFastElements()) {
7473 uint32_t new_length = 0;
7474 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007475 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007476 } else {
7477 new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
7478 }
John Reck59135872010-11-02 12:39:01 -07007479 Object* obj;
7480 { MaybeObject* maybe_obj =
7481 SetFastElementsCapacityAndLength(new_length, new_length);
7482 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7483 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007484#ifdef DEBUG
7485 if (FLAG_trace_normalization) {
7486 PrintF("Object elements are fast case again:\n");
7487 Print();
7488 }
7489#endif
7490 }
7491
7492 return value;
7493 }
7494 default:
7495 UNREACHABLE();
7496 break;
7497 }
7498 // All possible cases have been handled above. Add a return to avoid the
7499 // complaints from the compiler.
7500 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01007501 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007502}
7503
7504
John Reck59135872010-11-02 12:39:01 -07007505MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
7506 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007507 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007508 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00007509 // Check to see if we need to update the length. For now, we make
7510 // sure that the length stays within 32-bits (unsigned).
7511 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07007512 Object* len;
7513 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01007514 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07007515 if (!maybe_len->ToObject(&len)) return maybe_len;
7516 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007517 set_length(len);
7518 }
7519 return value;
7520}
7521
7522
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007523MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007524 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007525 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007526 // Get element works for both JSObject and JSArray since
7527 // JSArray::length cannot change.
7528 switch (GetElementsKind()) {
7529 case FAST_ELEMENTS: {
7530 FixedArray* elms = FixedArray::cast(elements());
7531 if (index < static_cast<uint32_t>(elms->length())) {
7532 Object* value = elms->get(index);
7533 if (!value->IsTheHole()) return value;
7534 }
7535 break;
7536 }
Steve Block44f0eee2011-05-26 01:26:41 +01007537 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007538 case EXTERNAL_BYTE_ELEMENTS:
7539 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7540 case EXTERNAL_SHORT_ELEMENTS:
7541 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7542 case EXTERNAL_INT_ELEMENTS:
7543 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7544 case EXTERNAL_FLOAT_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007545 MaybeObject* maybe_value = GetExternalElement(index);
7546 Object* value;
7547 if (!maybe_value->ToObject(&value)) return maybe_value;
7548 if (!value->IsUndefined()) return value;
Steve Block3ce2e202009-11-05 08:53:23 +00007549 break;
7550 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007551 case DICTIONARY_ELEMENTS: {
7552 NumberDictionary* dictionary = element_dictionary();
7553 int entry = dictionary->FindEntry(index);
7554 if (entry != NumberDictionary::kNotFound) {
7555 Object* element = dictionary->ValueAt(entry);
7556 PropertyDetails details = dictionary->DetailsAt(entry);
7557 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007558 return GetElementWithCallback(receiver,
7559 element,
7560 index,
7561 this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007562 }
7563 return element;
7564 }
7565 break;
7566 }
7567 default:
7568 UNREACHABLE();
7569 break;
7570 }
7571
7572 // Continue searching via the prototype chain.
7573 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007574 if (pt->IsNull()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007575 return pt->GetElementWithReceiver(receiver, index);
7576}
7577
7578
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007579MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007580 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007581 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007582 // Make sure that the top context does not change when doing
7583 // callbacks or interceptor calls.
7584 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007585 HandleScope scope(isolate);
7586 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
7587 Handle<Object> this_handle(receiver, isolate);
7588 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007589
7590 if (!interceptor->getter()->IsUndefined()) {
7591 v8::IndexedPropertyGetter getter =
7592 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007593 LOG(isolate,
7594 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
7595 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007596 v8::AccessorInfo info(args.end());
7597 v8::Handle<v8::Value> result;
7598 {
7599 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007600 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007601 result = getter(index, info);
7602 }
Steve Block44f0eee2011-05-26 01:26:41 +01007603 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007604 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
7605 }
7606
John Reck59135872010-11-02 12:39:01 -07007607 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00007608 holder_handle->GetElementPostInterceptor(*this_handle, index);
Steve Block44f0eee2011-05-26 01:26:41 +01007609 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007610 return raw_result;
7611}
7612
7613
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007614MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007615 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007616 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007617 // Check access rights if needed.
7618 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01007619 !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
7620 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
7621 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007622 }
7623
7624 if (HasIndexedInterceptor()) {
7625 return GetElementWithInterceptor(receiver, index);
7626 }
7627
7628 // Get element works for both JSObject and JSArray since
7629 // JSArray::length cannot change.
7630 switch (GetElementsKind()) {
7631 case FAST_ELEMENTS: {
7632 FixedArray* elms = FixedArray::cast(elements());
7633 if (index < static_cast<uint32_t>(elms->length())) {
7634 Object* value = elms->get(index);
7635 if (!value->IsTheHole()) return value;
7636 }
7637 break;
7638 }
Steve Block44f0eee2011-05-26 01:26:41 +01007639 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007640 case EXTERNAL_BYTE_ELEMENTS:
7641 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7642 case EXTERNAL_SHORT_ELEMENTS:
7643 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7644 case EXTERNAL_INT_ELEMENTS:
7645 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7646 case EXTERNAL_FLOAT_ELEMENTS: {
7647 MaybeObject* maybe_value = GetExternalElement(index);
7648 Object* value;
7649 if (!maybe_value->ToObject(&value)) return maybe_value;
7650 if (!value->IsUndefined()) return value;
7651 break;
7652 }
7653 case DICTIONARY_ELEMENTS: {
7654 NumberDictionary* dictionary = element_dictionary();
7655 int entry = dictionary->FindEntry(index);
7656 if (entry != NumberDictionary::kNotFound) {
7657 Object* element = dictionary->ValueAt(entry);
7658 PropertyDetails details = dictionary->DetailsAt(entry);
7659 if (details.type() == CALLBACKS) {
7660 return GetElementWithCallback(receiver,
7661 element,
7662 index,
7663 this);
7664 }
7665 return element;
7666 }
7667 break;
7668 }
7669 }
7670
7671 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007672 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007673 return pt->GetElementWithReceiver(receiver, index);
7674}
7675
7676
7677MaybeObject* JSObject::GetExternalElement(uint32_t index) {
7678 // Get element works for both JSObject and JSArray since
7679 // JSArray::length cannot change.
7680 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007681 case EXTERNAL_PIXEL_ELEMENTS: {
7682 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007683 if (index < static_cast<uint32_t>(pixels->length())) {
7684 uint8_t value = pixels->get(index);
7685 return Smi::FromInt(value);
7686 }
7687 break;
7688 }
Steve Block3ce2e202009-11-05 08:53:23 +00007689 case EXTERNAL_BYTE_ELEMENTS: {
7690 ExternalByteArray* array = ExternalByteArray::cast(elements());
7691 if (index < static_cast<uint32_t>(array->length())) {
7692 int8_t value = array->get(index);
7693 return Smi::FromInt(value);
7694 }
7695 break;
7696 }
7697 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7698 ExternalUnsignedByteArray* array =
7699 ExternalUnsignedByteArray::cast(elements());
7700 if (index < static_cast<uint32_t>(array->length())) {
7701 uint8_t value = array->get(index);
7702 return Smi::FromInt(value);
7703 }
7704 break;
7705 }
7706 case EXTERNAL_SHORT_ELEMENTS: {
7707 ExternalShortArray* array = ExternalShortArray::cast(elements());
7708 if (index < static_cast<uint32_t>(array->length())) {
7709 int16_t value = array->get(index);
7710 return Smi::FromInt(value);
7711 }
7712 break;
7713 }
7714 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7715 ExternalUnsignedShortArray* array =
7716 ExternalUnsignedShortArray::cast(elements());
7717 if (index < static_cast<uint32_t>(array->length())) {
7718 uint16_t value = array->get(index);
7719 return Smi::FromInt(value);
7720 }
7721 break;
7722 }
7723 case EXTERNAL_INT_ELEMENTS: {
7724 ExternalIntArray* array = ExternalIntArray::cast(elements());
7725 if (index < static_cast<uint32_t>(array->length())) {
7726 int32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007727 return GetHeap()->NumberFromInt32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007728 }
7729 break;
7730 }
7731 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7732 ExternalUnsignedIntArray* array =
7733 ExternalUnsignedIntArray::cast(elements());
7734 if (index < static_cast<uint32_t>(array->length())) {
7735 uint32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007736 return GetHeap()->NumberFromUint32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007737 }
7738 break;
7739 }
7740 case EXTERNAL_FLOAT_ELEMENTS: {
7741 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7742 if (index < static_cast<uint32_t>(array->length())) {
7743 float value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007744 return GetHeap()->AllocateHeapNumber(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007745 }
7746 break;
7747 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007748 case FAST_ELEMENTS:
7749 case DICTIONARY_ELEMENTS:
7750 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00007751 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007752 }
Steve Block44f0eee2011-05-26 01:26:41 +01007753 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007754}
7755
7756
7757bool JSObject::HasDenseElements() {
7758 int capacity = 0;
7759 int number_of_elements = 0;
7760
7761 switch (GetElementsKind()) {
7762 case FAST_ELEMENTS: {
7763 FixedArray* elms = FixedArray::cast(elements());
7764 capacity = elms->length();
7765 for (int i = 0; i < capacity; i++) {
7766 if (!elms->get(i)->IsTheHole()) number_of_elements++;
7767 }
7768 break;
7769 }
Steve Block44f0eee2011-05-26 01:26:41 +01007770 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007771 case EXTERNAL_BYTE_ELEMENTS:
7772 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7773 case EXTERNAL_SHORT_ELEMENTS:
7774 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7775 case EXTERNAL_INT_ELEMENTS:
7776 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7777 case EXTERNAL_FLOAT_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +00007778 return true;
7779 }
7780 case DICTIONARY_ELEMENTS: {
7781 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7782 capacity = dictionary->Capacity();
7783 number_of_elements = dictionary->NumberOfElements();
7784 break;
7785 }
7786 default:
7787 UNREACHABLE();
7788 break;
7789 }
7790
7791 if (capacity == 0) return true;
7792 return (number_of_elements > (capacity / 2));
7793}
7794
7795
7796bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
7797 ASSERT(HasFastElements());
7798 // Keep the array in fast case if the current backing storage is
7799 // almost filled and if the new capacity is no more than twice the
7800 // old capacity.
7801 int elements_length = FixedArray::cast(elements())->length();
7802 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
7803}
7804
7805
7806bool JSObject::ShouldConvertToFastElements() {
7807 ASSERT(HasDictionaryElements());
7808 NumberDictionary* dictionary = NumberDictionary::cast(elements());
7809 // If the elements are sparse, we should not go back to fast case.
7810 if (!HasDenseElements()) return false;
7811 // If an element has been added at a very high index in the elements
7812 // dictionary, we cannot go back to fast case.
7813 if (dictionary->requires_slow_elements()) return false;
7814 // An object requiring access checks is never allowed to have fast
7815 // elements. If it had fast elements we would skip security checks.
7816 if (IsAccessCheckNeeded()) return false;
7817 // If the dictionary backing storage takes up roughly half as much
7818 // space as a fast-case backing storage would the array should have
7819 // fast elements.
7820 uint32_t length = 0;
7821 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007822 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007823 } else {
7824 length = dictionary->max_number_key();
7825 }
7826 return static_cast<uint32_t>(dictionary->Capacity()) >=
7827 (length / (2 * NumberDictionary::kEntrySize));
7828}
7829
7830
7831// Certain compilers request function template instantiation when they
7832// see the definition of the other template functions in the
7833// class. This requires us to have the template functions put
7834// together, so even though this function belongs in objects-debug.cc,
7835// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007836#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00007837template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01007838void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007839 int capacity = HashTable<Shape, Key>::Capacity();
7840 for (int i = 0; i < capacity; i++) {
7841 Object* k = HashTable<Shape, Key>::KeyAt(i);
7842 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007843 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00007844 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007845 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00007846 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007847 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00007848 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007849 PrintF(out, ": ");
7850 ValueAt(i)->ShortPrint(out);
7851 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007852 }
7853 }
7854}
7855#endif
7856
7857
7858template<typename Shape, typename Key>
7859void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
7860 int pos = 0;
7861 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00007862 AssertNoAllocation no_gc;
7863 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00007864 for (int i = 0; i < capacity; i++) {
7865 Object* k = Dictionary<Shape, Key>::KeyAt(i);
7866 if (Dictionary<Shape, Key>::IsKey(k)) {
7867 elements->set(pos++, ValueAt(i), mode);
7868 }
7869 }
7870 ASSERT(pos == elements->length());
7871}
7872
7873
7874InterceptorInfo* JSObject::GetNamedInterceptor() {
7875 ASSERT(map()->has_named_interceptor());
7876 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01007877 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00007878 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01007879 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00007880 return InterceptorInfo::cast(result);
7881}
7882
7883
7884InterceptorInfo* JSObject::GetIndexedInterceptor() {
7885 ASSERT(map()->has_indexed_interceptor());
7886 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01007887 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00007888 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01007889 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00007890 return InterceptorInfo::cast(result);
7891}
7892
7893
John Reck59135872010-11-02 12:39:01 -07007894MaybeObject* JSObject::GetPropertyPostInterceptor(
7895 JSObject* receiver,
7896 String* name,
7897 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01007898 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007899 // Check local property in holder, ignore interceptor.
7900 LookupResult result;
7901 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00007902 if (result.IsProperty()) {
7903 return GetProperty(receiver, &result, name, attributes);
7904 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007905 // Continue searching via the prototype chain.
7906 Object* pt = GetPrototype();
7907 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +01007908 if (pt->IsNull()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007909 return pt->GetPropertyWithReceiver(receiver, name, attributes);
7910}
7911
7912
John Reck59135872010-11-02 12:39:01 -07007913MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Steve Blockd0582a62009-12-15 09:54:21 +00007914 JSObject* receiver,
7915 String* name,
7916 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01007917 Heap* heap = GetHeap();
Steve Blockd0582a62009-12-15 09:54:21 +00007918 // Check local property in holder, ignore interceptor.
7919 LookupResult result;
7920 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00007921 if (result.IsProperty()) {
7922 return GetProperty(receiver, &result, name, attributes);
7923 }
Steve Block44f0eee2011-05-26 01:26:41 +01007924 return heap->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00007925}
7926
7927
John Reck59135872010-11-02 12:39:01 -07007928MaybeObject* JSObject::GetPropertyWithInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00007929 JSObject* receiver,
7930 String* name,
7931 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01007932 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007933 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01007934 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007935 Handle<JSObject> receiver_handle(receiver);
7936 Handle<JSObject> holder_handle(this);
7937 Handle<String> name_handle(name);
7938
7939 if (!interceptor->getter()->IsUndefined()) {
7940 v8::NamedPropertyGetter getter =
7941 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007942 LOG(isolate,
7943 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
7944 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007945 v8::AccessorInfo info(args.end());
7946 v8::Handle<v8::Value> result;
7947 {
7948 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007949 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007950 result = getter(v8::Utils::ToLocal(name_handle), info);
7951 }
Steve Block44f0eee2011-05-26 01:26:41 +01007952 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007953 if (!result.IsEmpty()) {
7954 *attributes = NONE;
7955 return *v8::Utils::OpenHandle(*result);
7956 }
7957 }
7958
John Reck59135872010-11-02 12:39:01 -07007959 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00007960 *receiver_handle,
7961 *name_handle,
7962 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01007963 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007964 return result;
7965}
7966
7967
7968bool JSObject::HasRealNamedProperty(String* key) {
Steve Block44f0eee2011-05-26 01:26:41 +01007969 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007970 // Check access rights if needed.
7971 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01007972 !heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
7973 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +00007974 return false;
7975 }
7976
7977 LookupResult result;
7978 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00007979 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00007980}
7981
7982
7983bool JSObject::HasRealElementProperty(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007984 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007985 // Check access rights if needed.
7986 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01007987 !heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7988 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +00007989 return false;
7990 }
7991
7992 // Handle [] on String objects.
7993 if (this->IsStringObjectWithCharacterAt(index)) return true;
7994
7995 switch (GetElementsKind()) {
7996 case FAST_ELEMENTS: {
7997 uint32_t length = IsJSArray() ?
7998 static_cast<uint32_t>(
7999 Smi::cast(JSArray::cast(this)->length())->value()) :
8000 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8001 return (index < length) &&
8002 !FixedArray::cast(elements())->get(index)->IsTheHole();
8003 }
Steve Block44f0eee2011-05-26 01:26:41 +01008004 case EXTERNAL_PIXEL_ELEMENTS: {
8005 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008006 return index < static_cast<uint32_t>(pixels->length());
8007 }
Steve Block3ce2e202009-11-05 08:53:23 +00008008 case EXTERNAL_BYTE_ELEMENTS:
8009 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8010 case EXTERNAL_SHORT_ELEMENTS:
8011 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8012 case EXTERNAL_INT_ELEMENTS:
8013 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8014 case EXTERNAL_FLOAT_ELEMENTS: {
8015 ExternalArray* array = ExternalArray::cast(elements());
8016 return index < static_cast<uint32_t>(array->length());
8017 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008018 case DICTIONARY_ELEMENTS: {
8019 return element_dictionary()->FindEntry(index)
8020 != NumberDictionary::kNotFound;
8021 }
8022 default:
8023 UNREACHABLE();
8024 break;
8025 }
8026 // All possibilities have been handled above already.
8027 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01008028 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008029}
8030
8031
8032bool JSObject::HasRealNamedCallbackProperty(String* key) {
Steve Block44f0eee2011-05-26 01:26:41 +01008033 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008034 // Check access rights if needed.
8035 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01008036 !heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8037 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +00008038 return false;
8039 }
8040
8041 LookupResult result;
8042 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008043 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00008044}
8045
8046
8047int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
8048 if (HasFastProperties()) {
8049 DescriptorArray* descs = map()->instance_descriptors();
8050 int result = 0;
8051 for (int i = 0; i < descs->number_of_descriptors(); i++) {
8052 PropertyDetails details = descs->GetDetails(i);
8053 if (details.IsProperty() && (details.attributes() & filter) == 0) {
8054 result++;
8055 }
8056 }
8057 return result;
8058 } else {
8059 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
8060 }
8061}
8062
8063
8064int JSObject::NumberOfEnumProperties() {
8065 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
8066}
8067
8068
8069void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
8070 Object* temp = get(i);
8071 set(i, get(j));
8072 set(j, temp);
8073 if (this != numbers) {
8074 temp = numbers->get(i);
8075 numbers->set(i, numbers->get(j));
8076 numbers->set(j, temp);
8077 }
8078}
8079
8080
8081static void InsertionSortPairs(FixedArray* content,
8082 FixedArray* numbers,
8083 int len) {
8084 for (int i = 1; i < len; i++) {
8085 int j = i;
8086 while (j > 0 &&
8087 (NumberToUint32(numbers->get(j - 1)) >
8088 NumberToUint32(numbers->get(j)))) {
8089 content->SwapPairs(numbers, j - 1, j);
8090 j--;
8091 }
8092 }
8093}
8094
8095
8096void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
8097 // In-place heap sort.
8098 ASSERT(content->length() == numbers->length());
8099
8100 // Bottom-up max-heap construction.
8101 for (int i = 1; i < len; ++i) {
8102 int child_index = i;
8103 while (child_index > 0) {
8104 int parent_index = ((child_index + 1) >> 1) - 1;
8105 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8106 uint32_t child_value = NumberToUint32(numbers->get(child_index));
8107 if (parent_value < child_value) {
8108 content->SwapPairs(numbers, parent_index, child_index);
8109 } else {
8110 break;
8111 }
8112 child_index = parent_index;
8113 }
8114 }
8115
8116 // Extract elements and create sorted array.
8117 for (int i = len - 1; i > 0; --i) {
8118 // Put max element at the back of the array.
8119 content->SwapPairs(numbers, 0, i);
8120 // Sift down the new top element.
8121 int parent_index = 0;
8122 while (true) {
8123 int child_index = ((parent_index + 1) << 1) - 1;
8124 if (child_index >= i) break;
8125 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
8126 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
8127 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8128 if (child_index + 1 >= i || child1_value > child2_value) {
8129 if (parent_value > child1_value) break;
8130 content->SwapPairs(numbers, parent_index, child_index);
8131 parent_index = child_index;
8132 } else {
8133 if (parent_value > child2_value) break;
8134 content->SwapPairs(numbers, parent_index, child_index + 1);
8135 parent_index = child_index + 1;
8136 }
8137 }
8138 }
8139}
8140
8141
8142// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
8143void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
8144 ASSERT(this->length() == numbers->length());
8145 // For small arrays, simply use insertion sort.
8146 if (len <= 10) {
8147 InsertionSortPairs(this, numbers, len);
8148 return;
8149 }
8150 // Check the range of indices.
8151 uint32_t min_index = NumberToUint32(numbers->get(0));
8152 uint32_t max_index = min_index;
8153 uint32_t i;
8154 for (i = 1; i < len; i++) {
8155 if (NumberToUint32(numbers->get(i)) < min_index) {
8156 min_index = NumberToUint32(numbers->get(i));
8157 } else if (NumberToUint32(numbers->get(i)) > max_index) {
8158 max_index = NumberToUint32(numbers->get(i));
8159 }
8160 }
8161 if (max_index - min_index + 1 == len) {
8162 // Indices form a contiguous range, unless there are duplicates.
8163 // Do an in-place linear time sort assuming distinct numbers, but
8164 // avoid hanging in case they are not.
8165 for (i = 0; i < len; i++) {
8166 uint32_t p;
8167 uint32_t j = 0;
8168 // While the current element at i is not at its correct position p,
8169 // swap the elements at these two positions.
8170 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
8171 j++ < len) {
8172 SwapPairs(numbers, i, p);
8173 }
8174 }
8175 } else {
8176 HeapSortPairs(this, numbers, len);
8177 return;
8178 }
8179}
8180
8181
8182// Fill in the names of local properties into the supplied storage. The main
8183// purpose of this function is to provide reflection information for the object
8184// mirrors.
8185void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
8186 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
8187 if (HasFastProperties()) {
8188 DescriptorArray* descs = map()->instance_descriptors();
8189 for (int i = 0; i < descs->number_of_descriptors(); i++) {
8190 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
8191 }
8192 ASSERT(storage->length() >= index);
8193 } else {
8194 property_dictionary()->CopyKeysTo(storage);
8195 }
8196}
8197
8198
8199int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
8200 return GetLocalElementKeys(NULL, filter);
8201}
8202
8203
8204int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00008205 // Fast case for objects with no elements.
8206 if (!IsJSValue() && HasFastElements()) {
8207 uint32_t length = IsJSArray() ?
8208 static_cast<uint32_t>(
8209 Smi::cast(JSArray::cast(this)->length())->value()) :
8210 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8211 if (length == 0) return 0;
8212 }
8213 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00008214 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
8215}
8216
8217
8218int JSObject::GetLocalElementKeys(FixedArray* storage,
8219 PropertyAttributes filter) {
8220 int counter = 0;
8221 switch (GetElementsKind()) {
8222 case FAST_ELEMENTS: {
8223 int length = IsJSArray() ?
8224 Smi::cast(JSArray::cast(this)->length())->value() :
8225 FixedArray::cast(elements())->length();
8226 for (int i = 0; i < length; i++) {
8227 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
8228 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008229 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008230 }
8231 counter++;
8232 }
8233 }
8234 ASSERT(!storage || storage->length() >= counter);
8235 break;
8236 }
Steve Block44f0eee2011-05-26 01:26:41 +01008237 case EXTERNAL_PIXEL_ELEMENTS: {
8238 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008239 while (counter < length) {
8240 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008241 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00008242 }
8243 counter++;
8244 }
8245 ASSERT(!storage || storage->length() >= counter);
8246 break;
8247 }
Steve Block3ce2e202009-11-05 08:53:23 +00008248 case EXTERNAL_BYTE_ELEMENTS:
8249 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8250 case EXTERNAL_SHORT_ELEMENTS:
8251 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8252 case EXTERNAL_INT_ELEMENTS:
8253 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
8254 case EXTERNAL_FLOAT_ELEMENTS: {
8255 int length = ExternalArray::cast(elements())->length();
8256 while (counter < length) {
8257 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008258 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00008259 }
8260 counter++;
8261 }
8262 ASSERT(!storage || storage->length() >= counter);
8263 break;
8264 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008265 case DICTIONARY_ELEMENTS: {
8266 if (storage != NULL) {
8267 element_dictionary()->CopyKeysTo(storage, filter);
8268 }
8269 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
8270 break;
8271 }
8272 default:
8273 UNREACHABLE();
8274 break;
8275 }
8276
8277 if (this->IsJSValue()) {
8278 Object* val = JSValue::cast(this)->value();
8279 if (val->IsString()) {
8280 String* str = String::cast(val);
8281 if (storage) {
8282 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00008283 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008284 }
8285 }
8286 counter += str->length();
8287 }
8288 }
8289 ASSERT(!storage || storage->length() == counter);
8290 return counter;
8291}
8292
8293
8294int JSObject::GetEnumElementKeys(FixedArray* storage) {
8295 return GetLocalElementKeys(storage,
8296 static_cast<PropertyAttributes>(DONT_ENUM));
8297}
8298
8299
Steve Blocka7e24c12009-10-30 11:49:00 +00008300// StringKey simply carries a string object as key.
8301class StringKey : public HashTableKey {
8302 public:
8303 explicit StringKey(String* string) :
8304 string_(string),
8305 hash_(HashForObject(string)) { }
8306
8307 bool IsMatch(Object* string) {
8308 // We know that all entries in a hash table had their hash keys created.
8309 // Use that knowledge to have fast failure.
8310 if (hash_ != HashForObject(string)) {
8311 return false;
8312 }
8313 return string_->Equals(String::cast(string));
8314 }
8315
8316 uint32_t Hash() { return hash_; }
8317
8318 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
8319
8320 Object* AsObject() { return string_; }
8321
8322 String* string_;
8323 uint32_t hash_;
8324};
8325
8326
8327// StringSharedKeys are used as keys in the eval cache.
8328class StringSharedKey : public HashTableKey {
8329 public:
Steve Block1e0659c2011-05-24 12:43:12 +01008330 StringSharedKey(String* source,
8331 SharedFunctionInfo* shared,
8332 StrictModeFlag strict_mode)
8333 : source_(source),
8334 shared_(shared),
8335 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008336
8337 bool IsMatch(Object* other) {
8338 if (!other->IsFixedArray()) return false;
8339 FixedArray* pair = FixedArray::cast(other);
8340 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8341 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01008342 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8343 Smi::cast(pair->get(2))->value());
8344 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008345 String* source = String::cast(pair->get(1));
8346 return source->Equals(source_);
8347 }
8348
8349 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01008350 SharedFunctionInfo* shared,
8351 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008352 uint32_t hash = source->Hash();
8353 if (shared->HasSourceCode()) {
8354 // Instead of using the SharedFunctionInfo pointer in the hash
8355 // code computation, we use a combination of the hash of the
8356 // script source code and the start and end positions. We do
8357 // this to ensure that the cache entries can survive garbage
8358 // collection.
8359 Script* script = Script::cast(shared->script());
8360 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01008361 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00008362 hash += shared->start_position();
8363 }
8364 return hash;
8365 }
8366
8367 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01008368 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008369 }
8370
8371 uint32_t HashForObject(Object* obj) {
8372 FixedArray* pair = FixedArray::cast(obj);
8373 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8374 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01008375 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8376 Smi::cast(pair->get(2))->value());
8377 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00008378 }
8379
John Reck59135872010-11-02 12:39:01 -07008380 MUST_USE_RESULT MaybeObject* AsObject() {
8381 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008382 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07008383 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8384 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008385 FixedArray* pair = FixedArray::cast(obj);
8386 pair->set(0, shared_);
8387 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01008388 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00008389 return pair;
8390 }
8391
8392 private:
8393 String* source_;
8394 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01008395 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008396};
8397
8398
8399// RegExpKey carries the source and flags of a regular expression as key.
8400class RegExpKey : public HashTableKey {
8401 public:
8402 RegExpKey(String* string, JSRegExp::Flags flags)
8403 : string_(string),
8404 flags_(Smi::FromInt(flags.value())) { }
8405
Steve Block3ce2e202009-11-05 08:53:23 +00008406 // Rather than storing the key in the hash table, a pointer to the
8407 // stored value is stored where the key should be. IsMatch then
8408 // compares the search key to the found object, rather than comparing
8409 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00008410 bool IsMatch(Object* obj) {
8411 FixedArray* val = FixedArray::cast(obj);
8412 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
8413 && (flags_ == val->get(JSRegExp::kFlagsIndex));
8414 }
8415
8416 uint32_t Hash() { return RegExpHash(string_, flags_); }
8417
8418 Object* AsObject() {
8419 // Plain hash maps, which is where regexp keys are used, don't
8420 // use this function.
8421 UNREACHABLE();
8422 return NULL;
8423 }
8424
8425 uint32_t HashForObject(Object* obj) {
8426 FixedArray* val = FixedArray::cast(obj);
8427 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
8428 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
8429 }
8430
8431 static uint32_t RegExpHash(String* string, Smi* flags) {
8432 return string->Hash() + flags->value();
8433 }
8434
8435 String* string_;
8436 Smi* flags_;
8437};
8438
8439// Utf8SymbolKey carries a vector of chars as key.
8440class Utf8SymbolKey : public HashTableKey {
8441 public:
8442 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00008443 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008444
8445 bool IsMatch(Object* string) {
8446 return String::cast(string)->IsEqualTo(string_);
8447 }
8448
8449 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00008450 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008451 unibrow::Utf8InputBuffer<> buffer(string_.start(),
8452 static_cast<unsigned>(string_.length()));
8453 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00008454 hash_field_ = String::ComputeHashField(&buffer, chars_);
8455 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008456 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8457 return result;
8458 }
8459
8460 uint32_t HashForObject(Object* other) {
8461 return String::cast(other)->Hash();
8462 }
8463
John Reck59135872010-11-02 12:39:01 -07008464 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00008465 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008466 return Isolate::Current()->heap()->AllocateSymbol(
8467 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008468 }
8469
8470 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00008471 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008472 int chars_; // Caches the number of characters when computing the hash code.
8473};
8474
8475
Steve Block9fac8402011-05-12 15:51:54 +01008476template <typename Char>
8477class SequentialSymbolKey : public HashTableKey {
8478 public:
8479 explicit SequentialSymbolKey(Vector<const Char> string)
8480 : string_(string), hash_field_(0) { }
8481
8482 uint32_t Hash() {
8483 StringHasher hasher(string_.length());
8484
8485 // Very long strings have a trivial hash that doesn't inspect the
8486 // string contents.
8487 if (hasher.has_trivial_hash()) {
8488 hash_field_ = hasher.GetHashField();
8489 } else {
8490 int i = 0;
8491 // Do the iterative array index computation as long as there is a
8492 // chance this is an array index.
8493 while (i < string_.length() && hasher.is_array_index()) {
8494 hasher.AddCharacter(static_cast<uc32>(string_[i]));
8495 i++;
8496 }
8497
8498 // Process the remaining characters without updating the array
8499 // index.
8500 while (i < string_.length()) {
8501 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
8502 i++;
8503 }
8504 hash_field_ = hasher.GetHashField();
8505 }
8506
8507 uint32_t result = hash_field_ >> String::kHashShift;
8508 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8509 return result;
8510 }
8511
8512
8513 uint32_t HashForObject(Object* other) {
8514 return String::cast(other)->Hash();
8515 }
8516
8517 Vector<const Char> string_;
8518 uint32_t hash_field_;
8519};
8520
8521
8522
8523class AsciiSymbolKey : public SequentialSymbolKey<char> {
8524 public:
8525 explicit AsciiSymbolKey(Vector<const char> str)
8526 : SequentialSymbolKey<char>(str) { }
8527
8528 bool IsMatch(Object* string) {
8529 return String::cast(string)->IsAsciiEqualTo(string_);
8530 }
8531
8532 MaybeObject* AsObject() {
8533 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008534 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008535 }
8536};
8537
8538
8539class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
8540 public:
8541 explicit TwoByteSymbolKey(Vector<const uc16> str)
8542 : SequentialSymbolKey<uc16>(str) { }
8543
8544 bool IsMatch(Object* string) {
8545 return String::cast(string)->IsTwoByteEqualTo(string_);
8546 }
8547
8548 MaybeObject* AsObject() {
8549 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008550 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008551 }
8552};
8553
8554
Steve Blocka7e24c12009-10-30 11:49:00 +00008555// SymbolKey carries a string/symbol object as key.
8556class SymbolKey : public HashTableKey {
8557 public:
Steve Block44f0eee2011-05-26 01:26:41 +01008558 explicit SymbolKey(String* string)
8559 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008560
8561 bool IsMatch(Object* string) {
8562 return String::cast(string)->Equals(string_);
8563 }
8564
8565 uint32_t Hash() { return string_->Hash(); }
8566
8567 uint32_t HashForObject(Object* other) {
8568 return String::cast(other)->Hash();
8569 }
8570
John Reck59135872010-11-02 12:39:01 -07008571 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01008572 // Attempt to flatten the string, so that symbols will most often
8573 // be flat strings.
8574 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01008575 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008576 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01008577 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008578 if (map != NULL) {
8579 string_->set_map(map);
8580 ASSERT(string_->IsSymbol());
8581 return string_;
8582 }
8583 // Otherwise allocate a new symbol.
8584 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01008585 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00008586 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00008587 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00008588 }
8589
8590 static uint32_t StringHash(Object* obj) {
8591 return String::cast(obj)->Hash();
8592 }
8593
8594 String* string_;
8595};
8596
8597
8598template<typename Shape, typename Key>
8599void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
8600 IteratePointers(v, 0, kElementsStartOffset);
8601}
8602
8603
8604template<typename Shape, typename Key>
8605void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
8606 IteratePointers(v,
8607 kElementsStartOffset,
8608 kHeaderSize + length() * kPointerSize);
8609}
8610
8611
8612template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008613MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
8614 PretenureFlag pretenure) {
Steve Block6ded16b2010-05-10 14:33:55 +01008615 const int kMinCapacity = 32;
8616 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
8617 if (capacity < kMinCapacity) {
8618 capacity = kMinCapacity; // Guarantee min capacity.
Leon Clarkee46be812010-01-19 14:06:41 +00008619 } else if (capacity > HashTable::kMaxCapacity) {
8620 return Failure::OutOfMemoryException();
8621 }
8622
John Reck59135872010-11-02 12:39:01 -07008623 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008624 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
8625 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07008626 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00008627 }
John Reck59135872010-11-02 12:39:01 -07008628 HashTable::cast(obj)->SetNumberOfElements(0);
8629 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
8630 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008631 return obj;
8632}
8633
8634
Leon Clarkee46be812010-01-19 14:06:41 +00008635// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008636int StringDictionary::FindEntry(String* key) {
8637 if (!key->IsSymbol()) {
8638 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
8639 }
8640
8641 // Optimized for symbol key. Knowledge of the key type allows:
8642 // 1. Move the check if the key is a symbol out of the loop.
8643 // 2. Avoid comparing hash codes in symbol to symbol comparision.
8644 // 3. Detect a case when a dictionary key is not a symbol but the key is.
8645 // In case of positive result the dictionary key may be replaced by
8646 // the symbol with minimal performance penalty. It gives a chance to
8647 // perform further lookups in code stubs (and significant performance boost
8648 // a certain style of code).
8649
8650 // EnsureCapacity will guarantee the hash table is never full.
8651 uint32_t capacity = Capacity();
8652 uint32_t entry = FirstProbe(key->Hash(), capacity);
8653 uint32_t count = 1;
8654
8655 while (true) {
8656 int index = EntryToIndex(entry);
8657 Object* element = get(index);
8658 if (element->IsUndefined()) break; // Empty entry.
8659 if (key == element) return entry;
8660 if (!element->IsSymbol() &&
8661 !element->IsNull() &&
8662 String::cast(element)->Equals(key)) {
8663 // Replace a non-symbol key by the equivalent symbol for faster further
8664 // lookups.
8665 set(index, key);
8666 return entry;
8667 }
8668 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
8669 entry = NextProbe(entry, count++, capacity);
8670 }
8671 return kNotFound;
8672}
8673
8674
Steve Blocka7e24c12009-10-30 11:49:00 +00008675template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008676MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Block44f0eee2011-05-26 01:26:41 +01008677 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008678 int capacity = Capacity();
8679 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00008680 int nod = NumberOfDeletedElements();
8681 // Return if:
8682 // 50% is still free after adding n elements and
8683 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01008684 if (nod <= (capacity - nof) >> 1) {
8685 int needed_free = nof >> 1;
8686 if (nof + needed_free <= capacity) return this;
8687 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008688
Steve Block6ded16b2010-05-10 14:33:55 +01008689 const int kMinCapacityForPretenure = 256;
8690 bool pretenure =
Steve Block44f0eee2011-05-26 01:26:41 +01008691 (capacity > kMinCapacityForPretenure) && !heap->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07008692 Object* obj;
8693 { MaybeObject* maybe_obj =
8694 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
8695 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8696 }
Leon Clarke4515c472010-02-03 11:58:03 +00008697
8698 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00008699 HashTable* table = HashTable::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00008700 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008701
8702 // Copy prefix to new array.
8703 for (int i = kPrefixStartIndex;
8704 i < kPrefixStartIndex + Shape::kPrefixSize;
8705 i++) {
8706 table->set(i, get(i), mode);
8707 }
8708 // Rehash the elements.
8709 for (int i = 0; i < capacity; i++) {
8710 uint32_t from_index = EntryToIndex(i);
8711 Object* k = get(from_index);
8712 if (IsKey(k)) {
8713 uint32_t hash = Shape::HashForObject(key, k);
8714 uint32_t insertion_index =
8715 EntryToIndex(table->FindInsertionEntry(hash));
8716 for (int j = 0; j < Shape::kEntrySize; j++) {
8717 table->set(insertion_index + j, get(from_index + j), mode);
8718 }
8719 }
8720 }
8721 table->SetNumberOfElements(NumberOfElements());
Leon Clarkee46be812010-01-19 14:06:41 +00008722 table->SetNumberOfDeletedElements(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00008723 return table;
8724}
8725
8726
8727template<typename Shape, typename Key>
8728uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
8729 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00008730 uint32_t entry = FirstProbe(hash, capacity);
8731 uint32_t count = 1;
8732 // EnsureCapacity will guarantee the hash table is never full.
8733 while (true) {
8734 Object* element = KeyAt(entry);
8735 if (element->IsUndefined() || element->IsNull()) break;
8736 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008737 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008738 return entry;
8739}
8740
8741// Force instantiation of template instances class.
8742// Please note this list is compiler dependent.
8743
8744template class HashTable<SymbolTableShape, HashTableKey*>;
8745
8746template class HashTable<CompilationCacheShape, HashTableKey*>;
8747
8748template class HashTable<MapCacheShape, HashTableKey*>;
8749
8750template class Dictionary<StringDictionaryShape, String*>;
8751
8752template class Dictionary<NumberDictionaryShape, uint32_t>;
8753
John Reck59135872010-11-02 12:39:01 -07008754template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00008755 int);
8756
John Reck59135872010-11-02 12:39:01 -07008757template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00008758 int);
8759
John Reck59135872010-11-02 12:39:01 -07008760template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +00008761 uint32_t, Object*);
8762
8763template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
8764 Object*);
8765
8766template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
8767 Object*);
8768
8769template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
8770 FixedArray*, PropertyAttributes);
8771
8772template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
8773 int, JSObject::DeleteMode);
8774
8775template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
8776 int, JSObject::DeleteMode);
8777
8778template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
8779 FixedArray*);
8780
8781template int
8782Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
8783 PropertyAttributes);
8784
John Reck59135872010-11-02 12:39:01 -07008785template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00008786 String*, Object*, PropertyDetails);
8787
John Reck59135872010-11-02 12:39:01 -07008788template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +00008789Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
8790
8791template int
8792Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
8793 PropertyAttributes);
8794
John Reck59135872010-11-02 12:39:01 -07008795template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00008796 uint32_t, Object*, PropertyDetails);
8797
John Reck59135872010-11-02 12:39:01 -07008798template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
8799 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00008800
John Reck59135872010-11-02 12:39:01 -07008801template MaybeObject* Dictionary<StringDictionaryShape, String*>::
8802 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +00008803
John Reck59135872010-11-02 12:39:01 -07008804template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00008805 uint32_t, Object*, PropertyDetails, uint32_t);
8806
John Reck59135872010-11-02 12:39:01 -07008807template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00008808 String*, Object*, PropertyDetails, uint32_t);
8809
8810template
8811int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
8812
8813template
8814int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
8815
Leon Clarkee46be812010-01-19 14:06:41 +00008816template
8817int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
8818
8819
Steve Blocka7e24c12009-10-30 11:49:00 +00008820// Collates undefined and unexisting elements below limit from position
8821// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -07008822MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Block44f0eee2011-05-26 01:26:41 +01008823 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008824 ASSERT(HasDictionaryElements());
8825 // Must stay in dictionary mode, either because of requires_slow_elements,
8826 // or because we are not going to sort (and therefore compact) all of the
8827 // elements.
8828 NumberDictionary* dict = element_dictionary();
8829 HeapNumber* result_double = NULL;
8830 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
8831 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -07008832 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +01008833 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07008834 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
8835 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008836 result_double = HeapNumber::cast(new_double);
8837 }
8838
John Reck59135872010-11-02 12:39:01 -07008839 Object* obj;
8840 { MaybeObject* maybe_obj =
8841 NumberDictionary::Allocate(dict->NumberOfElements());
8842 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8843 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008844 NumberDictionary* new_dict = NumberDictionary::cast(obj);
8845
8846 AssertNoAllocation no_alloc;
8847
8848 uint32_t pos = 0;
8849 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01008850 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +00008851 for (int i = 0; i < capacity; i++) {
8852 Object* k = dict->KeyAt(i);
8853 if (dict->IsKey(k)) {
8854 ASSERT(k->IsNumber());
8855 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
8856 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
8857 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
8858 Object* value = dict->ValueAt(i);
8859 PropertyDetails details = dict->DetailsAt(i);
8860 if (details.type() == CALLBACKS) {
8861 // Bail out and do the sorting of undefineds and array holes in JS.
8862 return Smi::FromInt(-1);
8863 }
8864 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -07008865 // In the following we assert that adding the entry to the new dictionary
8866 // does not cause GC. This is the case because we made sure to allocate
8867 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +00008868 if (key < limit) {
8869 if (value->IsUndefined()) {
8870 undefs++;
8871 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01008872 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
8873 // Adding an entry with the key beyond smi-range requires
8874 // allocation. Bailout.
8875 return Smi::FromInt(-1);
8876 }
John Reck59135872010-11-02 12:39:01 -07008877 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008878 pos++;
8879 }
8880 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01008881 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
8882 // Adding an entry with the key beyond smi-range requires
8883 // allocation. Bailout.
8884 return Smi::FromInt(-1);
8885 }
John Reck59135872010-11-02 12:39:01 -07008886 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008887 }
8888 }
8889 }
8890
8891 uint32_t result = pos;
8892 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
8893 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01008894 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
8895 // Adding an entry with the key beyond smi-range requires
8896 // allocation. Bailout.
8897 return Smi::FromInt(-1);
8898 }
Steve Block44f0eee2011-05-26 01:26:41 +01008899 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -07008900 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00008901 pos++;
8902 undefs--;
8903 }
8904
8905 set_elements(new_dict);
8906
8907 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
8908 return Smi::FromInt(static_cast<int>(result));
8909 }
8910
8911 ASSERT_NE(NULL, result_double);
8912 result_double->set_value(static_cast<double>(result));
8913 return result_double;
8914}
8915
8916
8917// Collects all defined (non-hole) and non-undefined (array) elements at
8918// the start of the elements array.
8919// If the object is in dictionary mode, it is converted to fast elements
8920// mode.
John Reck59135872010-11-02 12:39:01 -07008921MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Steve Block44f0eee2011-05-26 01:26:41 +01008922 Heap* heap = GetHeap();
8923 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008924
8925 if (HasDictionaryElements()) {
8926 // Convert to fast elements containing only the existing properties.
8927 // Ordering is irrelevant, since we are going to sort anyway.
8928 NumberDictionary* dict = element_dictionary();
8929 if (IsJSArray() || dict->requires_slow_elements() ||
8930 dict->max_number_key() >= limit) {
8931 return PrepareSlowElementsForSort(limit);
8932 }
8933 // Convert to fast elements.
8934
John Reck59135872010-11-02 12:39:01 -07008935 Object* obj;
8936 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
8937 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8938 }
Steve Block8defd9f2010-07-08 12:39:36 +01008939 Map* new_map = Map::cast(obj);
8940
Steve Block44f0eee2011-05-26 01:26:41 +01008941 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -07008942 Object* new_array;
8943 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +01008944 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -07008945 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
8946 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008947 FixedArray* fast_elements = FixedArray::cast(new_array);
8948 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +01008949
8950 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00008951 set_elements(fast_elements);
Iain Merrick75681382010-08-19 15:07:18 +01008952 } else {
John Reck59135872010-11-02 12:39:01 -07008953 Object* obj;
8954 { MaybeObject* maybe_obj = EnsureWritableFastElements();
8955 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8956 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008957 }
8958 ASSERT(HasFastElements());
8959
8960 // Collect holes at the end, undefined before that and the rest at the
8961 // start, and return the number of non-hole, non-undefined values.
8962
8963 FixedArray* elements = FixedArray::cast(this->elements());
8964 uint32_t elements_length = static_cast<uint32_t>(elements->length());
8965 if (limit > elements_length) {
8966 limit = elements_length ;
8967 }
8968 if (limit == 0) {
8969 return Smi::FromInt(0);
8970 }
8971
8972 HeapNumber* result_double = NULL;
8973 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
8974 // Pessimistically allocate space for return value before
8975 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -07008976 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +01008977 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07008978 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
8979 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008980 result_double = HeapNumber::cast(new_double);
8981 }
8982
8983 AssertNoAllocation no_alloc;
8984
8985 // Split elements into defined, undefined and the_hole, in that order.
8986 // Only count locations for undefined and the hole, and fill them afterwards.
Leon Clarke4515c472010-02-03 11:58:03 +00008987 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008988 unsigned int undefs = limit;
8989 unsigned int holes = limit;
8990 // Assume most arrays contain no holes and undefined values, so minimize the
8991 // number of stores of non-undefined, non-the-hole values.
8992 for (unsigned int i = 0; i < undefs; i++) {
8993 Object* current = elements->get(i);
8994 if (current->IsTheHole()) {
8995 holes--;
8996 undefs--;
8997 } else if (current->IsUndefined()) {
8998 undefs--;
8999 } else {
9000 continue;
9001 }
9002 // Position i needs to be filled.
9003 while (undefs > i) {
9004 current = elements->get(undefs);
9005 if (current->IsTheHole()) {
9006 holes--;
9007 undefs--;
9008 } else if (current->IsUndefined()) {
9009 undefs--;
9010 } else {
9011 elements->set(i, current, write_barrier);
9012 break;
9013 }
9014 }
9015 }
9016 uint32_t result = undefs;
9017 while (undefs < holes) {
9018 elements->set_undefined(undefs);
9019 undefs++;
9020 }
9021 while (holes < limit) {
9022 elements->set_the_hole(holes);
9023 holes++;
9024 }
9025
9026 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9027 return Smi::FromInt(static_cast<int>(result));
9028 }
9029 ASSERT_NE(NULL, result_double);
9030 result_double->set_value(static_cast<double>(result));
9031 return result_double;
9032}
9033
9034
Steve Block44f0eee2011-05-26 01:26:41 +01009035Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009036 uint8_t clamped_value = 0;
9037 if (index < static_cast<uint32_t>(length())) {
9038 if (value->IsSmi()) {
9039 int int_value = Smi::cast(value)->value();
9040 if (int_value < 0) {
9041 clamped_value = 0;
9042 } else if (int_value > 255) {
9043 clamped_value = 255;
9044 } else {
9045 clamped_value = static_cast<uint8_t>(int_value);
9046 }
9047 } else if (value->IsHeapNumber()) {
9048 double double_value = HeapNumber::cast(value)->value();
9049 if (!(double_value > 0)) {
9050 // NaN and less than zero clamp to zero.
9051 clamped_value = 0;
9052 } else if (double_value > 255) {
9053 // Greater than 255 clamp to 255.
9054 clamped_value = 255;
9055 } else {
9056 // Other doubles are rounded to the nearest integer.
9057 clamped_value = static_cast<uint8_t>(double_value + 0.5);
9058 }
9059 } else {
9060 // Clamp undefined to zero (default). All other types have been
9061 // converted to a number type further up in the call chain.
9062 ASSERT(value->IsUndefined());
9063 }
9064 set(index, clamped_value);
9065 }
9066 return Smi::FromInt(clamped_value);
9067}
9068
9069
Steve Block3ce2e202009-11-05 08:53:23 +00009070template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +01009071static MaybeObject* ExternalArrayIntSetter(Heap* heap,
9072 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -07009073 uint32_t index,
9074 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009075 ValueType cast_value = 0;
9076 if (index < static_cast<uint32_t>(receiver->length())) {
9077 if (value->IsSmi()) {
9078 int int_value = Smi::cast(value)->value();
9079 cast_value = static_cast<ValueType>(int_value);
9080 } else if (value->IsHeapNumber()) {
9081 double double_value = HeapNumber::cast(value)->value();
9082 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
9083 } else {
9084 // Clamp undefined to zero (default). All other types have been
9085 // converted to a number type further up in the call chain.
9086 ASSERT(value->IsUndefined());
9087 }
9088 receiver->set(index, cast_value);
9089 }
Steve Block44f0eee2011-05-26 01:26:41 +01009090 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009091}
9092
9093
John Reck59135872010-11-02 12:39:01 -07009094MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009095 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009096 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009097}
9098
9099
John Reck59135872010-11-02 12:39:01 -07009100MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
9101 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009102 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009103 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009104}
9105
9106
John Reck59135872010-11-02 12:39:01 -07009107MaybeObject* ExternalShortArray::SetValue(uint32_t index,
9108 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009109 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009110 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009111}
9112
9113
John Reck59135872010-11-02 12:39:01 -07009114MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
9115 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009116 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009117 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009118}
9119
9120
John Reck59135872010-11-02 12:39:01 -07009121MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009122 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009123 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009124}
9125
9126
John Reck59135872010-11-02 12:39:01 -07009127MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009128 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009129 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009130 if (index < static_cast<uint32_t>(length())) {
9131 if (value->IsSmi()) {
9132 int int_value = Smi::cast(value)->value();
9133 cast_value = static_cast<uint32_t>(int_value);
9134 } else if (value->IsHeapNumber()) {
9135 double double_value = HeapNumber::cast(value)->value();
9136 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
9137 } else {
9138 // Clamp undefined to zero (default). All other types have been
9139 // converted to a number type further up in the call chain.
9140 ASSERT(value->IsUndefined());
9141 }
9142 set(index, cast_value);
9143 }
Steve Block44f0eee2011-05-26 01:26:41 +01009144 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009145}
9146
9147
John Reck59135872010-11-02 12:39:01 -07009148MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009149 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009150 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009151 if (index < static_cast<uint32_t>(length())) {
9152 if (value->IsSmi()) {
9153 int int_value = Smi::cast(value)->value();
9154 cast_value = static_cast<float>(int_value);
9155 } else if (value->IsHeapNumber()) {
9156 double double_value = HeapNumber::cast(value)->value();
9157 cast_value = static_cast<float>(double_value);
9158 } else {
9159 // Clamp undefined to zero (default). All other types have been
9160 // converted to a number type further up in the call chain.
9161 ASSERT(value->IsUndefined());
9162 }
9163 set(index, cast_value);
9164 }
Steve Block44f0eee2011-05-26 01:26:41 +01009165 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009166}
9167
9168
Ben Murdochb0fe1622011-05-05 13:52:32 +01009169JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009170 ASSERT(!HasFastProperties());
9171 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009172 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009173}
9174
9175
John Reck59135872010-11-02 12:39:01 -07009176MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009177 ASSERT(!HasFastProperties());
Steve Block44f0eee2011-05-26 01:26:41 +01009178 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009179 int entry = property_dictionary()->FindEntry(name);
9180 if (entry == StringDictionary::kNotFound) {
John Reck59135872010-11-02 12:39:01 -07009181 Object* cell;
9182 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +01009183 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -07009184 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
9185 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009186 PropertyDetails details(NONE, NORMAL);
9187 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -07009188 Object* dictionary;
9189 { MaybeObject* maybe_dictionary =
9190 property_dictionary()->Add(name, cell, details);
9191 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
9192 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009193 set_properties(StringDictionary::cast(dictionary));
9194 return cell;
9195 } else {
9196 Object* value = property_dictionary()->ValueAt(entry);
9197 ASSERT(value->IsJSGlobalPropertyCell());
9198 return value;
9199 }
9200}
9201
9202
John Reck59135872010-11-02 12:39:01 -07009203MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009204 SymbolKey key(string);
9205 return LookupKey(&key, s);
9206}
9207
9208
Steve Blockd0582a62009-12-15 09:54:21 +00009209// This class is used for looking up two character strings in the symbol table.
9210// If we don't have a hit we don't want to waste much time so we unroll the
9211// string hash calculation loop here for speed. Doesn't work if the two
9212// characters form a decimal integer, since such strings have a different hash
9213// algorithm.
9214class TwoCharHashTableKey : public HashTableKey {
9215 public:
9216 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
9217 : c1_(c1), c2_(c2) {
9218 // Char 1.
9219 uint32_t hash = c1 + (c1 << 10);
9220 hash ^= hash >> 6;
9221 // Char 2.
9222 hash += c2;
9223 hash += hash << 10;
9224 hash ^= hash >> 6;
9225 // GetHash.
9226 hash += hash << 3;
9227 hash ^= hash >> 11;
9228 hash += hash << 15;
9229 if (hash == 0) hash = 27;
9230#ifdef DEBUG
9231 StringHasher hasher(2);
9232 hasher.AddCharacter(c1);
9233 hasher.AddCharacter(c2);
9234 // If this assert fails then we failed to reproduce the two-character
9235 // version of the string hashing algorithm above. One reason could be
9236 // that we were passed two digits as characters, since the hash
9237 // algorithm is different in that case.
9238 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
9239#endif
9240 hash_ = hash;
9241 }
9242
9243 bool IsMatch(Object* o) {
9244 if (!o->IsString()) return false;
9245 String* other = String::cast(o);
9246 if (other->length() != 2) return false;
9247 if (other->Get(0) != c1_) return false;
9248 return other->Get(1) == c2_;
9249 }
9250
9251 uint32_t Hash() { return hash_; }
9252 uint32_t HashForObject(Object* key) {
9253 if (!key->IsString()) return 0;
9254 return String::cast(key)->Hash();
9255 }
9256
9257 Object* AsObject() {
9258 // The TwoCharHashTableKey is only used for looking in the symbol
9259 // table, not for adding to it.
9260 UNREACHABLE();
9261 return NULL;
9262 }
9263 private:
9264 uint32_t c1_;
9265 uint32_t c2_;
9266 uint32_t hash_;
9267};
9268
9269
Steve Blocka7e24c12009-10-30 11:49:00 +00009270bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
9271 SymbolKey key(string);
9272 int entry = FindEntry(&key);
9273 if (entry == kNotFound) {
9274 return false;
9275 } else {
9276 String* result = String::cast(KeyAt(entry));
9277 ASSERT(StringShape(result).IsSymbol());
9278 *symbol = result;
9279 return true;
9280 }
9281}
9282
9283
Steve Blockd0582a62009-12-15 09:54:21 +00009284bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
9285 uint32_t c2,
9286 String** symbol) {
9287 TwoCharHashTableKey key(c1, c2);
9288 int entry = FindEntry(&key);
9289 if (entry == kNotFound) {
9290 return false;
9291 } else {
9292 String* result = String::cast(KeyAt(entry));
9293 ASSERT(StringShape(result).IsSymbol());
9294 *symbol = result;
9295 return true;
9296 }
9297}
9298
9299
John Reck59135872010-11-02 12:39:01 -07009300MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009301 Utf8SymbolKey key(str);
9302 return LookupKey(&key, s);
9303}
9304
9305
Steve Block9fac8402011-05-12 15:51:54 +01009306MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
9307 Object** s) {
9308 AsciiSymbolKey key(str);
9309 return LookupKey(&key, s);
9310}
9311
9312
9313MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
9314 Object** s) {
9315 TwoByteSymbolKey key(str);
9316 return LookupKey(&key, s);
9317}
9318
John Reck59135872010-11-02 12:39:01 -07009319MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009320 int entry = FindEntry(key);
9321
9322 // Symbol already in table.
9323 if (entry != kNotFound) {
9324 *s = KeyAt(entry);
9325 return this;
9326 }
9327
9328 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -07009329 Object* obj;
9330 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9331 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9332 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009333
9334 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -07009335 Object* symbol;
9336 { MaybeObject* maybe_symbol = key->AsObject();
9337 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
9338 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009339
9340 // If the symbol table grew as part of EnsureCapacity, obj is not
9341 // the current symbol table and therefore we cannot use
9342 // SymbolTable::cast here.
9343 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
9344
9345 // Add the new symbol and return it along with the symbol table.
9346 entry = table->FindInsertionEntry(key->Hash());
9347 table->set(EntryToIndex(entry), symbol);
9348 table->ElementAdded();
9349 *s = symbol;
9350 return table;
9351}
9352
9353
9354Object* CompilationCacheTable::Lookup(String* src) {
Steve Block44f0eee2011-05-26 01:26:41 +01009355 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009356 StringKey key(src);
9357 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009358 if (entry == kNotFound) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009359 return get(EntryToIndex(entry) + 1);
9360}
9361
9362
Steve Block1e0659c2011-05-24 12:43:12 +01009363Object* CompilationCacheTable::LookupEval(String* src,
9364 Context* context,
9365 StrictModeFlag strict_mode) {
9366 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009367 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009368 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009369 return get(EntryToIndex(entry) + 1);
9370}
9371
9372
9373Object* CompilationCacheTable::LookupRegExp(String* src,
9374 JSRegExp::Flags flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01009375 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009376 RegExpKey key(src, flags);
9377 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009378 if (entry == kNotFound) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009379 return get(EntryToIndex(entry) + 1);
9380}
9381
9382
John Reck59135872010-11-02 12:39:01 -07009383MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009384 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -07009385 Object* obj;
9386 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9387 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9388 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009389
9390 CompilationCacheTable* cache =
9391 reinterpret_cast<CompilationCacheTable*>(obj);
9392 int entry = cache->FindInsertionEntry(key.Hash());
9393 cache->set(EntryToIndex(entry), src);
9394 cache->set(EntryToIndex(entry) + 1, value);
9395 cache->ElementAdded();
9396 return cache;
9397}
9398
9399
John Reck59135872010-11-02 12:39:01 -07009400MaybeObject* CompilationCacheTable::PutEval(String* src,
9401 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +01009402 SharedFunctionInfo* value) {
9403 StringSharedKey key(src,
9404 context->closure()->shared(),
9405 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -07009406 Object* obj;
9407 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9408 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9409 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009410
9411 CompilationCacheTable* cache =
9412 reinterpret_cast<CompilationCacheTable*>(obj);
9413 int entry = cache->FindInsertionEntry(key.Hash());
9414
John Reck59135872010-11-02 12:39:01 -07009415 Object* k;
9416 { MaybeObject* maybe_k = key.AsObject();
9417 if (!maybe_k->ToObject(&k)) return maybe_k;
9418 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009419
9420 cache->set(EntryToIndex(entry), k);
9421 cache->set(EntryToIndex(entry) + 1, value);
9422 cache->ElementAdded();
9423 return cache;
9424}
9425
9426
John Reck59135872010-11-02 12:39:01 -07009427MaybeObject* CompilationCacheTable::PutRegExp(String* src,
9428 JSRegExp::Flags flags,
9429 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009430 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -07009431 Object* obj;
9432 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9433 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9434 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009435
9436 CompilationCacheTable* cache =
9437 reinterpret_cast<CompilationCacheTable*>(obj);
9438 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +00009439 // We store the value in the key slot, and compare the search key
9440 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +00009441 cache->set(EntryToIndex(entry), value);
9442 cache->set(EntryToIndex(entry) + 1, value);
9443 cache->ElementAdded();
9444 return cache;
9445}
9446
9447
Ben Murdochb0fe1622011-05-05 13:52:32 +01009448void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009449 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01009450 for (int entry = 0, size = Capacity(); entry < size; entry++) {
9451 int entry_index = EntryToIndex(entry);
9452 int value_index = entry_index + 1;
9453 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009454 fast_set(this, entry_index, null_value);
9455 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009456 ElementRemoved();
9457 }
9458 }
9459 return;
9460}
9461
9462
Steve Blocka7e24c12009-10-30 11:49:00 +00009463// SymbolsKey used for HashTable where key is array of symbols.
9464class SymbolsKey : public HashTableKey {
9465 public:
9466 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
9467
9468 bool IsMatch(Object* symbols) {
9469 FixedArray* o = FixedArray::cast(symbols);
9470 int len = symbols_->length();
9471 if (o->length() != len) return false;
9472 for (int i = 0; i < len; i++) {
9473 if (o->get(i) != symbols_->get(i)) return false;
9474 }
9475 return true;
9476 }
9477
9478 uint32_t Hash() { return HashForObject(symbols_); }
9479
9480 uint32_t HashForObject(Object* obj) {
9481 FixedArray* symbols = FixedArray::cast(obj);
9482 int len = symbols->length();
9483 uint32_t hash = 0;
9484 for (int i = 0; i < len; i++) {
9485 hash ^= String::cast(symbols->get(i))->Hash();
9486 }
9487 return hash;
9488 }
9489
9490 Object* AsObject() { return symbols_; }
9491
9492 private:
9493 FixedArray* symbols_;
9494};
9495
9496
9497Object* MapCache::Lookup(FixedArray* array) {
Steve Block44f0eee2011-05-26 01:26:41 +01009498 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009499 SymbolsKey key(array);
9500 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009501 if (entry == kNotFound) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009502 return get(EntryToIndex(entry) + 1);
9503}
9504
9505
John Reck59135872010-11-02 12:39:01 -07009506MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009507 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -07009508 Object* obj;
9509 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9510 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9511 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009512
9513 MapCache* cache = reinterpret_cast<MapCache*>(obj);
9514 int entry = cache->FindInsertionEntry(key.Hash());
9515 cache->set(EntryToIndex(entry), array);
9516 cache->set(EntryToIndex(entry) + 1, value);
9517 cache->ElementAdded();
9518 return cache;
9519}
9520
9521
9522template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009523MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
9524 Object* obj;
9525 { MaybeObject* maybe_obj =
9526 HashTable<Shape, Key>::Allocate(at_least_space_for);
9527 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009528 }
John Reck59135872010-11-02 12:39:01 -07009529 // Initialize the next enumeration index.
9530 Dictionary<Shape, Key>::cast(obj)->
9531 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +00009532 return obj;
9533}
9534
9535
9536template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009537MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +01009538 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009539 int length = HashTable<Shape, Key>::NumberOfElements();
9540
9541 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -07009542 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009543 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009544 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9545 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009546 FixedArray* iteration_order = FixedArray::cast(obj);
9547 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009548 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009549 }
9550
9551 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +01009552 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009553 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9554 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009555 FixedArray* enumeration_order = FixedArray::cast(obj);
9556
9557 // Fill the enumeration order array with property details.
9558 int capacity = HashTable<Shape, Key>::Capacity();
9559 int pos = 0;
9560 for (int i = 0; i < capacity; i++) {
9561 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +00009562 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009563 }
9564 }
9565
9566 // Sort the arrays wrt. enumeration order.
9567 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
9568
9569 // Overwrite the enumeration_order with the enumeration indices.
9570 for (int i = 0; i < length; i++) {
9571 int index = Smi::cast(iteration_order->get(i))->value();
9572 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +00009573 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +00009574 }
9575
9576 // Update the dictionary with new indices.
9577 capacity = HashTable<Shape, Key>::Capacity();
9578 pos = 0;
9579 for (int i = 0; i < capacity; i++) {
9580 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
9581 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
9582 PropertyDetails details = DetailsAt(i);
9583 PropertyDetails new_details =
9584 PropertyDetails(details.attributes(), details.type(), enum_index);
9585 DetailsAtPut(i, new_details);
9586 }
9587 }
9588
9589 // Set the next enumeration index.
9590 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
9591 return this;
9592}
9593
9594template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009595MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009596 // Check whether there are enough enumeration indices to add n elements.
9597 if (Shape::kIsEnumerable &&
9598 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
9599 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -07009600 Object* result;
9601 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
9602 if (!maybe_result->ToObject(&result)) return maybe_result;
9603 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009604 }
9605 return HashTable<Shape, Key>::EnsureCapacity(n, key);
9606}
9607
9608
9609void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
9610 // Do nothing if the interval [from, to) is empty.
9611 if (from >= to) return;
9612
Steve Block44f0eee2011-05-26 01:26:41 +01009613 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009614 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009615 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009616 int capacity = Capacity();
9617 for (int i = 0; i < capacity; i++) {
9618 Object* key = KeyAt(i);
9619 if (key->IsNumber()) {
9620 uint32_t number = static_cast<uint32_t>(key->Number());
9621 if (from <= number && number < to) {
9622 SetEntry(i, sentinel, sentinel, Smi::FromInt(0));
9623 removed_entries++;
9624 }
9625 }
9626 }
9627
9628 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +00009629 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +00009630}
9631
9632
9633template<typename Shape, typename Key>
9634Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
9635 JSObject::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01009636 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009637 PropertyDetails details = DetailsAt(entry);
9638 // Ignore attributes if forcing a deletion.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009639 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +01009640 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009641 }
Steve Block44f0eee2011-05-26 01:26:41 +01009642 SetEntry(entry, heap->null_value(), heap->null_value(), Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00009643 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +01009644 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009645}
9646
9647
9648template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009649MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009650 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +00009651
9652 // If the entry is present set the value;
9653 if (entry != Dictionary<Shape, Key>::kNotFound) {
9654 ValueAtPut(entry, value);
9655 return this;
9656 }
9657
9658 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -07009659 Object* obj;
9660 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9661 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9662 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009663
John Reck59135872010-11-02 12:39:01 -07009664 Object* k;
9665 { MaybeObject* maybe_k = Shape::AsObject(key);
9666 if (!maybe_k->ToObject(&k)) return maybe_k;
9667 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009668 PropertyDetails details = PropertyDetails(NONE, NORMAL);
9669 return Dictionary<Shape, Key>::cast(obj)->
9670 AddEntry(key, value, details, Shape::Hash(key));
9671}
9672
9673
9674template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009675MaybeObject* Dictionary<Shape, Key>::Add(Key key,
9676 Object* value,
9677 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009678 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009679 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +00009680 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -07009681 Object* obj;
9682 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9683 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9684 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009685 return Dictionary<Shape, Key>::cast(obj)->
9686 AddEntry(key, value, details, Shape::Hash(key));
9687}
9688
9689
9690// Add a key, value pair to the dictionary.
9691template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009692MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
9693 Object* value,
9694 PropertyDetails details,
9695 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009696 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -07009697 Object* k;
9698 { MaybeObject* maybe_k = Shape::AsObject(key);
9699 if (!maybe_k->ToObject(&k)) return maybe_k;
9700 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009701
9702 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
9703 // Insert element at empty or deleted entry
9704 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
9705 // Assign an enumeration index to the property and update
9706 // SetNextEnumerationIndex.
9707 int index = NextEnumerationIndex();
9708 details = PropertyDetails(details.attributes(), details.type(), index);
9709 SetNextEnumerationIndex(index + 1);
9710 }
9711 SetEntry(entry, k, value, details);
9712 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
9713 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
9714 HashTable<Shape, Key>::ElementAdded();
9715 return this;
9716}
9717
9718
9719void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
9720 // If the dictionary requires slow elements an element has already
9721 // been added at a high index.
9722 if (requires_slow_elements()) return;
9723 // Check if this index is high enough that we should require slow
9724 // elements.
9725 if (key > kRequiresSlowElementsLimit) {
9726 set_requires_slow_elements();
9727 return;
9728 }
9729 // Update max key value.
9730 Object* max_index_object = get(kMaxNumberKeyIndex);
9731 if (!max_index_object->IsSmi() || max_number_key() < key) {
9732 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00009733 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +00009734 }
9735}
9736
9737
John Reck59135872010-11-02 12:39:01 -07009738MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
9739 Object* value,
9740 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009741 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009742 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +00009743 return Add(key, value, details);
9744}
9745
9746
John Reck59135872010-11-02 12:39:01 -07009747MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009748 UpdateMaxNumberKey(key);
9749 return AtPut(key, value);
9750}
9751
9752
John Reck59135872010-11-02 12:39:01 -07009753MaybeObject* NumberDictionary::Set(uint32_t key,
9754 Object* value,
9755 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009756 int entry = FindEntry(key);
9757 if (entry == kNotFound) return AddNumberEntry(key, value, details);
9758 // Preserve enumeration index.
9759 details = PropertyDetails(details.attributes(),
9760 details.type(),
9761 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -07009762 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
9763 Object* object_key;
9764 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +01009765 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00009766 return this;
9767}
9768
9769
9770
9771template<typename Shape, typename Key>
9772int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
9773 PropertyAttributes filter) {
9774 int capacity = HashTable<Shape, Key>::Capacity();
9775 int result = 0;
9776 for (int i = 0; i < capacity; i++) {
9777 Object* k = HashTable<Shape, Key>::KeyAt(i);
9778 if (HashTable<Shape, Key>::IsKey(k)) {
9779 PropertyDetails details = DetailsAt(i);
9780 if (details.IsDeleted()) continue;
9781 PropertyAttributes attr = details.attributes();
9782 if ((attr & filter) == 0) result++;
9783 }
9784 }
9785 return result;
9786}
9787
9788
9789template<typename Shape, typename Key>
9790int Dictionary<Shape, Key>::NumberOfEnumElements() {
9791 return NumberOfElementsFilterAttributes(
9792 static_cast<PropertyAttributes>(DONT_ENUM));
9793}
9794
9795
9796template<typename Shape, typename Key>
9797void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
9798 PropertyAttributes filter) {
9799 ASSERT(storage->length() >= NumberOfEnumElements());
9800 int capacity = HashTable<Shape, Key>::Capacity();
9801 int index = 0;
9802 for (int i = 0; i < capacity; i++) {
9803 Object* k = HashTable<Shape, Key>::KeyAt(i);
9804 if (HashTable<Shape, Key>::IsKey(k)) {
9805 PropertyDetails details = DetailsAt(i);
9806 if (details.IsDeleted()) continue;
9807 PropertyAttributes attr = details.attributes();
9808 if ((attr & filter) == 0) storage->set(index++, k);
9809 }
9810 }
9811 storage->SortPairs(storage, index);
9812 ASSERT(storage->length() >= index);
9813}
9814
9815
9816void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
9817 FixedArray* sort_array) {
9818 ASSERT(storage->length() >= NumberOfEnumElements());
9819 int capacity = Capacity();
9820 int index = 0;
9821 for (int i = 0; i < capacity; i++) {
9822 Object* k = KeyAt(i);
9823 if (IsKey(k)) {
9824 PropertyDetails details = DetailsAt(i);
9825 if (details.IsDeleted() || details.IsDontEnum()) continue;
9826 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +00009827 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009828 index++;
9829 }
9830 }
9831 storage->SortPairs(sort_array, sort_array->length());
9832 ASSERT(storage->length() >= index);
9833}
9834
9835
9836template<typename Shape, typename Key>
9837void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage) {
9838 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
9839 static_cast<PropertyAttributes>(NONE)));
9840 int capacity = HashTable<Shape, Key>::Capacity();
9841 int index = 0;
9842 for (int i = 0; i < capacity; i++) {
9843 Object* k = HashTable<Shape, Key>::KeyAt(i);
9844 if (HashTable<Shape, Key>::IsKey(k)) {
9845 PropertyDetails details = DetailsAt(i);
9846 if (details.IsDeleted()) continue;
9847 storage->set(index++, k);
9848 }
9849 }
9850 ASSERT(storage->length() >= index);
9851}
9852
9853
9854// Backwards lookup (slow).
9855template<typename Shape, typename Key>
9856Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009857 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009858 int capacity = HashTable<Shape, Key>::Capacity();
9859 for (int i = 0; i < capacity; i++) {
9860 Object* k = HashTable<Shape, Key>::KeyAt(i);
9861 if (Dictionary<Shape, Key>::IsKey(k)) {
9862 Object* e = ValueAt(i);
9863 if (e->IsJSGlobalPropertyCell()) {
9864 e = JSGlobalPropertyCell::cast(e)->value();
9865 }
9866 if (e == value) return k;
9867 }
9868 }
Steve Block44f0eee2011-05-26 01:26:41 +01009869 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009870}
9871
9872
John Reck59135872010-11-02 12:39:01 -07009873MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +00009874 JSObject* obj, int unused_property_fields) {
Steve Block44f0eee2011-05-26 01:26:41 +01009875 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009876 // Make sure we preserve dictionary representation if there are too many
9877 // descriptors.
9878 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
9879
9880 // Figure out if it is necessary to generate new enumeration indices.
9881 int max_enumeration_index =
9882 NextEnumerationIndex() +
9883 (DescriptorArray::kMaxNumberOfDescriptors -
9884 NumberOfElements());
9885 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -07009886 Object* result;
9887 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
9888 if (!maybe_result->ToObject(&result)) return maybe_result;
9889 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009890 }
9891
9892 int instance_descriptor_length = 0;
9893 int number_of_fields = 0;
9894
9895 // Compute the length of the instance descriptor.
9896 int capacity = Capacity();
9897 for (int i = 0; i < capacity; i++) {
9898 Object* k = KeyAt(i);
9899 if (IsKey(k)) {
9900 Object* value = ValueAt(i);
9901 PropertyType type = DetailsAt(i).type();
9902 ASSERT(type != FIELD);
9903 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +00009904 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +01009905 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +00009906 number_of_fields += 1;
9907 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009908 }
9909 }
9910
9911 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -07009912 Object* descriptors_unchecked;
9913 { MaybeObject* maybe_descriptors_unchecked =
9914 DescriptorArray::Allocate(instance_descriptor_length);
9915 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
9916 return maybe_descriptors_unchecked;
9917 }
9918 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009919 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
9920
9921 int inobject_props = obj->map()->inobject_properties();
9922 int number_of_allocated_fields =
9923 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +01009924 if (number_of_allocated_fields < 0) {
9925 // There is enough inobject space for all fields (including unused).
9926 number_of_allocated_fields = 0;
9927 unused_property_fields = inobject_props - number_of_fields;
9928 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009929
9930 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -07009931 Object* fields;
9932 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +01009933 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -07009934 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
9935 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009936
9937 // Fill in the instance descriptor and the fields.
9938 int next_descriptor = 0;
9939 int current_offset = 0;
9940 for (int i = 0; i < capacity; i++) {
9941 Object* k = KeyAt(i);
9942 if (IsKey(k)) {
9943 Object* value = ValueAt(i);
9944 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -07009945 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +01009946 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -07009947 if (!maybe_key->ToObject(&key)) return maybe_key;
9948 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009949 PropertyDetails details = DetailsAt(i);
9950 PropertyType type = details.type();
9951
Steve Block44f0eee2011-05-26 01:26:41 +01009952 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009953 ConstantFunctionDescriptor d(String::cast(key),
9954 JSFunction::cast(value),
9955 details.attributes(),
9956 details.index());
9957 descriptors->Set(next_descriptor++, &d);
9958 } else if (type == NORMAL) {
9959 if (current_offset < inobject_props) {
9960 obj->InObjectPropertyAtPut(current_offset,
9961 value,
9962 UPDATE_WRITE_BARRIER);
9963 } else {
9964 int offset = current_offset - inobject_props;
9965 FixedArray::cast(fields)->set(offset, value);
9966 }
9967 FieldDescriptor d(String::cast(key),
9968 current_offset++,
9969 details.attributes(),
9970 details.index());
9971 descriptors->Set(next_descriptor++, &d);
9972 } else if (type == CALLBACKS) {
9973 CallbacksDescriptor d(String::cast(key),
9974 value,
9975 details.attributes(),
9976 details.index());
9977 descriptors->Set(next_descriptor++, &d);
9978 } else {
9979 UNREACHABLE();
9980 }
9981 }
9982 }
9983 ASSERT(current_offset == number_of_fields);
9984
9985 descriptors->Sort();
9986 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -07009987 Object* new_map;
9988 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
9989 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
9990 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009991
9992 // Transform the object.
9993 obj->set_map(Map::cast(new_map));
9994 obj->map()->set_instance_descriptors(descriptors);
9995 obj->map()->set_unused_property_fields(unused_property_fields);
9996
9997 obj->set_properties(FixedArray::cast(fields));
9998 ASSERT(obj->IsJSObject());
9999
10000 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
10001 // Check that it really works.
10002 ASSERT(obj->HasFastProperties());
10003
10004 return obj;
10005}
10006
10007
10008#ifdef ENABLE_DEBUGGER_SUPPORT
10009// Check if there is a break point at this code position.
10010bool DebugInfo::HasBreakPoint(int code_position) {
10011 // Get the break point info object for this code position.
10012 Object* break_point_info = GetBreakPointInfo(code_position);
10013
10014 // If there is no break point info object or no break points in the break
10015 // point info object there is no break point at this code position.
10016 if (break_point_info->IsUndefined()) return false;
10017 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
10018}
10019
10020
10021// Get the break point info object for this code position.
10022Object* DebugInfo::GetBreakPointInfo(int code_position) {
Steve Block44f0eee2011-05-26 01:26:41 +010010023 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010024 // Find the index of the break point info object for this code position.
10025 int index = GetBreakPointInfoIndex(code_position);
10026
10027 // Return the break point info object if any.
Steve Block44f0eee2011-05-26 01:26:41 +010010028 if (index == kNoBreakPointInfo) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010029 return BreakPointInfo::cast(break_points()->get(index));
10030}
10031
10032
10033// Clear a break point at the specified code position.
10034void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
10035 int code_position,
10036 Handle<Object> break_point_object) {
10037 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10038 if (break_point_info->IsUndefined()) return;
10039 BreakPointInfo::ClearBreakPoint(
10040 Handle<BreakPointInfo>::cast(break_point_info),
10041 break_point_object);
10042}
10043
10044
10045void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
10046 int code_position,
10047 int source_position,
10048 int statement_position,
10049 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010050 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010051 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10052 if (!break_point_info->IsUndefined()) {
10053 BreakPointInfo::SetBreakPoint(
10054 Handle<BreakPointInfo>::cast(break_point_info),
10055 break_point_object);
10056 return;
10057 }
10058
10059 // Adding a new break point for a code position which did not have any
10060 // break points before. Try to find a free slot.
10061 int index = kNoBreakPointInfo;
10062 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10063 if (debug_info->break_points()->get(i)->IsUndefined()) {
10064 index = i;
10065 break;
10066 }
10067 }
10068 if (index == kNoBreakPointInfo) {
10069 // No free slot - extend break point info array.
10070 Handle<FixedArray> old_break_points =
10071 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010072 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010010073 isolate->factory()->NewFixedArray(
10074 old_break_points->length() +
10075 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010076
10077 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000010078 for (int i = 0; i < old_break_points->length(); i++) {
10079 new_break_points->set(i, old_break_points->get(i));
10080 }
10081 index = old_break_points->length();
10082 }
10083 ASSERT(index != kNoBreakPointInfo);
10084
10085 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010010086 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
10087 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000010088 new_break_point_info->set_code_position(Smi::FromInt(code_position));
10089 new_break_point_info->set_source_position(Smi::FromInt(source_position));
10090 new_break_point_info->
10091 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010010092 new_break_point_info->set_break_point_objects(
10093 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010094 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
10095 debug_info->break_points()->set(index, *new_break_point_info);
10096}
10097
10098
10099// Get the break point objects for a code position.
10100Object* DebugInfo::GetBreakPointObjects(int code_position) {
Steve Block44f0eee2011-05-26 01:26:41 +010010101 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010102 Object* break_point_info = GetBreakPointInfo(code_position);
10103 if (break_point_info->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010104 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010105 }
10106 return BreakPointInfo::cast(break_point_info)->break_point_objects();
10107}
10108
10109
10110// Get the total number of break points.
10111int DebugInfo::GetBreakPointCount() {
10112 if (break_points()->IsUndefined()) return 0;
10113 int count = 0;
10114 for (int i = 0; i < break_points()->length(); i++) {
10115 if (!break_points()->get(i)->IsUndefined()) {
10116 BreakPointInfo* break_point_info =
10117 BreakPointInfo::cast(break_points()->get(i));
10118 count += break_point_info->GetBreakPointCount();
10119 }
10120 }
10121 return count;
10122}
10123
10124
10125Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
10126 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010127 Heap* heap = Isolate::Current()->heap();
10128 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010129 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10130 if (!debug_info->break_points()->get(i)->IsUndefined()) {
10131 Handle<BreakPointInfo> break_point_info =
10132 Handle<BreakPointInfo>(BreakPointInfo::cast(
10133 debug_info->break_points()->get(i)));
10134 if (BreakPointInfo::HasBreakPointObject(break_point_info,
10135 break_point_object)) {
10136 return *break_point_info;
10137 }
10138 }
10139 }
Steve Block44f0eee2011-05-26 01:26:41 +010010140 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010141}
10142
10143
10144// Find the index of the break point info object for the specified code
10145// position.
10146int DebugInfo::GetBreakPointInfoIndex(int code_position) {
10147 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
10148 for (int i = 0; i < break_points()->length(); i++) {
10149 if (!break_points()->get(i)->IsUndefined()) {
10150 BreakPointInfo* break_point_info =
10151 BreakPointInfo::cast(break_points()->get(i));
10152 if (break_point_info->code_position()->value() == code_position) {
10153 return i;
10154 }
10155 }
10156 }
10157 return kNoBreakPointInfo;
10158}
10159
10160
10161// Remove the specified break point object.
10162void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
10163 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010164 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010165 // If there are no break points just ignore.
10166 if (break_point_info->break_point_objects()->IsUndefined()) return;
10167 // If there is a single break point clear it if it is the same.
10168 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10169 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010170 break_point_info->set_break_point_objects(
10171 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010172 }
10173 return;
10174 }
10175 // If there are multiple break points shrink the array
10176 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
10177 Handle<FixedArray> old_array =
10178 Handle<FixedArray>(
10179 FixedArray::cast(break_point_info->break_point_objects()));
10180 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010181 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010182 int found_count = 0;
10183 for (int i = 0; i < old_array->length(); i++) {
10184 if (old_array->get(i) == *break_point_object) {
10185 ASSERT(found_count == 0);
10186 found_count++;
10187 } else {
10188 new_array->set(i - found_count, old_array->get(i));
10189 }
10190 }
10191 // If the break point was found in the list change it.
10192 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
10193}
10194
10195
10196// Add the specified break point object.
10197void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
10198 Handle<Object> break_point_object) {
10199 // If there was no break point objects before just set it.
10200 if (break_point_info->break_point_objects()->IsUndefined()) {
10201 break_point_info->set_break_point_objects(*break_point_object);
10202 return;
10203 }
10204 // If the break point object is the same as before just ignore.
10205 if (break_point_info->break_point_objects() == *break_point_object) return;
10206 // If there was one break point object before replace with array.
10207 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010208 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010209 array->set(0, break_point_info->break_point_objects());
10210 array->set(1, *break_point_object);
10211 break_point_info->set_break_point_objects(*array);
10212 return;
10213 }
10214 // If there was more than one break point before extend array.
10215 Handle<FixedArray> old_array =
10216 Handle<FixedArray>(
10217 FixedArray::cast(break_point_info->break_point_objects()));
10218 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010219 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010220 for (int i = 0; i < old_array->length(); i++) {
10221 // If the break point was there before just ignore.
10222 if (old_array->get(i) == *break_point_object) return;
10223 new_array->set(i, old_array->get(i));
10224 }
10225 // Add the new break point.
10226 new_array->set(old_array->length(), *break_point_object);
10227 break_point_info->set_break_point_objects(*new_array);
10228}
10229
10230
10231bool BreakPointInfo::HasBreakPointObject(
10232 Handle<BreakPointInfo> break_point_info,
10233 Handle<Object> break_point_object) {
10234 // No break point.
10235 if (break_point_info->break_point_objects()->IsUndefined()) return false;
10236 // Single beak point.
10237 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10238 return break_point_info->break_point_objects() == *break_point_object;
10239 }
10240 // Multiple break points.
10241 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
10242 for (int i = 0; i < array->length(); i++) {
10243 if (array->get(i) == *break_point_object) {
10244 return true;
10245 }
10246 }
10247 return false;
10248}
10249
10250
10251// Get the number of break points.
10252int BreakPointInfo::GetBreakPointCount() {
10253 // No break point.
10254 if (break_point_objects()->IsUndefined()) return 0;
10255 // Single beak point.
10256 if (!break_point_objects()->IsFixedArray()) return 1;
10257 // Multiple break points.
10258 return FixedArray::cast(break_point_objects())->length();
10259}
10260#endif
10261
10262
10263} } // namespace v8::internal