blob: 0660dbaa7bbad2525ef9803ee85d48a08c63e1ad [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "deoptimizer.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000036#include "elements.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037#include "execution.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "full-codegen.h"
39#include "hydrogen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040#include "objects-inl.h"
Iain Merrick75681382010-08-19 15:07:18 +010041#include "objects-visiting.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042#include "macro-assembler.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010043#include "safepoint-table.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080044#include "scanner-base.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000045#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
John Reck59135872010-11-02 12:39:01 -070062MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
63 Object* value) {
64 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010065 { MaybeObject* maybe_result =
66 constructor->GetHeap()->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -070067 if (!maybe_result->ToObject(&result)) return maybe_result;
68 }
Steve Blocka7e24c12009-10-30 11:49:00 +000069 JSValue::cast(result)->set_value(value);
70 return result;
71}
72
73
John Reck59135872010-11-02 12:39:01 -070074MaybeObject* Object::ToObject(Context* global_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +000075 if (IsNumber()) {
76 return CreateJSValue(global_context->number_function(), this);
77 } else if (IsBoolean()) {
78 return CreateJSValue(global_context->boolean_function(), this);
79 } else if (IsString()) {
80 return CreateJSValue(global_context->string_function(), this);
81 }
82 ASSERT(IsJSObject());
83 return this;
84}
85
86
John Reck59135872010-11-02 12:39:01 -070087MaybeObject* Object::ToObject() {
Steve Blocka7e24c12009-10-30 11:49:00 +000088 if (IsJSObject()) {
89 return this;
90 } else if (IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010091 Isolate* isolate = Isolate::Current();
92 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000093 return CreateJSValue(global_context->number_function(), this);
94 } else if (IsBoolean()) {
Steve Block44f0eee2011-05-26 01:26:41 +010095 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
96 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000097 return CreateJSValue(global_context->boolean_function(), this);
98 } else if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +010099 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
100 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000101 return CreateJSValue(global_context->string_function(), this);
102 }
103
104 // Throw a type error.
105 return Failure::InternalError();
106}
107
108
109Object* Object::ToBoolean() {
Steve Block44f0eee2011-05-26 01:26:41 +0100110 if (IsTrue()) return this;
111 if (IsFalse()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000112 if (IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100113 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100115 HeapObject* heap_object = HeapObject::cast(this);
116 if (heap_object->IsUndefined() || heap_object->IsNull()) {
117 return heap_object->GetHeap()->false_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100118 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000119 // Undetectable object is false
Ben Murdoch8b112d22011-06-08 16:22:53 +0100120 if (heap_object->IsUndetectableObject()) {
121 return heap_object->GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000122 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100123 if (heap_object->IsString()) {
124 return heap_object->GetHeap()->ToBoolean(
Steve Block44f0eee2011-05-26 01:26:41 +0100125 String::cast(this)->length() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000126 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100127 if (heap_object->IsHeapNumber()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 return HeapNumber::cast(this)->HeapNumberToBoolean();
129 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100130 return heap_object->GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000131}
132
133
134void Object::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 Object* holder = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100136 if (IsSmi()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000137 Context* global_context = Isolate::Current()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 holder = global_context->number_function()->instance_prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100139 } else {
140 HeapObject* heap_object = HeapObject::cast(this);
141 if (heap_object->IsJSObject()) {
142 return JSObject::cast(this)->Lookup(name, result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000143 } else if (heap_object->IsJSProxy()) {
144 return result->HandlerResult();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100145 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000146 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100147 if (heap_object->IsString()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100148 holder = global_context->string_function()->instance_prototype();
149 } else if (heap_object->IsHeapNumber()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100150 holder = global_context->number_function()->instance_prototype();
151 } else if (heap_object->IsBoolean()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100152 holder = global_context->boolean_function()->instance_prototype();
153 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 }
155 ASSERT(holder != NULL); // Cannot handle null or undefined.
156 JSObject::cast(holder)->Lookup(name, result);
157}
158
159
John Reck59135872010-11-02 12:39:01 -0700160MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
161 String* name,
162 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000163 LookupResult result;
164 Lookup(name, &result);
John Reck59135872010-11-02 12:39:01 -0700165 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000166 ASSERT(*attributes <= ABSENT);
167 return value;
168}
169
170
John Reck59135872010-11-02 12:39:01 -0700171MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
172 Object* structure,
173 String* name,
174 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +0100175 Isolate* isolate = name->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000176 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +0000177 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +0000178 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +0000179 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000180 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +0000181 reinterpret_cast<AccessorDescriptor*>(
182 Foreign::cast(structure)->address());
John Reck59135872010-11-02 12:39:01 -0700183 MaybeObject* value = (callback->getter)(receiver, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +0100184 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000185 return value;
186 }
187
188 // api style callbacks.
189 if (structure->IsAccessorInfo()) {
190 AccessorInfo* data = AccessorInfo::cast(structure);
191 Object* fun_obj = data->getter();
192 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000193 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 JSObject* self = JSObject::cast(receiver);
195 JSObject* holder_handle = JSObject::cast(holder);
196 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100197 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
198 CustomArguments args(isolate, data->data(), self, holder_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +0000199 v8::AccessorInfo info(args.end());
200 v8::Handle<v8::Value> result;
201 {
202 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +0100203 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000204 result = call_fun(v8::Utils::ToLocal(key), info);
205 }
Steve Block44f0eee2011-05-26 01:26:41 +0100206 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
207 if (result.IsEmpty()) {
208 return isolate->heap()->undefined_value();
209 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 return *v8::Utils::OpenHandle(*result);
211 }
212
213 // __defineGetter__ callback
214 if (structure->IsFixedArray()) {
215 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
216 if (getter->IsJSFunction()) {
217 return Object::GetPropertyWithDefinedGetter(receiver,
218 JSFunction::cast(getter));
219 }
220 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +0100221 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 }
223
224 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +0100225 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000226}
227
228
Ben Murdoch257744e2011-11-30 15:57:28 +0000229MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
230 String* name_raw,
231 Object* handler_raw) {
232 Isolate* isolate = name_raw->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000233 HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +0000234 Handle<Object> receiver(receiver_raw);
235 Handle<Object> name(name_raw);
236 Handle<Object> handler(handler_raw);
237
238 // Extract trap function.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000239 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
240 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
241 if (trap->IsUndefined()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000242 // Get the derived `get' property.
243 trap = isolate->derived_get_trap();
244 }
245
246 // Call trap function.
247 Object** args[] = { receiver.location(), name.location() };
248 bool has_exception;
249 Handle<Object> result =
250 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
251 if (has_exception) return Failure::Exception();
252
253 return *result;
254}
255
256
John Reck59135872010-11-02 12:39:01 -0700257MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
258 JSFunction* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 HandleScope scope;
260 Handle<JSFunction> fun(JSFunction::cast(getter));
261 Handle<Object> self(receiver);
262#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100263 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000264 // Handle stepping into a getter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +0100265 if (debug->StepInActive()) {
266 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 }
268#endif
269 bool has_pending_exception;
270 Handle<Object> result =
271 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
272 // Check for pending exception and return the result.
273 if (has_pending_exception) return Failure::Exception();
274 return *result;
275}
276
277
278// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700279MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 Object* receiver,
281 LookupResult* result,
282 String* name,
283 PropertyAttributes* attributes) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000284 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 switch (result->type()) {
286 case CALLBACKS: {
287 // Only allow API accessors.
288 Object* obj = result->GetCallbackObject();
289 if (obj->IsAccessorInfo()) {
290 AccessorInfo* info = AccessorInfo::cast(obj);
291 if (info->all_can_read()) {
292 *attributes = result->GetAttributes();
293 return GetPropertyWithCallback(receiver,
294 result->GetCallbackObject(),
295 name,
296 result->holder());
297 }
298 }
299 break;
300 }
301 case NORMAL:
302 case FIELD:
303 case CONSTANT_FUNCTION: {
304 // Search ALL_CAN_READ accessors in prototype chain.
305 LookupResult r;
306 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000307 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000308 return GetPropertyWithFailedAccessCheck(receiver,
309 &r,
310 name,
311 attributes);
312 }
313 break;
314 }
315 case INTERCEPTOR: {
316 // If the object has an interceptor, try real named properties.
317 // No access check in GetPropertyAttributeWithInterceptor.
318 LookupResult r;
319 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000320 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 return GetPropertyWithFailedAccessCheck(receiver,
322 &r,
323 name,
324 attributes);
325 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 break;
327 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000328 default:
329 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 }
331 }
332
333 // No accessible property found.
334 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100335 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100336 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
337 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000338}
339
340
341PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
342 Object* receiver,
343 LookupResult* result,
344 String* name,
345 bool continue_search) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000346 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 switch (result->type()) {
348 case CALLBACKS: {
349 // Only allow API accessors.
350 Object* obj = result->GetCallbackObject();
351 if (obj->IsAccessorInfo()) {
352 AccessorInfo* info = AccessorInfo::cast(obj);
353 if (info->all_can_read()) {
354 return result->GetAttributes();
355 }
356 }
357 break;
358 }
359
360 case NORMAL:
361 case FIELD:
362 case CONSTANT_FUNCTION: {
363 if (!continue_search) break;
364 // Search ALL_CAN_READ accessors in prototype chain.
365 LookupResult r;
366 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000367 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 return GetPropertyAttributeWithFailedAccessCheck(receiver,
369 &r,
370 name,
371 continue_search);
372 }
373 break;
374 }
375
376 case INTERCEPTOR: {
377 // If the object has an interceptor, try real named properties.
378 // No access check in GetPropertyAttributeWithInterceptor.
379 LookupResult r;
380 if (continue_search) {
381 result->holder()->LookupRealNamedProperty(name, &r);
382 } else {
383 result->holder()->LocalLookupRealNamedProperty(name, &r);
384 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000385 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 return GetPropertyAttributeWithFailedAccessCheck(receiver,
387 &r,
388 name,
389 continue_search);
390 }
391 break;
392 }
393
Andrei Popescu402d9372010-02-26 13:31:12 +0000394 default:
395 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 }
397 }
398
Ben Murdoch8b112d22011-06-08 16:22:53 +0100399 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 return ABSENT;
401}
402
403
Steve Blocka7e24c12009-10-30 11:49:00 +0000404Object* JSObject::GetNormalizedProperty(LookupResult* result) {
405 ASSERT(!HasFastProperties());
406 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
407 if (IsGlobalObject()) {
408 value = JSGlobalPropertyCell::cast(value)->value();
409 }
410 ASSERT(!value->IsJSGlobalPropertyCell());
411 return value;
412}
413
414
415Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
416 ASSERT(!HasFastProperties());
417 if (IsGlobalObject()) {
418 JSGlobalPropertyCell* cell =
419 JSGlobalPropertyCell::cast(
420 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
421 cell->set_value(value);
422 } else {
423 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
424 }
425 return value;
426}
427
428
John Reck59135872010-11-02 12:39:01 -0700429MaybeObject* JSObject::SetNormalizedProperty(String* name,
430 Object* value,
431 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 ASSERT(!HasFastProperties());
433 int entry = property_dictionary()->FindEntry(name);
434 if (entry == StringDictionary::kNotFound) {
435 Object* store_value = value;
436 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100437 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100438 MaybeObject* maybe_store_value =
439 heap->AllocateJSGlobalPropertyCell(value);
440 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 }
John Reck59135872010-11-02 12:39:01 -0700442 Object* dict;
443 { MaybeObject* maybe_dict =
444 property_dictionary()->Add(name, store_value, details);
445 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
446 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 set_properties(StringDictionary::cast(dict));
448 return value;
449 }
450 // Preserve enumeration index.
451 details = PropertyDetails(details.attributes(),
452 details.type(),
453 property_dictionary()->DetailsAt(entry).index());
454 if (IsGlobalObject()) {
455 JSGlobalPropertyCell* cell =
456 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
457 cell->set_value(value);
458 // Please note we have to update the property details.
459 property_dictionary()->DetailsAtPut(entry, details);
460 } else {
461 property_dictionary()->SetEntry(entry, name, value, details);
462 }
463 return value;
464}
465
466
John Reck59135872010-11-02 12:39:01 -0700467MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 ASSERT(!HasFastProperties());
469 StringDictionary* dictionary = property_dictionary();
470 int entry = dictionary->FindEntry(name);
471 if (entry != StringDictionary::kNotFound) {
472 // If we have a global object set the cell to the hole.
473 if (IsGlobalObject()) {
474 PropertyDetails details = dictionary->DetailsAt(entry);
475 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100476 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 // When forced to delete global properties, we have to make a
478 // map change to invalidate any ICs that think they can load
479 // from the DontDelete cell without checking if it contains
480 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700481 Object* new_map;
482 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
483 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
484 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 set_map(Map::cast(new_map));
486 }
487 JSGlobalPropertyCell* cell =
488 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100489 cell->set_value(cell->heap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000490 dictionary->DetailsAtPut(entry, details.AsDeleted());
491 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000492 Object* deleted = dictionary->DeleteProperty(entry, mode);
493 if (deleted == GetHeap()->true_value()) {
494 FixedArray* new_properties = NULL;
495 MaybeObject* maybe_properties = dictionary->Shrink(name);
496 if (!maybe_properties->To(&new_properties)) {
497 return maybe_properties;
498 }
499 set_properties(new_properties);
500 }
501 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 }
503 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100504 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000505}
506
507
508bool JSObject::IsDirty() {
509 Object* cons_obj = map()->constructor();
510 if (!cons_obj->IsJSFunction())
511 return true;
512 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100513 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000514 return true;
515 // If the object is fully fast case and has the same map it was
516 // created with then no changes can have been made to it.
517 return map() != fun->initial_map()
518 || !HasFastElements()
519 || !HasFastProperties();
520}
521
522
John Reck59135872010-11-02 12:39:01 -0700523MaybeObject* Object::GetProperty(Object* receiver,
524 LookupResult* result,
525 String* name,
526 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 // Make sure that the top context does not change when doing
528 // callbacks or interceptor calls.
529 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100530 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000531
532 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000533 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 // objects more than once in case of interceptors, because the
535 // holder will always be the interceptor holder and the search may
536 // only continue with a current object just after the interceptor
537 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000538 // Proxy handlers do not use the proxy's prototype, so we can skip this.
539 if (!result->IsHandler()) {
540 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
541 ASSERT(this != this->GetPrototype());
542 for (Object* current = this; true; current = current->GetPrototype()) {
543 if (current->IsAccessCheckNeeded()) {
544 // Check if we're allowed to read from the current object. Note
545 // that even though we may not actually end up loading the named
546 // property from the current object, we still check that we have
547 // access to it.
548 JSObject* checked = JSObject::cast(current);
549 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
550 return checked->GetPropertyWithFailedAccessCheck(receiver,
551 result,
552 name,
553 attributes);
554 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000556 // Stop traversing the chain once we reach the last object in the
557 // chain; either the holder of the result or null in case of an
558 // absent property.
559 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000561 }
562
563 if (!result->IsProperty()) {
564 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100565 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 }
567 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 Object* value;
569 JSObject* holder = result->holder();
570 switch (result->type()) {
571 case NORMAL:
572 value = holder->GetNormalizedProperty(result);
573 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100574 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 case FIELD:
576 value = holder->FastPropertyAt(result->GetFieldIndex());
577 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100578 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000579 case CONSTANT_FUNCTION:
580 return result->GetConstantFunction();
581 case CALLBACKS:
582 return GetPropertyWithCallback(receiver,
583 result->GetCallbackObject(),
584 name,
585 holder);
Ben Murdoch257744e2011-11-30 15:57:28 +0000586 case HANDLER: {
587 JSProxy* proxy = JSProxy::cast(this);
588 return GetPropertyWithHandler(receiver, name, proxy->handler());
589 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 case INTERCEPTOR: {
591 JSObject* recvr = JSObject::cast(receiver);
592 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
593 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000594 case MAP_TRANSITION:
595 case EXTERNAL_ARRAY_TRANSITION:
596 case CONSTANT_TRANSITION:
597 case NULL_DESCRIPTOR:
598 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000600 UNREACHABLE();
601 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000602}
603
604
John Reck59135872010-11-02 12:39:01 -0700605MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000606 Heap* heap = IsSmi()
607 ? Isolate::Current()->heap()
608 : HeapObject::cast(this)->GetHeap();
609 Object* holder = this;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100610
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000611 // Iterate up the prototype chain until an element is found or the null
612 // prototype is encountered.
613 for (holder = this;
614 holder != heap->null_value();
615 holder = holder->GetPrototype()) {
616 if (holder->IsSmi()) {
617 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100618 holder = global_context->number_function()->instance_prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100619 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000620 HeapObject* heap_object = HeapObject::cast(holder);
621 if (!heap_object->IsJSObject()) {
622 Isolate* isolate = heap->isolate();
623 Context* global_context = isolate->context()->global_context();
624 if (heap_object->IsString()) {
625 holder = global_context->string_function()->instance_prototype();
626 } else if (heap_object->IsHeapNumber()) {
627 holder = global_context->number_function()->instance_prototype();
628 } else if (heap_object->IsBoolean()) {
629 holder = global_context->boolean_function()->instance_prototype();
630 } else if (heap_object->IsJSProxy()) {
631 return heap->undefined_value(); // For now...
632 } else {
633 // Undefined and null have no indexed properties.
634 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
635 return heap->undefined_value();
636 }
637 }
638 }
639
640 // Inline the case for JSObjects. Doing so significantly improves the
641 // performance of fetching elements where checking the prototype chain is
642 // necessary.
643 JSObject* js_object = JSObject::cast(holder);
644
645 // Check access rights if needed.
646 if (js_object->IsAccessCheckNeeded()) {
647 Isolate* isolate = heap->isolate();
648 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
649 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
650 return heap->undefined_value();
651 }
652 }
653
654 if (js_object->HasIndexedInterceptor()) {
655 return js_object->GetElementWithInterceptor(receiver, index);
656 }
657
658 if (js_object->elements() != heap->empty_fixed_array()) {
659 MaybeObject* result = js_object->GetElementsAccessor()->Get(
660 js_object->elements(),
661 index,
662 js_object,
663 receiver);
664 if (result != heap->the_hole_value()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100665 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100666 }
667
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000668 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000669}
670
671
672Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100673 if (IsSmi()) {
674 Heap* heap = Isolate::Current()->heap();
675 Context* context = heap->isolate()->context()->global_context();
676 return context->number_function()->instance_prototype();
677 }
678
679 HeapObject* heap_object = HeapObject::cast(this);
680
Ben Murdoch257744e2011-11-30 15:57:28 +0000681 // The object is either a number, a string, a boolean,
682 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000683 if (heap_object->IsJSReceiver()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000684 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100685 }
686 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100687 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000688
Ben Murdoch8b112d22011-06-08 16:22:53 +0100689 if (heap_object->IsHeapNumber()) {
690 return context->number_function()->instance_prototype();
691 }
692 if (heap_object->IsString()) {
693 return context->string_function()->instance_prototype();
694 }
695 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000696 return context->boolean_function()->instance_prototype();
697 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100698 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000699 }
700}
701
702
Ben Murdochb0fe1622011-05-05 13:52:32 +0100703void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000704 HeapStringAllocator allocator;
705 StringStream accumulator(&allocator);
706 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100707 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000708}
709
710
711void Object::ShortPrint(StringStream* accumulator) {
712 if (IsSmi()) {
713 Smi::cast(this)->SmiPrint(accumulator);
714 } else if (IsFailure()) {
715 Failure::cast(this)->FailurePrint(accumulator);
716 } else {
717 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
718 }
719}
720
721
Ben Murdochb0fe1622011-05-05 13:52:32 +0100722void Smi::SmiPrint(FILE* out) {
723 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000724}
725
726
727void Smi::SmiPrint(StringStream* accumulator) {
728 accumulator->Add("%d", value());
729}
730
731
732void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000733 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000734}
735
736
Ben Murdochb0fe1622011-05-05 13:52:32 +0100737void Failure::FailurePrint(FILE* out) {
738 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000739}
740
741
Steve Blocka7e24c12009-10-30 11:49:00 +0000742// Should a word be prefixed by 'a' or 'an' in order to read naturally in
743// English? Returns false for non-ASCII or words that don't start with
744// a capital letter. The a/an rule follows pronunciation in English.
745// We don't use the BBC's overcorrect "an historic occasion" though if
746// you speak a dialect you may well say "an 'istoric occasion".
747static bool AnWord(String* str) {
748 if (str->length() == 0) return false; // A nothing.
749 int c0 = str->Get(0);
750 int c1 = str->length() > 1 ? str->Get(1) : 0;
751 if (c0 == 'U') {
752 if (c1 > 'Z') {
753 return true; // An Umpire, but a UTF8String, a U.
754 }
755 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
756 return true; // An Ape, an ABCBook.
757 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
758 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
759 c0 == 'S' || c0 == 'X')) {
760 return true; // An MP3File, an M.
761 }
762 return false;
763}
764
765
John Reck59135872010-11-02 12:39:01 -0700766MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000767#ifdef DEBUG
768 // Do not attempt to flatten in debug mode when allocation is not
769 // allowed. This is to avoid an assertion failure when allocating.
770 // Flattening strings is the only case where we always allow
771 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100772 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000773#endif
774
Steve Block44f0eee2011-05-26 01:26:41 +0100775 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000776 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000777 case kConsStringTag: {
778 ConsString* cs = ConsString::cast(this);
779 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100780 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000781 }
782 // There's little point in putting the flat string in new space if the
783 // cons string is in old space. It can never get GCed until there is
784 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100785 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000786 int len = length();
787 Object* object;
788 String* result;
789 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100790 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700791 if (!maybe_object->ToObject(&object)) return maybe_object;
792 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000793 result = String::cast(object);
794 String* first = cs->first();
795 int first_length = first->length();
796 char* dest = SeqAsciiString::cast(result)->GetChars();
797 WriteToFlat(first, dest, 0, first_length);
798 String* second = cs->second();
799 WriteToFlat(second,
800 dest + first_length,
801 0,
802 len - first_length);
803 } else {
John Reck59135872010-11-02 12:39:01 -0700804 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100805 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700806 if (!maybe_object->ToObject(&object)) return maybe_object;
807 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 result = String::cast(object);
809 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
810 String* first = cs->first();
811 int first_length = first->length();
812 WriteToFlat(first, dest, 0, first_length);
813 String* second = cs->second();
814 WriteToFlat(second,
815 dest + first_length,
816 0,
817 len - first_length);
818 }
819 cs->set_first(result);
Steve Block44f0eee2011-05-26 01:26:41 +0100820 cs->set_second(heap->empty_string());
Leon Clarkef7060e22010-06-03 12:02:55 +0100821 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000822 }
823 default:
824 return this;
825 }
826}
827
828
829bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100830 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100831 // prohibited by the API.
832 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000833#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000834 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000835 // Assert that the resource and the string are equivalent.
836 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100837 ScopedVector<uc16> smart_chars(this->length());
838 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
839 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100841 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 }
843#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100844 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 int size = this->Size(); // Byte size of the original string.
846 if (size < ExternalString::kSize) {
847 // The string is too small to fit an external String in its place. This can
848 // only happen for zero length strings.
849 return false;
850 }
851 ASSERT(size >= ExternalString::kSize);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100852 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000853 bool is_symbol = this->IsSymbol();
854 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000855 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000856
857 // Morph the object to an external string by adjusting the map and
858 // reinitializing the fields.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100859 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100860 heap->external_string_with_ascii_data_map() :
861 heap->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000862 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
863 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000864 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000865 self->set_resource(resource);
866 // Additionally make the object into an external symbol if the original string
867 // was a symbol to start with.
868 if (is_symbol) {
869 self->Hash(); // Force regeneration of the hash value.
870 // Now morph this external string into a external symbol.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100871 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100872 heap->external_symbol_with_ascii_data_map() :
873 heap->external_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000874 }
875
876 // Fill the remainder of the string with dead wood.
877 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100878 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000879 return true;
880}
881
882
883bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
884#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000885 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 // Assert that the resource and the string are equivalent.
887 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100888 ScopedVector<char> smart_chars(this->length());
889 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
890 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000891 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100892 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000893 }
894#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100895 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000896 int size = this->Size(); // Byte size of the original string.
897 if (size < ExternalString::kSize) {
898 // The string is too small to fit an external String in its place. This can
899 // only happen for zero length strings.
900 return false;
901 }
902 ASSERT(size >= ExternalString::kSize);
903 bool is_symbol = this->IsSymbol();
904 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000905 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000906
907 // Morph the object to an external string by adjusting the map and
908 // reinitializing the fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100909 this->set_map(heap->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000910 ExternalAsciiString* self = ExternalAsciiString::cast(this);
911 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000912 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 self->set_resource(resource);
914 // Additionally make the object into an external symbol if the original string
915 // was a symbol to start with.
916 if (is_symbol) {
917 self->Hash(); // Force regeneration of the hash value.
918 // Now morph this external string into a external symbol.
Steve Block44f0eee2011-05-26 01:26:41 +0100919 this->set_map(heap->external_ascii_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 }
921
922 // Fill the remainder of the string with dead wood.
923 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100924 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000925 return true;
926}
927
928
929void String::StringShortPrint(StringStream* accumulator) {
930 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +0000931 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000932 accumulator->Add("<Very long string[%u]>", len);
933 return;
934 }
935
936 if (!LooksValid()) {
937 accumulator->Add("<Invalid String>");
938 return;
939 }
940
941 StringInputBuffer buf(this);
942
943 bool truncated = false;
944 if (len > kMaxShortPrintLength) {
945 len = kMaxShortPrintLength;
946 truncated = true;
947 }
948 bool ascii = true;
949 for (int i = 0; i < len; i++) {
950 int c = buf.GetNext();
951
952 if (c < 32 || c >= 127) {
953 ascii = false;
954 }
955 }
956 buf.Reset(this);
957 if (ascii) {
958 accumulator->Add("<String[%u]: ", length());
959 for (int i = 0; i < len; i++) {
960 accumulator->Put(buf.GetNext());
961 }
962 accumulator->Put('>');
963 } else {
964 // Backslash indicates that the string contains control
965 // characters and that backslashes are therefore escaped.
966 accumulator->Add("<String[%u]\\: ", length());
967 for (int i = 0; i < len; i++) {
968 int c = buf.GetNext();
969 if (c == '\n') {
970 accumulator->Add("\\n");
971 } else if (c == '\r') {
972 accumulator->Add("\\r");
973 } else if (c == '\\') {
974 accumulator->Add("\\\\");
975 } else if (c < 32 || c > 126) {
976 accumulator->Add("\\x%02x", c);
977 } else {
978 accumulator->Put(c);
979 }
980 }
981 if (truncated) {
982 accumulator->Put('.');
983 accumulator->Put('.');
984 accumulator->Put('.');
985 }
986 accumulator->Put('>');
987 }
988 return;
989}
990
991
992void JSObject::JSObjectShortPrint(StringStream* accumulator) {
993 switch (map()->instance_type()) {
994 case JS_ARRAY_TYPE: {
995 double length = JSArray::cast(this)->length()->Number();
996 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
997 break;
998 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000999 case JS_WEAK_MAP_TYPE: {
1000 int elements = JSWeakMap::cast(this)->table()->NumberOfElements();
1001 accumulator->Add("<JS WeakMap[%d]>", elements);
1002 break;
1003 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 case JS_REGEXP_TYPE: {
1005 accumulator->Add("<JS RegExp>");
1006 break;
1007 }
1008 case JS_FUNCTION_TYPE: {
1009 Object* fun_name = JSFunction::cast(this)->shared()->name();
1010 bool printed = false;
1011 if (fun_name->IsString()) {
1012 String* str = String::cast(fun_name);
1013 if (str->length() > 0) {
1014 accumulator->Add("<JS Function ");
1015 accumulator->Put(str);
1016 accumulator->Put('>');
1017 printed = true;
1018 }
1019 }
1020 if (!printed) {
1021 accumulator->Add("<JS Function>");
1022 }
1023 break;
1024 }
1025 // All other JSObjects are rather similar to each other (JSObject,
1026 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1027 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001028 Map* map_of_this = map();
1029 Heap* heap = map_of_this->heap();
1030 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001031 bool printed = false;
1032 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001033 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001034 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1035 } else {
1036 bool global_object = IsJSGlobalProxy();
1037 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001038 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001039 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1040 } else {
1041 Object* constructor_name =
1042 JSFunction::cast(constructor)->shared()->name();
1043 if (constructor_name->IsString()) {
1044 String* str = String::cast(constructor_name);
1045 if (str->length() > 0) {
1046 bool vowel = AnWord(str);
1047 accumulator->Add("<%sa%s ",
1048 global_object ? "Global Object: " : "",
1049 vowel ? "n" : "");
1050 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 printed = true;
1052 }
1053 }
1054 }
1055 }
1056 if (!printed) {
1057 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1058 }
1059 }
1060 if (IsJSValue()) {
1061 accumulator->Add(" value = ");
1062 JSValue::cast(this)->value()->ShortPrint(accumulator);
1063 }
1064 accumulator->Put('>');
1065 break;
1066 }
1067 }
1068}
1069
1070
1071void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001072 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1073 Heap* heap = GetHeap();
1074 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 accumulator->Add("!!!INVALID POINTER!!!");
1076 return;
1077 }
Steve Block44f0eee2011-05-26 01:26:41 +01001078 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001079 accumulator->Add("!!!INVALID MAP!!!");
1080 return;
1081 }
1082
1083 accumulator->Add("%p ", this);
1084
1085 if (IsString()) {
1086 String::cast(this)->StringShortPrint(accumulator);
1087 return;
1088 }
1089 if (IsJSObject()) {
1090 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1091 return;
1092 }
1093 switch (map()->instance_type()) {
1094 case MAP_TYPE:
1095 accumulator->Add("<Map>");
1096 break;
1097 case FIXED_ARRAY_TYPE:
1098 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1099 break;
1100 case BYTE_ARRAY_TYPE:
1101 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1102 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001103 case EXTERNAL_PIXEL_ARRAY_TYPE:
1104 accumulator->Add("<ExternalPixelArray[%u]>",
1105 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001106 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001107 case EXTERNAL_BYTE_ARRAY_TYPE:
1108 accumulator->Add("<ExternalByteArray[%u]>",
1109 ExternalByteArray::cast(this)->length());
1110 break;
1111 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1112 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1113 ExternalUnsignedByteArray::cast(this)->length());
1114 break;
1115 case EXTERNAL_SHORT_ARRAY_TYPE:
1116 accumulator->Add("<ExternalShortArray[%u]>",
1117 ExternalShortArray::cast(this)->length());
1118 break;
1119 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1120 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1121 ExternalUnsignedShortArray::cast(this)->length());
1122 break;
1123 case EXTERNAL_INT_ARRAY_TYPE:
1124 accumulator->Add("<ExternalIntArray[%u]>",
1125 ExternalIntArray::cast(this)->length());
1126 break;
1127 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1128 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1129 ExternalUnsignedIntArray::cast(this)->length());
1130 break;
1131 case EXTERNAL_FLOAT_ARRAY_TYPE:
1132 accumulator->Add("<ExternalFloatArray[%u]>",
1133 ExternalFloatArray::cast(this)->length());
1134 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001135 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1136 accumulator->Add("<ExternalDoubleArray[%u]>",
1137 ExternalDoubleArray::cast(this)->length());
1138 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001139 case SHARED_FUNCTION_INFO_TYPE:
1140 accumulator->Add("<SharedFunctionInfo>");
1141 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001142 case JS_MESSAGE_OBJECT_TYPE:
1143 accumulator->Add("<JSMessageObject>");
1144 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001145#define MAKE_STRUCT_CASE(NAME, Name, name) \
1146 case NAME##_TYPE: \
1147 accumulator->Put('<'); \
1148 accumulator->Add(#Name); \
1149 accumulator->Put('>'); \
1150 break;
1151 STRUCT_LIST(MAKE_STRUCT_CASE)
1152#undef MAKE_STRUCT_CASE
1153 case CODE_TYPE:
1154 accumulator->Add("<Code>");
1155 break;
1156 case ODDBALL_TYPE: {
1157 if (IsUndefined())
1158 accumulator->Add("<undefined>");
1159 else if (IsTheHole())
1160 accumulator->Add("<the hole>");
1161 else if (IsNull())
1162 accumulator->Add("<null>");
1163 else if (IsTrue())
1164 accumulator->Add("<true>");
1165 else if (IsFalse())
1166 accumulator->Add("<false>");
1167 else
1168 accumulator->Add("<Odd Oddball>");
1169 break;
1170 }
1171 case HEAP_NUMBER_TYPE:
1172 accumulator->Add("<Number: ");
1173 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1174 accumulator->Put('>');
1175 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001176 case FOREIGN_TYPE:
1177 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001178 break;
1179 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1180 accumulator->Add("Cell for ");
1181 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1182 break;
1183 default:
1184 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1185 break;
1186 }
1187}
1188
1189
Steve Blocka7e24c12009-10-30 11:49:00 +00001190void HeapObject::Iterate(ObjectVisitor* v) {
1191 // Handle header
1192 IteratePointer(v, kMapOffset);
1193 // Handle object body
1194 Map* m = map();
1195 IterateBody(m->instance_type(), SizeFromMap(m), v);
1196}
1197
1198
1199void HeapObject::IterateBody(InstanceType type, int object_size,
1200 ObjectVisitor* v) {
1201 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1202 // During GC, the map pointer field is encoded.
1203 if (type < FIRST_NONSTRING_TYPE) {
1204 switch (type & kStringRepresentationMask) {
1205 case kSeqStringTag:
1206 break;
1207 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001208 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001209 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001210 case kSlicedStringTag:
1211 SlicedString::BodyDescriptor::IterateBody(this, v);
1212 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001213 case kExternalStringTag:
1214 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1215 reinterpret_cast<ExternalAsciiString*>(this)->
1216 ExternalAsciiStringIterateBody(v);
1217 } else {
1218 reinterpret_cast<ExternalTwoByteString*>(this)->
1219 ExternalTwoByteStringIterateBody(v);
1220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 break;
1222 }
1223 return;
1224 }
1225
1226 switch (type) {
1227 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001228 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001229 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001230 case FIXED_DOUBLE_ARRAY_TYPE:
1231 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001232 case JS_OBJECT_TYPE:
1233 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1234 case JS_VALUE_TYPE:
1235 case JS_ARRAY_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001236 case JS_WEAK_MAP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 case JS_GLOBAL_PROXY_TYPE:
1239 case JS_GLOBAL_OBJECT_TYPE:
1240 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001241 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001242 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 break;
Steve Block791712a2010-08-27 10:21:07 +01001244 case JS_FUNCTION_TYPE:
1245 reinterpret_cast<JSFunction*>(this)
1246 ->JSFunctionIterateBody(object_size, v);
1247 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001248 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001249 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001250 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001251 case JS_PROXY_TYPE:
1252 JSProxy::BodyDescriptor::IterateBody(this, v);
1253 break;
1254 case FOREIGN_TYPE:
1255 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 break;
1257 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001258 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001259 break;
1260 case CODE_TYPE:
1261 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1262 break;
1263 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001264 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 break;
1266 case HEAP_NUMBER_TYPE:
1267 case FILLER_TYPE:
1268 case BYTE_ARRAY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001269 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001270 case EXTERNAL_BYTE_ARRAY_TYPE:
1271 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1272 case EXTERNAL_SHORT_ARRAY_TYPE:
1273 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1274 case EXTERNAL_INT_ARRAY_TYPE:
1275 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1276 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001277 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001278 break;
Iain Merrick75681382010-08-19 15:07:18 +01001279 case SHARED_FUNCTION_INFO_TYPE:
1280 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001281 break;
Iain Merrick75681382010-08-19 15:07:18 +01001282
Steve Blocka7e24c12009-10-30 11:49:00 +00001283#define MAKE_STRUCT_CASE(NAME, Name, name) \
1284 case NAME##_TYPE:
1285 STRUCT_LIST(MAKE_STRUCT_CASE)
1286#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001287 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001288 break;
1289 default:
1290 PrintF("Unknown type: %d\n", type);
1291 UNREACHABLE();
1292 }
1293}
1294
1295
Steve Blocka7e24c12009-10-30 11:49:00 +00001296Object* HeapNumber::HeapNumberToBoolean() {
1297 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001298#if __BYTE_ORDER == __LITTLE_ENDIAN
1299 union IeeeDoubleLittleEndianArchType u;
1300#elif __BYTE_ORDER == __BIG_ENDIAN
1301 union IeeeDoubleBigEndianArchType u;
1302#endif
1303 u.d = value();
1304 if (u.bits.exp == 2047) {
1305 // Detect NaN for IEEE double precision floating point.
1306 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001307 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001308 }
Iain Merrick75681382010-08-19 15:07:18 +01001309 if (u.bits.exp == 0) {
1310 // Detect +0, and -0 for IEEE double precision floating point.
1311 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001312 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001313 }
Steve Block44f0eee2011-05-26 01:26:41 +01001314 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001315}
1316
1317
Ben Murdochb0fe1622011-05-05 13:52:32 +01001318void HeapNumber::HeapNumberPrint(FILE* out) {
1319 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001320}
1321
1322
1323void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1324 // The Windows version of vsnprintf can allocate when printing a %g string
1325 // into a buffer that may not be big enough. We don't want random memory
1326 // allocation when producing post-crash stack traces, so we print into a
1327 // buffer that is plenty big enough for any floating point number, then
1328 // print that using vsnprintf (which may truncate but never allocate if
1329 // there is no more space in the buffer).
1330 EmbeddedVector<char, 100> buffer;
1331 OS::SNPrintF(buffer, "%.16g", Number());
1332 accumulator->Add("%s", buffer.start());
1333}
1334
1335
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001336String* JSReceiver::class_name() {
1337 if (IsJSFunction() && IsJSFunctionProxy()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001338 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001339 }
1340 if (map()->constructor()->IsJSFunction()) {
1341 JSFunction* constructor = JSFunction::cast(map()->constructor());
1342 return String::cast(constructor->shared()->instance_class_name());
1343 }
1344 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001345 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001346}
1347
1348
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001349String* JSReceiver::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 if (map()->constructor()->IsJSFunction()) {
1351 JSFunction* constructor = JSFunction::cast(map()->constructor());
1352 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001353 if (name->length() > 0) return name;
1354 String* inferred_name = constructor->shared()->inferred_name();
1355 if (inferred_name->length() > 0) return inferred_name;
1356 Object* proto = GetPrototype();
1357 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001358 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001359 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001360 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001361 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001362}
1363
1364
John Reck59135872010-11-02 12:39:01 -07001365MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1366 String* name,
1367 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001368 int index = new_map->PropertyIndexFor(name);
1369 if (map()->unused_property_fields() == 0) {
1370 ASSERT(map()->unused_property_fields() == 0);
1371 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001372 Object* values;
1373 { MaybeObject* maybe_values =
1374 properties()->CopySize(properties()->length() + new_unused + 1);
1375 if (!maybe_values->ToObject(&values)) return maybe_values;
1376 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001377 set_properties(FixedArray::cast(values));
1378 }
1379 set_map(new_map);
1380 return FastPropertyAtPut(index, value);
1381}
1382
1383
Ben Murdoch8b112d22011-06-08 16:22:53 +01001384static bool IsIdentifier(UnicodeCache* cache,
1385 unibrow::CharacterStream* buffer) {
1386 // Checks whether the buffer contains an identifier (no escape).
1387 if (!buffer->has_more()) return false;
1388 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1389 return false;
1390 }
1391 while (buffer->has_more()) {
1392 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1393 return false;
1394 }
1395 }
1396 return true;
1397}
1398
1399
John Reck59135872010-11-02 12:39:01 -07001400MaybeObject* JSObject::AddFastProperty(String* name,
1401 Object* value,
1402 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001403 ASSERT(!IsJSGlobalProxy());
1404
Steve Blocka7e24c12009-10-30 11:49:00 +00001405 // Normalize the object if the name is an actual string (not the
1406 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001407 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001408 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001409 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001410 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001411 Object* obj;
1412 { MaybeObject* maybe_obj =
1413 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1414 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1415 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 return AddSlowProperty(name, value, attributes);
1417 }
1418
1419 DescriptorArray* old_descriptors = map()->instance_descriptors();
1420 // Compute the new index for new field.
1421 int index = map()->NextFreePropertyIndex();
1422
1423 // Allocate new instance descriptors with (name, index) added
1424 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001425 Object* new_descriptors;
1426 { MaybeObject* maybe_new_descriptors =
1427 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1428 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1429 return maybe_new_descriptors;
1430 }
1431 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001432
Steve Block44f0eee2011-05-26 01:26:41 +01001433 // Only allow map transition if the object isn't the global object and there
1434 // is not a transition for the name, or there's a transition for the name but
1435 // it's unrelated to properties.
1436 int descriptor_index = old_descriptors->Search(name);
1437
1438 // External array transitions are stored in the descriptor for property "",
1439 // which is not a identifier and should have forced a switch to slow
1440 // properties above.
1441 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1442 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1443 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1444 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001445 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001446 can_insert_transition &&
1447 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001448
1449 ASSERT(index < map()->inobject_properties() ||
1450 (index - map()->inobject_properties()) < properties()->length() ||
1451 map()->unused_property_fields() == 0);
1452 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001453 Object* r;
1454 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1455 if (!maybe_r->ToObject(&r)) return maybe_r;
1456 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001457 Map* new_map = Map::cast(r);
1458 if (allow_map_transition) {
1459 // Allocate new instance descriptors for the old map with map transition.
1460 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001461 Object* r;
1462 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1463 if (!maybe_r->ToObject(&r)) return maybe_r;
1464 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 old_descriptors = DescriptorArray::cast(r);
1466 }
1467
1468 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001469 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001470 Object* obj;
1471 { MaybeObject* maybe_obj =
1472 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1473 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1474 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 return AddSlowProperty(name, value, attributes);
1476 }
1477 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001478 Object* values;
1479 { MaybeObject* maybe_values =
1480 properties()->CopySize(properties()->length() + kFieldsAdded);
1481 if (!maybe_values->ToObject(&values)) return maybe_values;
1482 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001483 set_properties(FixedArray::cast(values));
1484 new_map->set_unused_property_fields(kFieldsAdded - 1);
1485 } else {
1486 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1487 }
1488 // We have now allocated all the necessary objects.
1489 // All the changes can be applied at once, so they are atomic.
1490 map()->set_instance_descriptors(old_descriptors);
1491 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1492 set_map(new_map);
1493 return FastPropertyAtPut(index, value);
1494}
1495
1496
John Reck59135872010-11-02 12:39:01 -07001497MaybeObject* JSObject::AddConstantFunctionProperty(
1498 String* name,
1499 JSFunction* function,
1500 PropertyAttributes attributes) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001501 ASSERT(!GetHeap()->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001502
Steve Blocka7e24c12009-10-30 11:49:00 +00001503 // Allocate new instance descriptors with (name, function) added
1504 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001505 Object* new_descriptors;
1506 { MaybeObject* maybe_new_descriptors =
1507 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1508 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1509 return maybe_new_descriptors;
1510 }
1511 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001512
1513 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001514 Object* new_map;
1515 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1516 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1517 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001518
1519 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1520 Map::cast(new_map)->set_instance_descriptors(descriptors);
1521 Map* old_map = map();
1522 set_map(Map::cast(new_map));
1523
1524 // If the old map is the global object map (from new Object()),
1525 // then transitions are not added to it, so we are done.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001526 Heap* heap = old_map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001527 if (old_map == heap->isolate()->context()->global_context()->
1528 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001529 return function;
1530 }
1531
1532 // Do not add CONSTANT_TRANSITIONS to global objects
1533 if (IsGlobalObject()) {
1534 return function;
1535 }
1536
1537 // Add a CONSTANT_TRANSITION descriptor to the old map,
1538 // so future assignments to this property on other objects
1539 // of the same type will create a normal field, not a constant function.
1540 // Don't do this for special properties, with non-trival attributes.
1541 if (attributes != NONE) {
1542 return function;
1543 }
Iain Merrick75681382010-08-19 15:07:18 +01001544 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001545 { MaybeObject* maybe_new_descriptors =
1546 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1547 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1548 // We have accomplished the main goal, so return success.
1549 return function;
1550 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 }
1552 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1553
1554 return function;
1555}
1556
1557
1558// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001559MaybeObject* JSObject::AddSlowProperty(String* name,
1560 Object* value,
1561 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001562 ASSERT(!HasFastProperties());
1563 StringDictionary* dict = property_dictionary();
1564 Object* store_value = value;
1565 if (IsGlobalObject()) {
1566 // In case name is an orphaned property reuse the cell.
1567 int entry = dict->FindEntry(name);
1568 if (entry != StringDictionary::kNotFound) {
1569 store_value = dict->ValueAt(entry);
1570 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1571 // Assign an enumeration index to the property and update
1572 // SetNextEnumerationIndex.
1573 int index = dict->NextEnumerationIndex();
1574 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1575 dict->SetNextEnumerationIndex(index + 1);
1576 dict->SetEntry(entry, name, store_value, details);
1577 return value;
1578 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001579 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001580 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001581 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001582 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1583 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001584 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1585 }
1586 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001587 Object* result;
1588 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1589 if (!maybe_result->ToObject(&result)) return maybe_result;
1590 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001591 if (dict != result) set_properties(StringDictionary::cast(result));
1592 return value;
1593}
1594
1595
John Reck59135872010-11-02 12:39:01 -07001596MaybeObject* JSObject::AddProperty(String* name,
1597 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001598 PropertyAttributes attributes,
1599 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001600 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001601 Map* map_of_this = map();
1602 Heap* heap = map_of_this->heap();
1603 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001604 if (strict_mode == kNonStrictMode) {
1605 return heap->undefined_value();
1606 } else {
1607 Handle<Object> args[1] = {Handle<String>(name)};
1608 return heap->isolate()->Throw(
1609 *FACTORY->NewTypeError("object_not_extensible",
1610 HandleVector(args, 1)));
1611 }
Steve Block8defd9f2010-07-08 12:39:36 +01001612 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001613 if (HasFastProperties()) {
1614 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001615 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001617 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001618 return AddConstantFunctionProperty(name,
1619 JSFunction::cast(value),
1620 attributes);
1621 } else {
1622 return AddFastProperty(name, value, attributes);
1623 }
1624 } else {
1625 // Normalize the object to prevent very large instance descriptors.
1626 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001627 Object* obj;
1628 { MaybeObject* maybe_obj =
1629 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1630 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1631 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001632 }
1633 }
1634 return AddSlowProperty(name, value, attributes);
1635}
1636
1637
John Reck59135872010-11-02 12:39:01 -07001638MaybeObject* JSObject::SetPropertyPostInterceptor(
1639 String* name,
1640 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001641 PropertyAttributes attributes,
1642 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001643 // Check local property, ignore interceptor.
1644 LookupResult result;
1645 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001646 if (result.IsFound()) {
1647 // An existing property, a map transition or a null descriptor was
1648 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001649 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001650 }
1651 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001652 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001653}
1654
1655
John Reck59135872010-11-02 12:39:01 -07001656MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1657 Object* value,
1658 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001659 StringDictionary* dictionary = property_dictionary();
1660 int old_index = dictionary->FindEntry(name);
1661 int new_enumeration_index = 0; // 0 means "Use the next available index."
1662 if (old_index != -1) {
1663 // All calls to ReplaceSlowProperty have had all transitions removed.
1664 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1665 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1666 }
1667
1668 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1669 return SetNormalizedProperty(name, value, new_details);
1670}
1671
Steve Blockd0582a62009-12-15 09:54:21 +00001672
John Reck59135872010-11-02 12:39:01 -07001673MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001674 String* name,
1675 Object* new_value,
1676 PropertyAttributes attributes) {
1677 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001678 Object* result;
1679 { MaybeObject* maybe_result =
1680 ConvertDescriptorToField(name, new_value, attributes);
1681 if (!maybe_result->ToObject(&result)) return maybe_result;
1682 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001683 // If we get to this point we have succeeded - do not return failure
1684 // after this point. Later stuff is optional.
1685 if (!HasFastProperties()) {
1686 return result;
1687 }
1688 // Do not add transitions to the map of "new Object()".
Ben Murdoch8b112d22011-06-08 16:22:53 +01001689 if (map() == old_map->heap()->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001690 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001691 return result;
1692 }
1693
1694 MapTransitionDescriptor transition(name,
1695 map(),
1696 attributes);
John Reck59135872010-11-02 12:39:01 -07001697 Object* new_descriptors;
1698 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1699 CopyInsert(&transition, KEEP_TRANSITIONS);
1700 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1701 return result; // Yes, return _result_.
1702 }
1703 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001704 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1705 return result;
1706}
1707
1708
John Reck59135872010-11-02 12:39:01 -07001709MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1710 Object* new_value,
1711 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001712 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001713 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001714 Object* obj;
1715 { MaybeObject* maybe_obj =
1716 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1717 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1718 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001719 return ReplaceSlowProperty(name, new_value, attributes);
1720 }
1721
1722 int index = map()->NextFreePropertyIndex();
1723 FieldDescriptor new_field(name, index, attributes);
1724 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001725 Object* descriptors_unchecked;
1726 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1727 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1728 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1729 return maybe_descriptors_unchecked;
1730 }
1731 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001732 DescriptorArray* new_descriptors =
1733 DescriptorArray::cast(descriptors_unchecked);
1734
1735 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001736 Object* new_map_unchecked;
1737 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1738 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1739 return maybe_new_map_unchecked;
1740 }
1741 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 Map* new_map = Map::cast(new_map_unchecked);
1743 new_map->set_instance_descriptors(new_descriptors);
1744
1745 // Make new properties array if necessary.
1746 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1747 int new_unused_property_fields = map()->unused_property_fields() - 1;
1748 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001749 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001750 Object* new_properties_object;
1751 { MaybeObject* maybe_new_properties_object =
1752 properties()->CopySize(properties()->length() + kFieldsAdded);
1753 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1754 return maybe_new_properties_object;
1755 }
1756 }
1757 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001758 }
1759
1760 // Update pointers to commit changes.
1761 // Object points to the new map.
1762 new_map->set_unused_property_fields(new_unused_property_fields);
1763 set_map(new_map);
1764 if (new_properties) {
1765 set_properties(FixedArray::cast(new_properties));
1766 }
1767 return FastPropertyAtPut(index, new_value);
1768}
1769
1770
1771
John Reck59135872010-11-02 12:39:01 -07001772MaybeObject* JSObject::SetPropertyWithInterceptor(
1773 String* name,
1774 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001775 PropertyAttributes attributes,
1776 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001777 Isolate* isolate = GetIsolate();
1778 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001779 Handle<JSObject> this_handle(this);
1780 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001781 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001782 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1783 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001784 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1785 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001786 v8::AccessorInfo info(args.end());
1787 v8::NamedPropertySetter setter =
1788 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1789 v8::Handle<v8::Value> result;
1790 {
1791 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001792 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001793 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001794 isolate->heap()->undefined_value() :
1795 value,
1796 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 result = setter(v8::Utils::ToLocal(name_handle),
1798 v8::Utils::ToLocal(value_unhole),
1799 info);
1800 }
Steve Block44f0eee2011-05-26 01:26:41 +01001801 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001802 if (!result.IsEmpty()) return *value_handle;
1803 }
John Reck59135872010-11-02 12:39:01 -07001804 MaybeObject* raw_result =
1805 this_handle->SetPropertyPostInterceptor(*name_handle,
1806 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001807 attributes,
1808 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001809 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001810 return raw_result;
1811}
1812
1813
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001814MaybeObject* JSReceiver::SetProperty(String* name,
1815 Object* value,
1816 PropertyAttributes attributes,
1817 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001818 LookupResult result;
1819 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001820 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001821}
1822
1823
John Reck59135872010-11-02 12:39:01 -07001824MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1825 String* name,
1826 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001827 JSObject* holder,
1828 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001829 Isolate* isolate = GetIsolate();
1830 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001831
1832 // We should never get here to initialize a const with the hole
1833 // value since a const declaration would conflict with the setter.
1834 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001835 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001836
1837 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00001838 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00001839 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00001840 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001841 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00001842 reinterpret_cast<AccessorDescriptor*>(
1843 Foreign::cast(structure)->address());
John Reck59135872010-11-02 12:39:01 -07001844 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001845 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001846 if (obj->IsFailure()) return obj;
1847 return *value_handle;
1848 }
1849
1850 if (structure->IsAccessorInfo()) {
1851 // api style callbacks
1852 AccessorInfo* data = AccessorInfo::cast(structure);
1853 Object* call_obj = data->setter();
1854 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1855 if (call_fun == NULL) return value;
1856 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001857 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1858 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001859 v8::AccessorInfo info(args.end());
1860 {
1861 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001862 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001863 call_fun(v8::Utils::ToLocal(key),
1864 v8::Utils::ToLocal(value_handle),
1865 info);
1866 }
Steve Block44f0eee2011-05-26 01:26:41 +01001867 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001868 return *value_handle;
1869 }
1870
1871 if (structure->IsFixedArray()) {
1872 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1873 if (setter->IsJSFunction()) {
1874 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1875 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001876 if (strict_mode == kNonStrictMode) {
1877 return value;
1878 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001879 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001880 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001881 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01001882 return isolate->Throw(
1883 *isolate->factory()->NewTypeError("no_setter_in_callback",
1884 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001885 }
1886 }
1887
1888 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01001889 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001890}
1891
1892
John Reck59135872010-11-02 12:39:01 -07001893MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1894 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01001895 Isolate* isolate = GetIsolate();
1896 Handle<Object> value_handle(value, isolate);
1897 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1898 Handle<JSObject> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001899#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01001900 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00001901 // Handle stepping into a setter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01001902 if (debug->StepInActive()) {
1903 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 }
1905#endif
1906 bool has_pending_exception;
1907 Object** argv[] = { value_handle.location() };
1908 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1909 // Check for pending exception and return the result.
1910 if (has_pending_exception) return Failure::Exception();
1911 return *value_handle;
1912}
1913
1914
1915void JSObject::LookupCallbackSetterInPrototypes(String* name,
1916 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001917 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001918 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001919 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001920 pt = pt->GetPrototype()) {
1921 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001922 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01001923 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
1924 // Found non-callback or read-only callback, stop looking.
1925 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001926 }
1927 }
1928 result->NotFound();
1929}
1930
1931
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001932MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1933 uint32_t index,
1934 Object* value,
1935 bool* found,
1936 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001937 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001938 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001939 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001940 pt = pt->GetPrototype()) {
1941 if (!JSObject::cast(pt)->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001942 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00001943 }
1944 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1945 int entry = dictionary->FindEntry(index);
1946 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001947 PropertyDetails details = dictionary->DetailsAt(entry);
1948 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001949 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001950 return SetElementWithCallback(dictionary->ValueAt(entry),
1951 index,
1952 value,
1953 JSObject::cast(pt),
1954 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001955 }
1956 }
1957 }
Steve Block1e0659c2011-05-24 12:43:12 +01001958 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001959 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001960}
1961
1962
1963void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1964 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001965 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001966 if (number != DescriptorArray::kNotFound) {
1967 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1968 } else {
1969 result->NotFound();
1970 }
1971}
1972
1973
Ben Murdochb0fe1622011-05-05 13:52:32 +01001974void Map::LookupInDescriptors(JSObject* holder,
1975 String* name,
1976 LookupResult* result) {
1977 DescriptorArray* descriptors = instance_descriptors();
Steve Block44f0eee2011-05-26 01:26:41 +01001978 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1979 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001980 if (number == DescriptorLookupCache::kAbsent) {
1981 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001982 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001983 }
1984 if (number != DescriptorArray::kNotFound) {
1985 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1986 } else {
1987 result->NotFound();
1988 }
1989}
1990
1991
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001992static JSObject::ElementsKind GetElementsKindFromExternalArrayType(
1993 ExternalArrayType array_type) {
1994 switch (array_type) {
1995 case kExternalByteArray:
1996 return JSObject::EXTERNAL_BYTE_ELEMENTS;
1997 break;
1998 case kExternalUnsignedByteArray:
1999 return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
2000 break;
2001 case kExternalShortArray:
2002 return JSObject::EXTERNAL_SHORT_ELEMENTS;
2003 break;
2004 case kExternalUnsignedShortArray:
2005 return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
2006 break;
2007 case kExternalIntArray:
2008 return JSObject::EXTERNAL_INT_ELEMENTS;
2009 break;
2010 case kExternalUnsignedIntArray:
2011 return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS;
2012 break;
2013 case kExternalFloatArray:
2014 return JSObject::EXTERNAL_FLOAT_ELEMENTS;
2015 break;
2016 case kExternalDoubleArray:
2017 return JSObject::EXTERNAL_DOUBLE_ELEMENTS;
2018 break;
2019 case kExternalPixelArray:
2020 return JSObject::EXTERNAL_PIXEL_ELEMENTS;
2021 break;
2022 }
2023 UNREACHABLE();
2024 return JSObject::DICTIONARY_ELEMENTS;
2025}
2026
2027
Steve Block44f0eee2011-05-26 01:26:41 +01002028MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
2029 bool safe_to_add_transition) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002030 Heap* current_heap = heap();
Steve Block44f0eee2011-05-26 01:26:41 +01002031 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002032 String* external_array_sentinel_name = current_heap->empty_symbol();
Steve Block44f0eee2011-05-26 01:26:41 +01002033
2034 if (safe_to_add_transition) {
2035 // It's only safe to manipulate the descriptor array if it would be
2036 // safe to add a transition.
2037
2038 ASSERT(!is_shared()); // no transitions can be added to shared maps.
2039 // Check if the external array transition already exists.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002040 DescriptorLookupCache* cache =
2041 current_heap->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01002042 int index = cache->Lookup(descriptors, external_array_sentinel_name);
2043 if (index == DescriptorLookupCache::kAbsent) {
2044 index = descriptors->Search(external_array_sentinel_name);
2045 cache->Update(descriptors,
2046 external_array_sentinel_name,
2047 index);
2048 }
2049
2050 // If the transition already exists, check the type. If there is a match,
2051 // return it.
2052 if (index != DescriptorArray::kNotFound) {
2053 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
2054 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
2055 details.array_type() == array_type) {
2056 return descriptors->GetValue(index);
2057 } else {
2058 safe_to_add_transition = false;
2059 }
2060 }
2061 }
2062
2063 // No transition to an existing external array map. Make a new one.
2064 Object* obj;
2065 { MaybeObject* maybe_map = CopyDropTransitions();
2066 if (!maybe_map->ToObject(&obj)) return maybe_map;
2067 }
2068 Map* new_map = Map::cast(obj);
2069
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002070 new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type));
Steve Block44f0eee2011-05-26 01:26:41 +01002071 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
2072
2073 // Only remember the map transition if the object's map is NOT equal to the
2074 // global object_function's map and there is not an already existing
2075 // non-matching external array transition.
2076 bool allow_map_transition =
2077 safe_to_add_transition &&
2078 (GetIsolate()->context()->global_context()->object_function()->map() !=
2079 map());
2080 if (allow_map_transition) {
2081 // Allocate new instance descriptors for the old map with map transition.
2082 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
2083 Map::cast(new_map),
2084 array_type);
2085 Object* new_descriptors;
2086 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2087 &desc,
2088 KEEP_TRANSITIONS);
2089 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2090 return maybe_new_descriptors;
2091 }
2092 descriptors = DescriptorArray::cast(new_descriptors);
2093 set_instance_descriptors(descriptors);
2094 }
2095
2096 return new_map;
2097}
2098
2099
Steve Blocka7e24c12009-10-30 11:49:00 +00002100void JSObject::LocalLookupRealNamedProperty(String* name,
2101 LookupResult* result) {
2102 if (IsJSGlobalProxy()) {
2103 Object* proto = GetPrototype();
2104 if (proto->IsNull()) return result->NotFound();
2105 ASSERT(proto->IsJSGlobalObject());
2106 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2107 }
2108
2109 if (HasFastProperties()) {
2110 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002111 if (result->IsFound()) {
2112 // A property, a map transition or a null descriptor was found.
2113 // We return all of these result types because
2114 // LocalLookupRealNamedProperty is used when setting properties
2115 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002116 ASSERT(result->holder() == this && result->type() != NORMAL);
2117 // Disallow caching for uninitialized constants. These can only
2118 // occur as fields.
2119 if (result->IsReadOnly() && result->type() == FIELD &&
2120 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2121 result->DisallowCaching();
2122 }
2123 return;
2124 }
2125 } else {
2126 int entry = property_dictionary()->FindEntry(name);
2127 if (entry != StringDictionary::kNotFound) {
2128 Object* value = property_dictionary()->ValueAt(entry);
2129 if (IsGlobalObject()) {
2130 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2131 if (d.IsDeleted()) {
2132 result->NotFound();
2133 return;
2134 }
2135 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002136 }
2137 // Make sure to disallow caching for uninitialized constants
2138 // found in the dictionary-mode objects.
2139 if (value->IsTheHole()) result->DisallowCaching();
2140 result->DictionaryResult(this, entry);
2141 return;
2142 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002143 }
2144 result->NotFound();
2145}
2146
2147
2148void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2149 LocalLookupRealNamedProperty(name, result);
2150 if (result->IsProperty()) return;
2151
2152 LookupRealNamedPropertyInPrototypes(name, result);
2153}
2154
2155
2156void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2157 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002158 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002159 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002160 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002161 pt = JSObject::cast(pt)->GetPrototype()) {
2162 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002163 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002164 }
2165 result->NotFound();
2166}
2167
2168
2169// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002170MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2171 LookupResult* result,
2172 String* name,
2173 Object* value,
2174 bool check_prototype,
2175 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002176 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002177 LookupCallbackSetterInPrototypes(name, result);
2178 }
2179
2180 if (result->IsProperty()) {
2181 if (!result->IsReadOnly()) {
2182 switch (result->type()) {
2183 case CALLBACKS: {
2184 Object* obj = result->GetCallbackObject();
2185 if (obj->IsAccessorInfo()) {
2186 AccessorInfo* info = AccessorInfo::cast(obj);
2187 if (info->all_can_write()) {
2188 return SetPropertyWithCallback(result->GetCallbackObject(),
2189 name,
2190 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002191 result->holder(),
2192 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 }
2194 }
2195 break;
2196 }
2197 case INTERCEPTOR: {
2198 // Try lookup real named properties. Note that only property can be
2199 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2200 LookupResult r;
2201 LookupRealNamedProperty(name, &r);
2202 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002203 return SetPropertyWithFailedAccessCheck(&r,
2204 name,
2205 value,
2206 check_prototype,
2207 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002208 }
2209 break;
2210 }
2211 default: {
2212 break;
2213 }
2214 }
2215 }
2216 }
2217
Ben Murdoch8b112d22011-06-08 16:22:53 +01002218 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002219 HandleScope scope(heap->isolate());
2220 Handle<Object> value_handle(value);
Steve Block44f0eee2011-05-26 01:26:41 +01002221 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002222 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002223}
2224
2225
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002226MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2227 String* key,
2228 Object* value,
2229 PropertyAttributes attributes,
2230 StrictModeFlag strict_mode) {
2231 if (result->IsFound() && result->type() == HANDLER) {
2232 return JSProxy::cast(this)->SetPropertyWithHandler(
2233 key, value, attributes, strict_mode);
2234 } else {
2235 return JSObject::cast(this)->SetPropertyForResult(
2236 result, key, value, attributes, strict_mode);
2237 }
2238}
2239
2240
2241bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2242 Isolate* isolate = GetIsolate();
2243 HandleScope scope(isolate);
2244 Handle<Object> receiver(this);
2245 Handle<Object> name(name_raw);
2246 Handle<Object> handler(this->handler());
2247
2248 // Extract trap function.
2249 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
2250 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2251 if (trap->IsUndefined()) {
2252 trap = isolate->derived_has_trap();
2253 }
2254
2255 // Call trap function.
2256 Object** args[] = { name.location() };
2257 bool has_exception;
2258 Handle<Object> result =
2259 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2260 if (has_exception) return Failure::Exception();
2261
2262 return result->ToBoolean()->IsTrue();
2263}
2264
2265
2266MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2267 String* name_raw,
2268 Object* value_raw,
2269 PropertyAttributes attributes,
2270 StrictModeFlag strict_mode) {
2271 Isolate* isolate = GetIsolate();
2272 HandleScope scope(isolate);
2273 Handle<Object> receiver(this);
2274 Handle<Object> name(name_raw);
2275 Handle<Object> value(value_raw);
2276 Handle<Object> handler(this->handler());
2277
2278 // Extract trap function.
2279 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2280 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2281 if (trap->IsUndefined()) {
2282 trap = isolate->derived_set_trap();
2283 }
2284
2285 // Call trap function.
2286 Object** args[] = {
2287 receiver.location(), name.location(), value.location()
2288 };
2289 bool has_exception;
2290 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2291 if (has_exception) return Failure::Exception();
2292
2293 return *value;
2294}
2295
2296
2297MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2298 String* name_raw, DeleteMode mode) {
2299 Isolate* isolate = GetIsolate();
2300 HandleScope scope(isolate);
2301 Handle<Object> receiver(this);
2302 Handle<Object> name(name_raw);
2303 Handle<Object> handler(this->handler());
2304
2305 // Extract trap function.
2306 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2307 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2308 if (trap->IsUndefined()) {
2309 Handle<Object> args[] = { handler, trap_name };
2310 Handle<Object> error = isolate->factory()->NewTypeError(
2311 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2312 isolate->Throw(*error);
2313 return Failure::Exception();
2314 }
2315
2316 // Call trap function.
2317 Object** args[] = { name.location() };
2318 bool has_exception;
2319 Handle<Object> result =
2320 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2321 if (has_exception) return Failure::Exception();
2322
2323 Object* bool_result = result->ToBoolean();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002324 if (mode == STRICT_DELETION &&
2325 bool_result == isolate->heap()->false_value()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002326 Handle<Object> args[] = { handler, trap_name };
2327 Handle<Object> error = isolate->factory()->NewTypeError(
2328 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2329 isolate->Throw(*error);
2330 return Failure::Exception();
2331 }
2332 return bool_result;
2333}
2334
2335
2336MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2337 JSReceiver* receiver_raw,
2338 String* name_raw,
2339 bool* has_exception) {
2340 Isolate* isolate = GetIsolate();
2341 HandleScope scope(isolate);
2342 Handle<JSReceiver> receiver(receiver_raw);
2343 Handle<Object> name(name_raw);
2344 Handle<Object> handler(this->handler());
2345
2346 // Extract trap function.
2347 Handle<String> trap_name =
2348 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2349 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2350 if (trap->IsUndefined()) {
2351 Handle<Object> args[] = { handler, trap_name };
2352 Handle<Object> error = isolate->factory()->NewTypeError(
2353 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2354 isolate->Throw(*error);
2355 *has_exception = true;
2356 return NONE;
2357 }
2358
2359 // Call trap function.
2360 Object** args[] = { name.location() };
2361 Handle<Object> result =
2362 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2363 if (has_exception) return NONE;
2364
2365 // TODO(rossberg): convert result to PropertyAttributes
2366 USE(result);
2367 return NONE;
2368}
2369
2370
2371void JSProxy::Fix() {
2372 Isolate* isolate = GetIsolate();
2373 HandleScope scope(isolate);
2374 Handle<JSProxy> self(this);
2375
2376 isolate->factory()->BecomeJSObject(self);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002377 ASSERT(self->IsJSObject());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002378 // TODO(rossberg): recognize function proxies.
2379}
2380
2381
2382
2383MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2384 String* name,
2385 Object* value,
2386 PropertyAttributes attributes,
2387 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002388 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002389 // Make sure that the top context does not change when doing callbacks or
2390 // interceptor calls.
2391 AssertNoContextChange ncc;
2392
Steve Blockd0582a62009-12-15 09:54:21 +00002393 // Optimization for 2-byte strings often used as keys in a decompression
2394 // dictionary. We make these short keys into symbols to avoid constantly
2395 // reallocating them.
2396 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002397 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002398 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002399 if (maybe_symbol_version->ToObject(&symbol_version)) {
2400 name = String::cast(symbol_version);
2401 }
2402 }
Steve Blockd0582a62009-12-15 09:54:21 +00002403 }
2404
Steve Blocka7e24c12009-10-30 11:49:00 +00002405 // Check access rights if needed.
2406 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002407 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002408 return SetPropertyWithFailedAccessCheck(result,
2409 name,
2410 value,
2411 true,
2412 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002413 }
2414
2415 if (IsJSGlobalProxy()) {
2416 Object* proto = GetPrototype();
2417 if (proto->IsNull()) return value;
2418 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002419 return JSObject::cast(proto)->SetProperty(
2420 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002421 }
2422
2423 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2424 // We could not find a local property so let's check whether there is an
2425 // accessor that wants to handle the property.
2426 LookupResult accessor_result;
2427 LookupCallbackSetterInPrototypes(name, &accessor_result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002428 if (accessor_result.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002429 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2430 name,
2431 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002432 accessor_result.holder(),
2433 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002434 }
2435 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002436 if (!result->IsFound()) {
2437 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002438 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002439 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002440 if (result->IsReadOnly() && result->IsProperty()) {
2441 if (strict_mode == kStrictMode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002442 HandleScope scope(heap->isolate());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002443 Handle<String> key(name);
2444 Handle<Object> holder(this);
2445 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002446 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2447 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002448 } else {
2449 return value;
2450 }
2451 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002452 // This is a real property that is not read-only, or it is a
2453 // transition or null descriptor and there are no setters in the prototypes.
2454 switch (result->type()) {
2455 case NORMAL:
2456 return SetNormalizedProperty(result, value);
2457 case FIELD:
2458 return FastPropertyAtPut(result->GetFieldIndex(), value);
2459 case MAP_TRANSITION:
2460 if (attributes == result->GetAttributes()) {
2461 // Only use map transition if the attributes match.
2462 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2463 name,
2464 value);
2465 }
2466 return ConvertDescriptorToField(name, value, attributes);
2467 case CONSTANT_FUNCTION:
2468 // Only replace the function if necessary.
2469 if (value == result->GetConstantFunction()) return value;
2470 // Preserve the attributes of this existing property.
2471 attributes = result->GetAttributes();
2472 return ConvertDescriptorToField(name, value, attributes);
2473 case CALLBACKS:
2474 return SetPropertyWithCallback(result->GetCallbackObject(),
2475 name,
2476 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002477 result->holder(),
2478 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002479 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002480 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002481 case CONSTANT_TRANSITION: {
2482 // If the same constant function is being added we can simply
2483 // transition to the target map.
2484 Map* target_map = result->GetTransitionMap();
2485 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2486 int number = target_descriptors->SearchWithCache(name);
2487 ASSERT(number != DescriptorArray::kNotFound);
2488 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2489 JSFunction* function =
2490 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002491 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002492 if (value == function) {
2493 set_map(target_map);
2494 return value;
2495 }
2496 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2497 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002498 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002499 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002500 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002501 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002502 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2503 default:
2504 UNREACHABLE();
2505 }
2506 UNREACHABLE();
2507 return value;
2508}
2509
2510
2511// Set a real local property, even if it is READ_ONLY. If the property is not
2512// present, add it with attributes NONE. This code is an exact clone of
2513// SetProperty, with the check for IsReadOnly and the check for a
2514// callback setter removed. The two lines looking up the LookupResult
2515// result are also added. If one of the functions is changed, the other
2516// should be.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002517// Note that this method cannot be used to set the prototype of a function
2518// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
2519// doesn't handle function prototypes correctly.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002520MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002521 String* name,
2522 Object* value,
2523 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002524
Steve Blocka7e24c12009-10-30 11:49:00 +00002525 // Make sure that the top context does not change when doing callbacks or
2526 // interceptor calls.
2527 AssertNoContextChange ncc;
Andrei Popescu402d9372010-02-26 13:31:12 +00002528 LookupResult result;
2529 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002530 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002531 if (IsAccessCheckNeeded()) {
2532 Heap* heap = GetHeap();
2533 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002534 return SetPropertyWithFailedAccessCheck(&result,
2535 name,
2536 value,
2537 false,
2538 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002539 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002540 }
2541
2542 if (IsJSGlobalProxy()) {
2543 Object* proto = GetPrototype();
2544 if (proto->IsNull()) return value;
2545 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002546 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002547 name,
2548 value,
2549 attributes);
2550 }
2551
2552 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002553 if (!result.IsFound()) {
2554 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002555 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002556 }
Steve Block6ded16b2010-05-10 14:33:55 +01002557
Andrei Popescu402d9372010-02-26 13:31:12 +00002558 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2559
Steve Blocka7e24c12009-10-30 11:49:00 +00002560 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002561 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002562 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002563 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002564 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002565 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002566 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002567 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002568 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002569 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002570 name,
2571 value);
2572 }
2573 return ConvertDescriptorToField(name, value, attributes);
2574 case CONSTANT_FUNCTION:
2575 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002576 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002577 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002578 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002579 return ConvertDescriptorToField(name, value, attributes);
2580 case CALLBACKS:
2581 case INTERCEPTOR:
2582 // Override callback in clone
2583 return ConvertDescriptorToField(name, value, attributes);
2584 case CONSTANT_TRANSITION:
2585 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2586 // if the value is a function.
2587 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2588 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002589 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002590 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2591 default:
2592 UNREACHABLE();
2593 }
2594 UNREACHABLE();
2595 return value;
2596}
2597
2598
2599PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2600 JSObject* receiver,
2601 String* name,
2602 bool continue_search) {
2603 // Check local property, ignore interceptor.
2604 LookupResult result;
2605 LocalLookupRealNamedProperty(name, &result);
2606 if (result.IsProperty()) return result.GetAttributes();
2607
2608 if (continue_search) {
2609 // Continue searching via the prototype chain.
2610 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002611 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002612 return JSObject::cast(pt)->
2613 GetPropertyAttributeWithReceiver(receiver, name);
2614 }
2615 }
2616 return ABSENT;
2617}
2618
2619
2620PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2621 JSObject* receiver,
2622 String* name,
2623 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002624 Isolate* isolate = GetIsolate();
2625
Steve Blocka7e24c12009-10-30 11:49:00 +00002626 // Make sure that the top context does not change when doing
2627 // callbacks or interceptor calls.
2628 AssertNoContextChange ncc;
2629
Steve Block44f0eee2011-05-26 01:26:41 +01002630 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002631 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2632 Handle<JSObject> receiver_handle(receiver);
2633 Handle<JSObject> holder_handle(this);
2634 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002635 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002636 v8::AccessorInfo info(args.end());
2637 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002638 v8::NamedPropertyQuery query =
2639 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002640 LOG(isolate,
2641 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002642 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002643 {
2644 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002645 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002646 result = query(v8::Utils::ToLocal(name_handle), info);
2647 }
2648 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002649 ASSERT(result->IsInt32());
2650 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002651 }
2652 } else if (!interceptor->getter()->IsUndefined()) {
2653 v8::NamedPropertyGetter getter =
2654 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002655 LOG(isolate,
2656 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002657 v8::Handle<v8::Value> result;
2658 {
2659 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002660 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002661 result = getter(v8::Utils::ToLocal(name_handle), info);
2662 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002663 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002664 }
2665 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2666 *name_handle,
2667 continue_search);
2668}
2669
2670
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002671PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2672 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00002673 String* key) {
2674 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002675 if (IsJSObject() && key->AsArrayIndex(&index)) {
2676 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2677 return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002678 return ABSENT;
2679 }
2680 // Named property.
2681 LookupResult result;
2682 Lookup(key, &result);
2683 return GetPropertyAttribute(receiver, &result, key, true);
2684}
2685
2686
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002687PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2688 LookupResult* result,
2689 String* name,
2690 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002691 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002692 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002693 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002694 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002695 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2696 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2697 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002698 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002699 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002700 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002701 switch (result->type()) {
2702 case NORMAL: // fall through
2703 case FIELD:
2704 case CONSTANT_FUNCTION:
2705 case CALLBACKS:
2706 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002707 case HANDLER: {
2708 // TODO(rossberg): propagate exceptions properly.
2709 bool has_exception = false;
2710 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2711 receiver, name, &has_exception);
2712 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002713 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002714 return result->holder()->GetPropertyAttributeWithInterceptor(
2715 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002716 default:
2717 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002718 }
2719 }
2720 return ABSENT;
2721}
2722
2723
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002724PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002725 // Check whether the name is an array index.
2726 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002727 if (IsJSObject() && name->AsArrayIndex(&index)) {
2728 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002729 return ABSENT;
2730 }
2731 // Named property.
2732 LookupResult result;
2733 LocalLookup(name, &result);
2734 return GetPropertyAttribute(this, &result, name, false);
2735}
2736
2737
John Reck59135872010-11-02 12:39:01 -07002738MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2739 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002740 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002741 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002742 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002743 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002744 if (result->IsMap() &&
2745 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002746#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002747 Map::cast(result)->SharedMapVerify();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002748 if (FLAG_enable_slow_asserts) {
2749 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002750 Object* fresh;
2751 { MaybeObject* maybe_fresh =
2752 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2753 if (maybe_fresh->ToObject(&fresh)) {
2754 ASSERT(memcmp(Map::cast(fresh)->address(),
2755 Map::cast(result)->address(),
2756 Map::kSize) == 0);
2757 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002758 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002759 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002760#endif
2761 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002762 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002763
John Reck59135872010-11-02 12:39:01 -07002764 { MaybeObject* maybe_result =
2765 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2766 if (!maybe_result->ToObject(&result)) return maybe_result;
2767 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002768 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002769 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002770
2771 return result;
2772}
2773
2774
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002775void NormalizedMapCache::Clear() {
2776 int entries = length();
2777 for (int i = 0; i != entries; i++) {
2778 set_undefined(i);
2779 }
2780}
2781
2782
John Reck59135872010-11-02 12:39:01 -07002783MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002784 if (map()->is_shared()) {
2785 // Fast case maps are never marked as shared.
2786 ASSERT(!HasFastProperties());
2787 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002788 Object* obj;
2789 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2790 UNIQUE_NORMALIZED_MAP);
2791 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2792 }
Steve Block44f0eee2011-05-26 01:26:41 +01002793 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002794
2795 set_map(Map::cast(obj));
2796 }
2797 return map()->UpdateCodeCache(name, code);
2798}
2799
2800
John Reck59135872010-11-02 12:39:01 -07002801MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2802 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002803 if (!HasFastProperties()) return this;
2804
2805 // The global object is always normalized.
2806 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002807 // JSGlobalProxy must never be normalized
2808 ASSERT(!IsJSGlobalProxy());
2809
Ben Murdoch8b112d22011-06-08 16:22:53 +01002810 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01002811
Steve Blocka7e24c12009-10-30 11:49:00 +00002812 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002813 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00002814 if (expected_additional_properties > 0) {
2815 property_count += expected_additional_properties;
2816 } else {
2817 property_count += 2; // Make space for two more properties.
2818 }
John Reck59135872010-11-02 12:39:01 -07002819 Object* obj;
2820 { MaybeObject* maybe_obj =
2821 StringDictionary::Allocate(property_count);
2822 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2823 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002824 StringDictionary* dictionary = StringDictionary::cast(obj);
2825
Ben Murdoch8b112d22011-06-08 16:22:53 +01002826 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002827 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002828 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00002829 switch (details.type()) {
2830 case CONSTANT_FUNCTION: {
2831 PropertyDetails d =
2832 PropertyDetails(details.attributes(), NORMAL, details.index());
2833 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07002834 Object* result;
2835 { MaybeObject* maybe_result =
2836 dictionary->Add(descs->GetKey(i), value, d);
2837 if (!maybe_result->ToObject(&result)) return maybe_result;
2838 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002839 dictionary = StringDictionary::cast(result);
2840 break;
2841 }
2842 case FIELD: {
2843 PropertyDetails d =
2844 PropertyDetails(details.attributes(), NORMAL, details.index());
2845 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07002846 Object* result;
2847 { MaybeObject* maybe_result =
2848 dictionary->Add(descs->GetKey(i), value, d);
2849 if (!maybe_result->ToObject(&result)) return maybe_result;
2850 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002851 dictionary = StringDictionary::cast(result);
2852 break;
2853 }
2854 case CALLBACKS: {
2855 PropertyDetails d =
2856 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2857 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07002858 Object* result;
2859 { MaybeObject* maybe_result =
2860 dictionary->Add(descs->GetKey(i), value, d);
2861 if (!maybe_result->ToObject(&result)) return maybe_result;
2862 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002863 dictionary = StringDictionary::cast(result);
2864 break;
2865 }
2866 case MAP_TRANSITION:
2867 case CONSTANT_TRANSITION:
2868 case NULL_DESCRIPTOR:
2869 case INTERCEPTOR:
Ben Murdoch257744e2011-11-30 15:57:28 +00002870 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002871 break;
2872 default:
2873 UNREACHABLE();
2874 }
2875 }
2876
Ben Murdoch8b112d22011-06-08 16:22:53 +01002877 Heap* current_heap = map_of_this->heap();
2878
Steve Blocka7e24c12009-10-30 11:49:00 +00002879 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002880 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002881 dictionary->SetNextEnumerationIndex(index);
2882
Ben Murdoch8b112d22011-06-08 16:22:53 +01002883 { MaybeObject* maybe_obj =
2884 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01002885 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07002886 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2887 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002888 Map* new_map = Map::cast(obj);
2889
Steve Blocka7e24c12009-10-30 11:49:00 +00002890 // We have now successfully allocated all the necessary objects.
2891 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002892
2893 // Resize the object in the heap if necessary.
2894 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002895 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002896 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002897 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2898 instance_size_delta);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002899
Steve Blocka7e24c12009-10-30 11:49:00 +00002900 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00002901 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002902
2903 set_properties(dictionary);
2904
Ben Murdoch8b112d22011-06-08 16:22:53 +01002905 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002906
2907#ifdef DEBUG
2908 if (FLAG_trace_normalization) {
2909 PrintF("Object properties have been normalized:\n");
2910 Print();
2911 }
2912#endif
2913 return this;
2914}
2915
2916
John Reck59135872010-11-02 12:39:01 -07002917MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002918 if (HasFastProperties()) return this;
2919 ASSERT(!IsGlobalObject());
2920 return property_dictionary()->
2921 TransformPropertiesToFastFor(this, unused_property_fields);
2922}
2923
2924
John Reck59135872010-11-02 12:39:01 -07002925MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002926 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01002927
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002928 // Find the backing store.
2929 FixedArrayBase* array = FixedArrayBase::cast(elements());
2930 Map* old_map = array->map();
2931 bool is_arguments =
2932 (old_map == old_map->heap()->non_strict_arguments_elements_map());
2933 if (is_arguments) {
2934 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07002935 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002936 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00002937
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002938 ASSERT(HasFastElements() ||
2939 HasFastDoubleElements() ||
2940 HasFastArgumentsElements());
2941 // Compute the effective length and allocate a new backing store.
2942 int length = IsJSArray()
2943 ? Smi::cast(JSArray::cast(this)->length())->value()
2944 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002945 int old_capacity = 0;
2946 int used_elements = 0;
2947 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002948 NumberDictionary* dictionary = NULL;
2949 { Object* object;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002950 MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002951 if (!maybe->ToObject(&object)) return maybe;
2952 dictionary = NumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07002953 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002954
2955 // Copy the elements to the new backing store.
2956 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00002957 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002958 Object* value = NULL;
2959 if (has_double_elements) {
2960 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
2961 if (double_array->is_the_hole(i)) {
2962 value = GetIsolate()->heap()->the_hole_value();
2963 } else {
2964 // Objects must be allocated in the old object space, since the
2965 // overall number of HeapNumbers needed for the conversion might
2966 // exceed the capacity of new space, and we would fail repeatedly
2967 // trying to convert the FixedDoubleArray.
2968 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002969 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002970 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07002971 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002972 } else {
2973 ASSERT(old_map->has_fast_elements());
2974 value = FixedArray::cast(array)->get(i);
2975 }
2976 PropertyDetails details = PropertyDetails(NONE, NORMAL);
2977 if (!value->IsTheHole()) {
2978 Object* result;
2979 MaybeObject* maybe_result =
2980 dictionary->AddNumberEntry(i, value, details);
2981 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002982 dictionary = NumberDictionary::cast(result);
2983 }
2984 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002985
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002986 // Switch to using the dictionary as the backing storage for elements.
2987 if (is_arguments) {
2988 FixedArray::cast(elements())->set(1, dictionary);
2989 } else {
2990 // Set the new map first to satify the elements type assert in
2991 // set_elements().
2992 Object* new_map;
2993 MaybeObject* maybe = map()->GetSlowElementsMap();
2994 if (!maybe->ToObject(&new_map)) return maybe;
2995 set_map(Map::cast(new_map));
2996 set_elements(dictionary);
2997 }
2998
2999 old_map->isolate()->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00003000
3001#ifdef DEBUG
3002 if (FLAG_trace_normalization) {
3003 PrintF("Object elements have been normalized:\n");
3004 Print();
3005 }
3006#endif
3007
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003008 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
3009 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00003010}
3011
3012
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003013MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
3014 Isolate* isolate = GetIsolate();
3015 Heap* heap = isolate->heap();
3016 Object* holder = BypassGlobalProxy();
3017 if (holder->IsUndefined()) return heap->undefined_value();
3018 JSObject* obj = JSObject::cast(holder);
3019 if (obj->HasFastProperties()) {
3020 // If the object has fast properties, check whether the first slot
3021 // in the descriptor array matches the hidden symbol. Since the
3022 // hidden symbols hash code is zero (and no other string has hash
3023 // code zero) it will always occupy the first entry if present.
3024 DescriptorArray* descriptors = obj->map()->instance_descriptors();
3025 if ((descriptors->number_of_descriptors() > 0) &&
3026 (descriptors->GetKey(0) == heap->hidden_symbol()) &&
3027 descriptors->IsProperty(0)) {
3028 ASSERT(descriptors->GetType(0) == FIELD);
3029 return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
3030 }
3031 }
3032
3033 // Only attempt to find the hidden properties in the local object and not
3034 // in the prototype chain.
3035 if (!obj->HasHiddenPropertiesObject()) {
3036 // Hidden properties object not found. Allocate a new hidden properties
3037 // object if requested. Otherwise return the undefined value.
3038 if (flag == ALLOW_CREATION) {
3039 Object* hidden_obj;
3040 { MaybeObject* maybe_obj = heap->AllocateJSObject(
3041 isolate->context()->global_context()->object_function());
3042 if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
3043 }
3044 // Don't allow leakage of the hidden object through accessors
3045 // on Object.prototype.
3046 {
3047 MaybeObject* maybe_obj =
3048 JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false);
3049 if (maybe_obj->IsFailure()) return maybe_obj;
3050 }
3051 return obj->SetHiddenPropertiesObject(hidden_obj);
3052 } else {
3053 return heap->undefined_value();
3054 }
3055 }
3056 return obj->GetHiddenPropertiesObject();
3057}
3058
3059
3060MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) {
3061 Isolate* isolate = GetIsolate();
3062 Object* hidden_props_obj;
3063 { MaybeObject* maybe_obj = GetHiddenProperties(flag);
3064 if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
3065 }
3066 if (!hidden_props_obj->IsJSObject()) {
3067 // We failed to create hidden properties. That's a detached
3068 // global proxy.
3069 ASSERT(hidden_props_obj->IsUndefined());
3070 return Smi::FromInt(0);
3071 }
3072 JSObject* hidden_props = JSObject::cast(hidden_props_obj);
3073 String* hash_symbol = isolate->heap()->identity_hash_symbol();
3074 {
3075 // Note that HasLocalProperty() can cause a GC in the general case in the
3076 // presence of interceptors.
3077 AssertNoAllocation no_alloc;
3078 if (hidden_props->HasLocalProperty(hash_symbol)) {
3079 MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
3080 return Smi::cast(hash->ToObjectChecked());
3081 }
3082 }
3083
3084 int hash_value;
3085 int attempts = 0;
3086 do {
3087 // Generate a random 32-bit hash value but limit range to fit
3088 // within a smi.
3089 hash_value = V8::Random(isolate) & Smi::kMaxValue;
3090 attempts++;
3091 } while (hash_value == 0 && attempts < 30);
3092 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3093
3094 Smi* hash = Smi::FromInt(hash_value);
3095 { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
3096 hash_symbol,
3097 hash,
3098 static_cast<PropertyAttributes>(None));
3099 if (result->IsFailure()) return result;
3100 }
3101 return hash;
3102}
3103
3104
John Reck59135872010-11-02 12:39:01 -07003105MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3106 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003107 // Check local property, ignore interceptor.
3108 LookupResult result;
3109 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003110 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003111
3112 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003113 Object* obj;
3114 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3115 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3116 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003117
3118 return DeleteNormalizedProperty(name, mode);
3119}
3120
3121
John Reck59135872010-11-02 12:39:01 -07003122MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01003123 Isolate* isolate = GetIsolate();
3124 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003125 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3126 Handle<String> name_handle(name);
3127 Handle<JSObject> this_handle(this);
3128 if (!interceptor->deleter()->IsUndefined()) {
3129 v8::NamedPropertyDeleter deleter =
3130 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01003131 LOG(isolate,
3132 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3133 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003134 v8::AccessorInfo info(args.end());
3135 v8::Handle<v8::Boolean> result;
3136 {
3137 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003138 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003139 result = deleter(v8::Utils::ToLocal(name_handle), info);
3140 }
Steve Block44f0eee2011-05-26 01:26:41 +01003141 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003142 if (!result.IsEmpty()) {
3143 ASSERT(result->IsBoolean());
3144 return *v8::Utils::OpenHandle(*result);
3145 }
3146 }
John Reck59135872010-11-02 12:39:01 -07003147 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003148 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003149 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003150 return raw_result;
3151}
3152
3153
John Reck59135872010-11-02 12:39:01 -07003154MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003155 Isolate* isolate = GetIsolate();
3156 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003157 // Make sure that the top context does not change when doing
3158 // callbacks or interceptor calls.
3159 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003160 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003161 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003162 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003163 v8::IndexedPropertyDeleter deleter =
3164 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3165 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003166 LOG(isolate,
3167 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3168 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003169 v8::AccessorInfo info(args.end());
3170 v8::Handle<v8::Boolean> result;
3171 {
3172 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003173 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003174 result = deleter(index, info);
3175 }
Steve Block44f0eee2011-05-26 01:26:41 +01003176 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003177 if (!result.IsEmpty()) {
3178 ASSERT(result->IsBoolean());
3179 return *v8::Utils::OpenHandle(*result);
3180 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003181 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3182 *this_handle,
3183 index,
3184 NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003185 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003186 return raw_result;
3187}
3188
3189
John Reck59135872010-11-02 12:39:01 -07003190MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003191 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003192 // Check access rights if needed.
3193 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003194 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3195 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3196 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003197 }
3198
3199 if (IsJSGlobalProxy()) {
3200 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003201 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003202 ASSERT(proto->IsJSGlobalObject());
3203 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3204 }
3205
3206 if (HasIndexedInterceptor()) {
3207 // Skip interceptor if forcing deletion.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003208 if (mode != FORCE_DELETION) {
3209 return DeleteElementWithInterceptor(index);
3210 }
3211 mode = JSReceiver::FORCE_DELETION;
Steve Blocka7e24c12009-10-30 11:49:00 +00003212 }
3213
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003214 return GetElementsAccessor()->Delete(this, index, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003215}
3216
3217
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003218MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3219 if (IsJSProxy()) {
3220 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3221 } else {
3222 return JSObject::cast(this)->DeleteProperty(name, mode);
3223 }
3224}
3225
3226
John Reck59135872010-11-02 12:39:01 -07003227MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003228 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003229 // ECMA-262, 3rd, 8.6.2.5
3230 ASSERT(name->IsString());
3231
3232 // Check access rights if needed.
3233 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003234 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3235 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3236 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003237 }
3238
3239 if (IsJSGlobalProxy()) {
3240 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003241 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003242 ASSERT(proto->IsJSGlobalObject());
3243 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3244 }
3245
3246 uint32_t index = 0;
3247 if (name->AsArrayIndex(&index)) {
3248 return DeleteElement(index, mode);
3249 } else {
3250 LookupResult result;
3251 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003252 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003253 // Ignore attributes if forcing a deletion.
3254 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003255 if (mode == STRICT_DELETION) {
3256 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003257 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003258 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003259 return isolate->Throw(*isolate->factory()->NewTypeError(
3260 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003261 }
Steve Block44f0eee2011-05-26 01:26:41 +01003262 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003263 }
3264 // Check for interceptor.
3265 if (result.type() == INTERCEPTOR) {
3266 // Skip interceptor if forcing a deletion.
3267 if (mode == FORCE_DELETION) {
3268 return DeletePropertyPostInterceptor(name, mode);
3269 }
3270 return DeletePropertyWithInterceptor(name);
3271 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003272 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003273 Object* obj;
3274 { MaybeObject* maybe_obj =
3275 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3276 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3277 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003278 // Make sure the properties are normalized before removing the entry.
3279 return DeleteNormalizedProperty(name, mode);
3280 }
3281}
3282
3283
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003284bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3285 ElementsKind kind,
3286 Object* object) {
3287 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
3288 if (kind == FAST_ELEMENTS) {
3289 int length = IsJSArray()
3290 ? Smi::cast(JSArray::cast(this)->length())->value()
3291 : elements->length();
3292 for (int i = 0; i < length; ++i) {
3293 Object* element = elements->get(i);
3294 if (!element->IsTheHole() && element == object) return true;
3295 }
3296 } else {
3297 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
3298 if (!key->IsUndefined()) return true;
3299 }
3300 return false;
3301}
3302
3303
Steve Blocka7e24c12009-10-30 11:49:00 +00003304// Check whether this object references another object.
3305bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003306 Map* map_of_this = map();
3307 Heap* heap = map_of_this->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003308 AssertNoAllocation no_alloc;
3309
3310 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003311 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003312 return true;
3313 }
3314
3315 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003316 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003317 return true;
3318 }
3319
3320 // Check if the object is among the named properties.
3321 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003322 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003323 return true;
3324 }
3325
3326 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003327 ElementsKind kind = GetElementsKind();
3328 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01003329 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003330 case EXTERNAL_BYTE_ELEMENTS:
3331 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3332 case EXTERNAL_SHORT_ELEMENTS:
3333 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3334 case EXTERNAL_INT_ELEMENTS:
3335 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3336 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003337 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003338 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003339 // Raw pixels and external arrays do not reference other
3340 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00003341 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003342 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00003343 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003344 FixedArray* elements = FixedArray::cast(this->elements());
3345 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003346 break;
3347 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003348 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3349 FixedArray* parameter_map = FixedArray::cast(elements());
3350 // Check the mapped parameters.
3351 int length = parameter_map->length();
3352 for (int i = 2; i < length; ++i) {
3353 Object* value = parameter_map->get(i);
3354 if (!value->IsTheHole() && value == obj) return true;
3355 }
3356 // Check the arguments.
3357 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3358 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
3359 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003360 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003361 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003362 }
3363
Steve Block6ded16b2010-05-10 14:33:55 +01003364 // For functions check the context.
3365 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003366 // Get the constructor function for arguments array.
3367 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01003368 heap->isolate()->context()->global_context()->
3369 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003370 JSFunction* arguments_function =
3371 JSFunction::cast(arguments_boilerplate->map()->constructor());
3372
3373 // Get the context and don't check if it is the global context.
3374 JSFunction* f = JSFunction::cast(this);
3375 Context* context = f->context();
3376 if (context->IsGlobalContext()) {
3377 return false;
3378 }
3379
3380 // Check the non-special context slots.
3381 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3382 // Only check JS objects.
3383 if (context->get(i)->IsJSObject()) {
3384 JSObject* ctxobj = JSObject::cast(context->get(i));
3385 // If it is an arguments array check the content.
3386 if (ctxobj->map()->constructor() == arguments_function) {
3387 if (ctxobj->ReferencesObject(obj)) {
3388 return true;
3389 }
3390 } else if (ctxobj == obj) {
3391 return true;
3392 }
3393 }
3394 }
3395
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003396 // Check the context extension (if any) if it can have references.
3397 if (context->has_extension() && !context->IsCatchContext()) {
3398 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00003399 }
3400 }
3401
3402 // No references to object.
3403 return false;
3404}
3405
3406
John Reck59135872010-11-02 12:39:01 -07003407MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01003408 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003409 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003410 !isolate->MayNamedAccess(this,
3411 isolate->heap()->undefined_value(),
3412 v8::ACCESS_KEYS)) {
3413 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3414 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003415 }
3416
Steve Block1e0659c2011-05-24 12:43:12 +01003417 if (IsJSGlobalProxy()) {
3418 Object* proto = GetPrototype();
3419 if (proto->IsNull()) return this;
3420 ASSERT(proto->IsJSGlobalObject());
3421 return JSObject::cast(proto)->PreventExtensions();
3422 }
3423
Ben Murdoch257744e2011-11-30 15:57:28 +00003424 // It's not possible to seal objects with external array elements
3425 if (HasExternalArrayElements()) {
3426 HandleScope scope(isolate);
3427 Handle<Object> object(this);
3428 Handle<Object> error =
3429 isolate->factory()->NewTypeError(
3430 "cant_prevent_ext_external_array_elements",
3431 HandleVector(&object, 1));
3432 return isolate->Throw(*error);
3433 }
3434
Steve Block8defd9f2010-07-08 12:39:36 +01003435 // If there are fast elements we normalize.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003436 NumberDictionary* dictionary = NULL;
3437 { MaybeObject* maybe = NormalizeElements();
3438 if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01003439 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003440 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003441 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003442 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01003443
3444 // Do a map transition, other objects with this map may still
3445 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003446 Map* new_map;
3447 { MaybeObject* maybe = map()->CopyDropTransitions();
3448 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07003449 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003450 new_map->set_is_extensible(false);
3451 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01003452 ASSERT(!map()->is_extensible());
3453 return new_map;
3454}
3455
3456
Steve Blocka7e24c12009-10-30 11:49:00 +00003457// Tests for the fast common case for property enumeration:
Steve Blockd0582a62009-12-15 09:54:21 +00003458// - This object and all prototypes has an enum cache (which means that it has
3459// no interceptors and needs no access checks).
3460// - This object has no elements.
3461// - No prototype has enumerable properties/elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00003462bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003463 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003464 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003465 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003466 o = JSObject::cast(o)->GetPrototype()) {
3467 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003468 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003469 ASSERT(!curr->HasNamedInterceptor());
3470 ASSERT(!curr->HasIndexedInterceptor());
3471 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003472 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003473 if (curr != this) {
3474 FixedArray* curr_fixed_array =
3475 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003476 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003477 }
3478 }
3479 return true;
3480}
3481
3482
3483int Map::NumberOfDescribedProperties() {
3484 int result = 0;
3485 DescriptorArray* descs = instance_descriptors();
3486 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3487 if (descs->IsProperty(i)) result++;
3488 }
3489 return result;
3490}
3491
3492
3493int Map::PropertyIndexFor(String* name) {
3494 DescriptorArray* descs = instance_descriptors();
3495 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3496 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3497 return descs->GetFieldIndex(i);
3498 }
3499 }
3500 return -1;
3501}
3502
3503
3504int Map::NextFreePropertyIndex() {
3505 int max_index = -1;
3506 DescriptorArray* descs = instance_descriptors();
3507 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3508 if (descs->GetType(i) == FIELD) {
3509 int current_index = descs->GetFieldIndex(i);
3510 if (current_index > max_index) max_index = current_index;
3511 }
3512 }
3513 return max_index + 1;
3514}
3515
3516
3517AccessorDescriptor* Map::FindAccessor(String* name) {
3518 DescriptorArray* descs = instance_descriptors();
3519 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3520 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3521 return descs->GetCallbacks(i);
3522 }
3523 }
3524 return NULL;
3525}
3526
3527
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003528void JSReceiver::LocalLookup(String* name, LookupResult* result) {
3529 if (IsJSProxy()) {
3530 result->HandlerResult();
3531 } else {
3532 JSObject::cast(this)->LocalLookup(name, result);
3533 }
3534}
3535
3536
Steve Blocka7e24c12009-10-30 11:49:00 +00003537void JSObject::LocalLookup(String* name, LookupResult* result) {
3538 ASSERT(name->IsString());
3539
Steve Block44f0eee2011-05-26 01:26:41 +01003540 Heap* heap = GetHeap();
3541
Steve Blocka7e24c12009-10-30 11:49:00 +00003542 if (IsJSGlobalProxy()) {
3543 Object* proto = GetPrototype();
3544 if (proto->IsNull()) return result->NotFound();
3545 ASSERT(proto->IsJSGlobalObject());
3546 return JSObject::cast(proto)->LocalLookup(name, result);
3547 }
3548
3549 // Do not use inline caching if the object is a non-global object
3550 // that requires access checks.
3551 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
3552 result->DisallowCaching();
3553 }
3554
3555 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003556 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003557 result->ConstantResult(this);
3558 return;
3559 }
3560
3561 // Check for lookup interceptor except when bootstrapping.
Steve Block44f0eee2011-05-26 01:26:41 +01003562 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003563 result->InterceptorResult(this);
3564 return;
3565 }
3566
3567 LocalLookupRealNamedProperty(name, result);
3568}
3569
3570
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003571void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003572 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003573 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003574 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003575 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003576 current = JSObject::cast(current)->GetPrototype()) {
3577 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003578 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003579 }
3580 result->NotFound();
3581}
3582
3583
3584// Search object and it's prototype chain for callback properties.
3585void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003586 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003587 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003588 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003589 current = JSObject::cast(current)->GetPrototype()) {
3590 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003591 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003592 }
3593 result->NotFound();
3594}
3595
3596
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003597// Search for a getter or setter in an elements dictionary. Returns either
3598// undefined if the element is read-only, or the getter/setter pair (fixed
3599// array) if there is an existing one, or the hole value if the element does
3600// not exist or is a normal non-getter/setter data element.
3601static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary,
3602 uint32_t index,
3603 Heap* heap) {
3604 int entry = dictionary->FindEntry(index);
3605 if (entry != NumberDictionary::kNotFound) {
3606 Object* result = dictionary->ValueAt(entry);
3607 PropertyDetails details = dictionary->DetailsAt(entry);
3608 if (details.IsReadOnly()) return heap->undefined_value();
3609 if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
3610 }
3611 return heap->the_hole_value();
3612}
3613
3614
John Reck59135872010-11-02 12:39:01 -07003615MaybeObject* JSObject::DefineGetterSetter(String* name,
3616 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003617 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003618 // Make sure that the top context does not change when doing callbacks or
3619 // interceptor calls.
3620 AssertNoContextChange ncc;
3621
Steve Blocka7e24c12009-10-30 11:49:00 +00003622 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01003623 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003624
Leon Clarkef7060e22010-06-03 12:02:55 +01003625 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003626 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003627 }
3628
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003629 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003630 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003631
3632 if (is_element) {
3633 switch (GetElementsKind()) {
3634 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003635 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00003636 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003637 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003638 case EXTERNAL_BYTE_ELEMENTS:
3639 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3640 case EXTERNAL_SHORT_ELEMENTS:
3641 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3642 case EXTERNAL_INT_ELEMENTS:
3643 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3644 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003645 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003646 // Ignore getters and setters on pixel and external array
3647 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003648 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003649 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003650 Object* probe =
3651 FindGetterSetterInDictionary(element_dictionary(), index, heap);
3652 if (!probe->IsTheHole()) return probe;
3653 // Otherwise allow to override it.
3654 break;
3655 }
3656 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3657 // Ascertain whether we have read-only properties or an existing
3658 // getter/setter pair in an arguments elements dictionary backing
3659 // store.
3660 FixedArray* parameter_map = FixedArray::cast(elements());
3661 uint32_t length = parameter_map->length();
3662 Object* probe =
3663 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
3664 if (probe == NULL || probe->IsTheHole()) {
3665 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3666 if (arguments->IsDictionary()) {
3667 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
3668 probe = FindGetterSetterInDictionary(dictionary, index, heap);
3669 if (!probe->IsTheHole()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00003670 }
3671 }
3672 break;
3673 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003674 }
3675 } else {
3676 // Lookup the name.
3677 LookupResult result;
3678 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003679 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003680 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003681 if (result.type() == CALLBACKS) {
3682 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01003683 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00003684 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003685 // Use set to update attributes.
3686 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003687 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003688 }
3689 }
3690 }
3691
3692 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07003693 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01003694 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07003695 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3696 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003697
3698 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003699 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003700 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003701 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003702 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003703}
3704
3705
3706bool JSObject::CanSetCallback(String* name) {
3707 ASSERT(!IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01003708 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003709
3710 // Check if there is an API defined callback object which prohibits
3711 // callback overwriting in this object or it's prototype chain.
3712 // This mechanism is needed for instance in a browser setting, where
3713 // certain accessors such as window.location should not be allowed
3714 // to be overwritten because allowing overwriting could potentially
3715 // cause security problems.
3716 LookupResult callback_result;
3717 LookupCallback(name, &callback_result);
3718 if (callback_result.IsProperty()) {
3719 Object* obj = callback_result.GetCallbackObject();
3720 if (obj->IsAccessorInfo() &&
3721 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3722 return false;
3723 }
3724 }
3725
3726 return true;
3727}
3728
3729
John Reck59135872010-11-02 12:39:01 -07003730MaybeObject* JSObject::SetElementCallback(uint32_t index,
3731 Object* structure,
3732 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003733 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3734
3735 // Normalize elements to make this operation simple.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003736 NumberDictionary* dictionary = NULL;
3737 { Object* result;
3738 MaybeObject* maybe = NormalizeElements();
3739 if (!maybe->ToObject(&result)) return maybe;
3740 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003741 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003742 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01003743
3744 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003745 { Object* result;
3746 MaybeObject* maybe = dictionary->Set(index, structure, details);
3747 if (!maybe->ToObject(&result)) return maybe;
3748 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003749 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003750
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003751 dictionary->set_requires_slow_elements();
3752 // Update the dictionary backing store on the object.
3753 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
3754 // Also delete any parameter alias.
3755 //
3756 // TODO(kmillikin): when deleting the last parameter alias we could
3757 // switch to a direct backing store without the parameter map. This
3758 // would allow GC of the context.
3759 FixedArray* parameter_map = FixedArray::cast(elements());
3760 uint32_t length = parameter_map->length();
3761 if (index < length - 2) {
3762 parameter_map->set(index + 2, GetHeap()->the_hole_value());
3763 }
3764 parameter_map->set(1, dictionary);
3765 } else {
3766 set_elements(dictionary);
3767 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003768
3769 return structure;
3770}
3771
3772
John Reck59135872010-11-02 12:39:01 -07003773MaybeObject* JSObject::SetPropertyCallback(String* name,
3774 Object* structure,
3775 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003776 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3777
3778 bool convert_back_to_fast = HasFastProperties() &&
3779 (map()->instance_descriptors()->number_of_descriptors()
3780 < DescriptorArray::kMaxNumberOfDescriptors);
3781
3782 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003783 Object* ok;
3784 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3785 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3786 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003787
3788 // For the global object allocate a new map to invalidate the global inline
3789 // caches which have a global property cell reference directly in the code.
3790 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07003791 Object* new_map;
3792 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3793 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3794 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003795 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003796 // When running crankshaft, changing the map is not enough. We
3797 // need to deoptimize all functions that rely on this global
3798 // object.
3799 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003800 }
3801
3802 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003803 Object* result;
3804 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3805 if (!maybe_result->ToObject(&result)) return maybe_result;
3806 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003807
3808 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07003809 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3810 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3811 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003812 }
3813 return result;
3814}
3815
John Reck59135872010-11-02 12:39:01 -07003816MaybeObject* JSObject::DefineAccessor(String* name,
3817 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01003818 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003819 PropertyAttributes attributes) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003820 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003821 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003822 // Check access rights if needed.
3823 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003824 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3825 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3826 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003827 }
3828
3829 if (IsJSGlobalProxy()) {
3830 Object* proto = GetPrototype();
3831 if (proto->IsNull()) return this;
3832 ASSERT(proto->IsJSGlobalObject());
3833 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3834 fun, attributes);
3835 }
3836
John Reck59135872010-11-02 12:39:01 -07003837 Object* array;
3838 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3839 if (!maybe_array->ToObject(&array)) return maybe_array;
3840 }
3841 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003842 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3843 return this;
3844}
3845
3846
John Reck59135872010-11-02 12:39:01 -07003847MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003848 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003849 String* name = String::cast(info->name());
3850 // Check access rights if needed.
3851 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003852 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3853 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3854 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003855 }
3856
3857 if (IsJSGlobalProxy()) {
3858 Object* proto = GetPrototype();
3859 if (proto->IsNull()) return this;
3860 ASSERT(proto->IsJSGlobalObject());
3861 return JSObject::cast(proto)->DefineAccessor(info);
3862 }
3863
3864 // Make sure that the top context does not change when doing callbacks or
3865 // interceptor calls.
3866 AssertNoContextChange ncc;
3867
3868 // Try to flatten before operating on the string.
3869 name->TryFlatten();
3870
3871 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003872 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003873 }
3874
3875 uint32_t index = 0;
3876 bool is_element = name->AsArrayIndex(&index);
3877
3878 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003879 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003880
3881 // Accessors overwrite previous callbacks (cf. with getters/setters).
3882 switch (GetElementsKind()) {
3883 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003884 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003885 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003886 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003887 case EXTERNAL_BYTE_ELEMENTS:
3888 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3889 case EXTERNAL_SHORT_ELEMENTS:
3890 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3891 case EXTERNAL_INT_ELEMENTS:
3892 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3893 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003894 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003895 // Ignore getters and setters on pixel and external array
3896 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003897 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003898 case DICTIONARY_ELEMENTS:
3899 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003900 case NON_STRICT_ARGUMENTS_ELEMENTS:
3901 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01003902 break;
3903 }
3904
John Reck59135872010-11-02 12:39:01 -07003905 Object* ok;
3906 { MaybeObject* maybe_ok =
3907 SetElementCallback(index, info, info->property_attributes());
3908 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3909 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003910 } else {
3911 // Lookup the name.
3912 LookupResult result;
3913 LocalLookup(name, &result);
3914 // ES5 forbids turning a property into an accessor if it's not
3915 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3916 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003917 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003918 }
John Reck59135872010-11-02 12:39:01 -07003919 Object* ok;
3920 { MaybeObject* maybe_ok =
3921 SetPropertyCallback(name, info, info->property_attributes());
3922 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3923 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003924 }
3925
3926 return this;
3927}
3928
3929
Steve Blocka7e24c12009-10-30 11:49:00 +00003930Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003931 Heap* heap = GetHeap();
3932
Steve Blocka7e24c12009-10-30 11:49:00 +00003933 // Make sure that the top context does not change when doing callbacks or
3934 // interceptor calls.
3935 AssertNoContextChange ncc;
3936
3937 // Check access rights if needed.
3938 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003939 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3940 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3941 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003942 }
3943
3944 // Make the lookup and include prototypes.
3945 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003946 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003947 if (name->AsArrayIndex(&index)) {
3948 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003949 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003950 obj = JSObject::cast(obj)->GetPrototype()) {
3951 JSObject* js_object = JSObject::cast(obj);
3952 if (js_object->HasDictionaryElements()) {
3953 NumberDictionary* dictionary = js_object->element_dictionary();
3954 int entry = dictionary->FindEntry(index);
3955 if (entry != NumberDictionary::kNotFound) {
3956 Object* element = dictionary->ValueAt(entry);
3957 PropertyDetails details = dictionary->DetailsAt(entry);
3958 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003959 if (element->IsFixedArray()) {
3960 return FixedArray::cast(element)->get(accessor_index);
3961 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003962 }
3963 }
3964 }
3965 }
3966 } else {
3967 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003968 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003969 obj = JSObject::cast(obj)->GetPrototype()) {
3970 LookupResult result;
3971 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003972 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003973 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003974 if (result.type() == CALLBACKS) {
3975 Object* obj = result.GetCallbackObject();
3976 if (obj->IsFixedArray()) {
3977 return FixedArray::cast(obj)->get(accessor_index);
3978 }
3979 }
3980 }
3981 }
3982 }
Steve Block44f0eee2011-05-26 01:26:41 +01003983 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003984}
3985
3986
3987Object* JSObject::SlowReverseLookup(Object* value) {
3988 if (HasFastProperties()) {
3989 DescriptorArray* descs = map()->instance_descriptors();
3990 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3991 if (descs->GetType(i) == FIELD) {
3992 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3993 return descs->GetKey(i);
3994 }
3995 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3996 if (descs->GetConstantFunction(i) == value) {
3997 return descs->GetKey(i);
3998 }
3999 }
4000 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004001 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004002 } else {
4003 return property_dictionary()->SlowReverseLookup(value);
4004 }
4005}
4006
4007
John Reck59135872010-11-02 12:39:01 -07004008MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01004009 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07004010 Object* result;
4011 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004012 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07004013 if (!maybe_result->ToObject(&result)) return maybe_result;
4014 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004015 Map::cast(result)->set_prototype(prototype());
4016 Map::cast(result)->set_constructor(constructor());
4017 // Don't copy descriptors, so map transitions always remain a forest.
4018 // If we retained the same descriptors we would have two maps
4019 // pointing to the same transition which is bad because the garbage
4020 // collector relies on being able to reverse pointers from transitions
4021 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004022 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004023 // Please note instance_type and instance_size are set when allocated.
4024 Map::cast(result)->set_inobject_properties(inobject_properties());
4025 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4026
4027 // If the map has pre-allocated properties always start out with a descriptor
4028 // array describing these properties.
4029 if (pre_allocated_property_fields() > 0) {
4030 ASSERT(constructor()->IsJSFunction());
4031 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004032 Object* descriptors;
4033 { MaybeObject* maybe_descriptors =
4034 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4035 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4036 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004037 Map::cast(result)->set_instance_descriptors(
4038 DescriptorArray::cast(descriptors));
4039 Map::cast(result)->set_pre_allocated_property_fields(
4040 pre_allocated_property_fields());
4041 }
4042 Map::cast(result)->set_bit_field(bit_field());
4043 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004044 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004045 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004046 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004047 return result;
4048}
4049
4050
John Reck59135872010-11-02 12:39:01 -07004051MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4052 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004053 int new_instance_size = instance_size();
4054 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4055 new_instance_size -= inobject_properties() * kPointerSize;
4056 }
4057
John Reck59135872010-11-02 12:39:01 -07004058 Object* result;
4059 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004060 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004061 if (!maybe_result->ToObject(&result)) return maybe_result;
4062 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004063
4064 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4065 Map::cast(result)->set_inobject_properties(inobject_properties());
4066 }
4067
4068 Map::cast(result)->set_prototype(prototype());
4069 Map::cast(result)->set_constructor(constructor());
4070
4071 Map::cast(result)->set_bit_field(bit_field());
4072 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004073 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004074
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004075 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4076
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004077#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004078 if (Map::cast(result)->is_shared()) {
4079 Map::cast(result)->SharedMapVerify();
4080 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004081#endif
4082
4083 return result;
4084}
4085
4086
John Reck59135872010-11-02 12:39:01 -07004087MaybeObject* Map::CopyDropTransitions() {
4088 Object* new_map;
4089 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4090 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4091 }
4092 Object* descriptors;
4093 { MaybeObject* maybe_descriptors =
4094 instance_descriptors()->RemoveTransitions();
4095 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4096 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004097 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004098 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004099}
4100
4101
John Reck59135872010-11-02 12:39:01 -07004102MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004103 // Allocate the code cache if not present.
4104 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004105 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004106 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004107 if (!maybe_result->ToObject(&result)) return maybe_result;
4108 }
Steve Block6ded16b2010-05-10 14:33:55 +01004109 set_code_cache(result);
4110 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004111
Steve Block6ded16b2010-05-10 14:33:55 +01004112 // Update the code cache.
4113 return CodeCache::cast(code_cache())->Update(name, code);
4114}
4115
4116
4117Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4118 // Do a lookup if a code cache exists.
4119 if (!code_cache()->IsFixedArray()) {
4120 return CodeCache::cast(code_cache())->Lookup(name, flags);
4121 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004122 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004123 }
4124}
4125
4126
4127int Map::IndexInCodeCache(Object* name, Code* code) {
4128 // Get the internal index if a code cache exists.
4129 if (!code_cache()->IsFixedArray()) {
4130 return CodeCache::cast(code_cache())->GetIndex(name, code);
4131 }
4132 return -1;
4133}
4134
4135
4136void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4137 // No GC is supposed to happen between a call to IndexInCodeCache and
4138 // RemoveFromCodeCache so the code cache must be there.
4139 ASSERT(!code_cache()->IsFixedArray());
4140 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4141}
4142
4143
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004144void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Steve Block053d10c2011-06-13 19:13:29 +01004145 // Traverse the transition tree without using a stack. We do this by
4146 // reversing the pointers in the maps and descriptor arrays.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004147 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004148 Map* meta_map = heap()->meta_map();
Steve Block053d10c2011-06-13 19:13:29 +01004149 Object** map_or_index_field = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01004150 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004151 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00004152 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
Steve Block053d10c2011-06-13 19:13:29 +01004153 if (!d->IsEmpty()) {
4154 FixedArray* contents = reinterpret_cast<FixedArray*>(
4155 d->get(DescriptorArray::kContentArrayIndex));
4156 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
4157 Object* map_or_index = *map_or_index_field;
4158 bool map_done = true; // Controls a nested continue statement.
4159 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
4160 i < contents->length();
4161 i += 2) {
4162 PropertyDetails details(Smi::cast(contents->get(i + 1)));
4163 if (details.IsTransition()) {
4164 // Found a map in the transition array. We record our progress in
4165 // the transition array by recording the current map in the map field
4166 // of the next map and recording the index in the transition array in
4167 // the map field of the array.
4168 Map* next = Map::cast(contents->get(i));
4169 next->set_map(current);
4170 *map_or_index_field = Smi::FromInt(i + 2);
4171 current = next;
4172 map_done = false;
4173 break;
4174 }
4175 }
4176 if (!map_done) continue;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004177 } else {
4178 map_or_index_field = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004179 }
Steve Block053d10c2011-06-13 19:13:29 +01004180 // That was the regular transitions, now for the prototype transitions.
4181 FixedArray* prototype_transitions =
4182 current->unchecked_prototype_transitions();
4183 Object** proto_map_or_index_field =
4184 RawField(prototype_transitions, HeapObject::kMapOffset);
4185 Object* map_or_index = *proto_map_or_index_field;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004186 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
Steve Block053d10c2011-06-13 19:13:29 +01004187 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
4188 if (i < prototype_transitions->length()) {
4189 // Found a map in the prototype transition array. Record progress in
4190 // an analogous way to the regular transitions array above.
4191 Object* perhaps_map = prototype_transitions->get(i);
4192 if (perhaps_map->IsMap()) {
4193 Map* next = Map::cast(perhaps_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004194 next->set_map(current);
Steve Block053d10c2011-06-13 19:13:29 +01004195 *proto_map_or_index_field =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004196 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004197 current = next;
Steve Block053d10c2011-06-13 19:13:29 +01004198 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004199 }
4200 }
Steve Block053d10c2011-06-13 19:13:29 +01004201 *proto_map_or_index_field = heap()->fixed_array_map();
4202 if (map_or_index_field != NULL) {
4203 *map_or_index_field = heap()->fixed_array_map();
4204 }
4205
4206 // The callback expects a map to have a real map as its map, so we save
4207 // the map field, which is being used to track the traversal and put the
4208 // correct map (the meta_map) in place while we do the callback.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004209 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01004210 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004211 callback(current, data);
4212 current = prev;
4213 }
4214}
4215
4216
John Reck59135872010-11-02 12:39:01 -07004217MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004218 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4219 // a large number and therefore they need to go into a hash table. They are
4220 // used to load global properties from cells.
4221 if (code->type() == NORMAL) {
4222 // Make sure that a hash table is allocated for the normal load code cache.
4223 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07004224 Object* result;
4225 { MaybeObject* maybe_result =
4226 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4227 if (!maybe_result->ToObject(&result)) return maybe_result;
4228 }
Steve Block6ded16b2010-05-10 14:33:55 +01004229 set_normal_type_cache(result);
4230 }
4231 return UpdateNormalTypeCache(name, code);
4232 } else {
4233 ASSERT(default_cache()->IsFixedArray());
4234 return UpdateDefaultCache(name, code);
4235 }
4236}
4237
4238
John Reck59135872010-11-02 12:39:01 -07004239MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004240 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00004241 // flags. This allows call constant stubs to overwrite call field
4242 // stubs, etc.
4243 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4244
4245 // First check whether we can update existing code cache without
4246 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01004247 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004248 int length = cache->length();
4249 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01004250 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004251 Object* key = cache->get(i);
4252 if (key->IsNull()) {
4253 if (deleted_index < 0) deleted_index = i;
4254 continue;
4255 }
4256 if (key->IsUndefined()) {
4257 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01004258 cache->set(i + kCodeCacheEntryNameOffset, name);
4259 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004260 return this;
4261 }
4262 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004263 Code::Flags found =
4264 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00004265 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01004266 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004267 return this;
4268 }
4269 }
4270 }
4271
4272 // Reached the end of the code cache. If there were deleted
4273 // elements, reuse the space for the first of them.
4274 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01004275 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4276 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004277 return this;
4278 }
4279
Steve Block6ded16b2010-05-10 14:33:55 +01004280 // Extend the code cache with some new entries (at least one). Must be a
4281 // multiple of the entry size.
4282 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4283 new_length = new_length - new_length % kCodeCacheEntrySize;
4284 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07004285 Object* result;
4286 { MaybeObject* maybe_result = cache->CopySize(new_length);
4287 if (!maybe_result->ToObject(&result)) return maybe_result;
4288 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004289
4290 // Add the (name, code) pair to the new cache.
4291 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01004292 cache->set(length + kCodeCacheEntryNameOffset, name);
4293 cache->set(length + kCodeCacheEntryCodeOffset, code);
4294 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00004295 return this;
4296}
4297
4298
John Reck59135872010-11-02 12:39:01 -07004299MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004300 // Adding a new entry can cause a new cache to be allocated.
4301 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07004302 Object* new_cache;
4303 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4304 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4305 }
Steve Block6ded16b2010-05-10 14:33:55 +01004306 set_normal_type_cache(new_cache);
4307 return this;
4308}
4309
4310
4311Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4312 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4313 return LookupNormalTypeCache(name, flags);
4314 } else {
4315 return LookupDefaultCache(name, flags);
4316 }
4317}
4318
4319
4320Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4321 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004322 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004323 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4324 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00004325 // Skip deleted elements.
4326 if (key->IsNull()) continue;
4327 if (key->IsUndefined()) return key;
4328 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004329 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4330 if (code->flags() == flags) {
4331 return code;
4332 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004333 }
4334 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004335 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004336}
4337
4338
Steve Block6ded16b2010-05-10 14:33:55 +01004339Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4340 if (!normal_type_cache()->IsUndefined()) {
4341 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4342 return cache->Lookup(name, flags);
4343 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004344 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004345 }
4346}
4347
4348
4349int CodeCache::GetIndex(Object* name, Code* code) {
4350 if (code->type() == NORMAL) {
4351 if (normal_type_cache()->IsUndefined()) return -1;
4352 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4353 return cache->GetIndex(String::cast(name), code->flags());
4354 }
4355
4356 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004357 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004358 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4359 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004360 }
4361 return -1;
4362}
4363
4364
Steve Block6ded16b2010-05-10 14:33:55 +01004365void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
4366 if (code->type() == NORMAL) {
4367 ASSERT(!normal_type_cache()->IsUndefined());
4368 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4369 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
4370 cache->RemoveByIndex(index);
4371 } else {
4372 FixedArray* array = default_cache();
4373 ASSERT(array->length() >= index && array->get(index)->IsCode());
4374 // Use null instead of undefined for deleted elements to distinguish
4375 // deleted elements from unused elements. This distinction is used
4376 // when looking up in the cache and when updating the cache.
4377 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4378 array->set_null(index - 1); // Name.
4379 array->set_null(index); // Code.
4380 }
4381}
4382
4383
4384// The key in the code cache hash table consists of the property name and the
4385// code object. The actual match is on the name and the code flags. If a key
4386// is created using the flags and not a code object it can only be used for
4387// lookup not to create a new entry.
4388class CodeCacheHashTableKey : public HashTableKey {
4389 public:
4390 CodeCacheHashTableKey(String* name, Code::Flags flags)
4391 : name_(name), flags_(flags), code_(NULL) { }
4392
4393 CodeCacheHashTableKey(String* name, Code* code)
4394 : name_(name),
4395 flags_(code->flags()),
4396 code_(code) { }
4397
4398
4399 bool IsMatch(Object* other) {
4400 if (!other->IsFixedArray()) return false;
4401 FixedArray* pair = FixedArray::cast(other);
4402 String* name = String::cast(pair->get(0));
4403 Code::Flags flags = Code::cast(pair->get(1))->flags();
4404 if (flags != flags_) {
4405 return false;
4406 }
4407 return name_->Equals(name);
4408 }
4409
4410 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4411 return name->Hash() ^ flags;
4412 }
4413
4414 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4415
4416 uint32_t HashForObject(Object* obj) {
4417 FixedArray* pair = FixedArray::cast(obj);
4418 String* name = String::cast(pair->get(0));
4419 Code* code = Code::cast(pair->get(1));
4420 return NameFlagsHashHelper(name, code->flags());
4421 }
4422
John Reck59135872010-11-02 12:39:01 -07004423 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01004424 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07004425 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004426 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07004427 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4428 }
Steve Block6ded16b2010-05-10 14:33:55 +01004429 FixedArray* pair = FixedArray::cast(obj);
4430 pair->set(0, name_);
4431 pair->set(1, code_);
4432 return pair;
4433 }
4434
4435 private:
4436 String* name_;
4437 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004438 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01004439 Code* code_;
4440};
4441
4442
4443Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4444 CodeCacheHashTableKey key(name, flags);
4445 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01004446 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004447 return get(EntryToIndex(entry) + 1);
4448}
4449
4450
John Reck59135872010-11-02 12:39:01 -07004451MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004452 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07004453 Object* obj;
4454 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4455 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4456 }
Steve Block6ded16b2010-05-10 14:33:55 +01004457
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004458 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01004459 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4460
4461 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004462 Object* k;
4463 { MaybeObject* maybe_k = key.AsObject();
4464 if (!maybe_k->ToObject(&k)) return maybe_k;
4465 }
Steve Block6ded16b2010-05-10 14:33:55 +01004466
4467 cache->set(EntryToIndex(entry), k);
4468 cache->set(EntryToIndex(entry) + 1, code);
4469 cache->ElementAdded();
4470 return cache;
4471}
4472
4473
4474int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4475 CodeCacheHashTableKey key(name, flags);
4476 int entry = FindEntry(&key);
4477 return (entry == kNotFound) ? -1 : entry;
4478}
4479
4480
4481void CodeCacheHashTable::RemoveByIndex(int index) {
4482 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004483 Heap* heap = GetHeap();
4484 set(EntryToIndex(index), heap->null_value());
4485 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004486 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004487}
4488
4489
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004490MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4491 Code::Flags flags,
4492 Code* code) {
4493 // Initialize cache if necessary.
4494 if (cache()->IsUndefined()) {
4495 Object* result;
4496 { MaybeObject* maybe_result =
4497 PolymorphicCodeCacheHashTable::Allocate(
4498 PolymorphicCodeCacheHashTable::kInitialSize);
4499 if (!maybe_result->ToObject(&result)) return maybe_result;
4500 }
4501 set_cache(result);
4502 } else {
4503 // This entry shouldn't be contained in the cache yet.
4504 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4505 ->Lookup(maps, flags)->IsUndefined());
4506 }
4507 PolymorphicCodeCacheHashTable* hash_table =
4508 PolymorphicCodeCacheHashTable::cast(cache());
4509 Object* new_cache;
4510 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4511 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4512 }
4513 set_cache(new_cache);
4514 return this;
4515}
4516
4517
4518Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4519 if (!cache()->IsUndefined()) {
4520 PolymorphicCodeCacheHashTable* hash_table =
4521 PolymorphicCodeCacheHashTable::cast(cache());
4522 return hash_table->Lookup(maps, flags);
4523 } else {
4524 return GetHeap()->undefined_value();
4525 }
4526}
4527
4528
4529// Despite their name, object of this class are not stored in the actual
4530// hash table; instead they're temporarily used for lookups. It is therefore
4531// safe to have a weak (non-owning) pointer to a MapList as a member field.
4532class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4533 public:
4534 // Callers must ensure that |maps| outlives the newly constructed object.
4535 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4536 : maps_(maps),
4537 code_flags_(code_flags) {}
4538
4539 bool IsMatch(Object* other) {
4540 MapList other_maps(kDefaultListAllocationSize);
4541 int other_flags;
4542 FromObject(other, &other_flags, &other_maps);
4543 if (code_flags_ != other_flags) return false;
4544 if (maps_->length() != other_maps.length()) return false;
4545 // Compare just the hashes first because it's faster.
4546 int this_hash = MapsHashHelper(maps_, code_flags_);
4547 int other_hash = MapsHashHelper(&other_maps, other_flags);
4548 if (this_hash != other_hash) return false;
4549
4550 // Full comparison: for each map in maps_, look for an equivalent map in
4551 // other_maps. This implementation is slow, but probably good enough for
4552 // now because the lists are short (<= 4 elements currently).
4553 for (int i = 0; i < maps_->length(); ++i) {
4554 bool match_found = false;
4555 for (int j = 0; j < other_maps.length(); ++j) {
4556 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
4557 match_found = true;
4558 break;
4559 }
4560 }
4561 if (!match_found) return false;
4562 }
4563 return true;
4564 }
4565
4566 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4567 uint32_t hash = code_flags;
4568 for (int i = 0; i < maps->length(); ++i) {
4569 hash ^= maps->at(i)->Hash();
4570 }
4571 return hash;
4572 }
4573
4574 uint32_t Hash() {
4575 return MapsHashHelper(maps_, code_flags_);
4576 }
4577
4578 uint32_t HashForObject(Object* obj) {
4579 MapList other_maps(kDefaultListAllocationSize);
4580 int other_flags;
4581 FromObject(obj, &other_flags, &other_maps);
4582 return MapsHashHelper(&other_maps, other_flags);
4583 }
4584
4585 MUST_USE_RESULT MaybeObject* AsObject() {
4586 Object* obj;
4587 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4588 // both because the referenced MapList is short-lived, and because C++
4589 // objects can't be stored in the heap anyway.
4590 { MaybeObject* maybe_obj =
4591 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4592 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4593 }
4594 FixedArray* list = FixedArray::cast(obj);
4595 list->set(0, Smi::FromInt(code_flags_));
4596 for (int i = 0; i < maps_->length(); ++i) {
4597 list->set(i + 1, maps_->at(i));
4598 }
4599 return list;
4600 }
4601
4602 private:
4603 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4604 FixedArray* list = FixedArray::cast(obj);
4605 maps->Rewind(0);
4606 *code_flags = Smi::cast(list->get(0))->value();
4607 for (int i = 1; i < list->length(); ++i) {
4608 maps->Add(Map::cast(list->get(i)));
4609 }
4610 return maps;
4611 }
4612
4613 MapList* maps_; // weak.
4614 int code_flags_;
4615 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
4616};
4617
4618
4619Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4620 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4621 int entry = FindEntry(&key);
4622 if (entry == kNotFound) return GetHeap()->undefined_value();
4623 return get(EntryToIndex(entry) + 1);
4624}
4625
4626
4627MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4628 int code_flags,
4629 Code* code) {
4630 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4631 Object* obj;
4632 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4633 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4634 }
4635 PolymorphicCodeCacheHashTable* cache =
4636 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4637 int entry = cache->FindInsertionEntry(key.Hash());
4638 { MaybeObject* maybe_obj = key.AsObject();
4639 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4640 }
4641 cache->set(EntryToIndex(entry), obj);
4642 cache->set(EntryToIndex(entry) + 1, code);
4643 cache->ElementAdded();
4644 return cache;
4645}
4646
4647
John Reck59135872010-11-02 12:39:01 -07004648MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004649 ElementsAccessor* accessor = array->GetElementsAccessor();
4650 MaybeObject* maybe_result =
4651 accessor->AddElementsToFixedArray(array->elements(), this, array, array);
4652 FixedArray* result;
4653 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
4654#ifdef DEBUG
4655 if (FLAG_enable_slow_asserts) {
4656 for (int i = 0; i < result->length(); i++) {
4657 Object* current = result->get(i);
4658 ASSERT(current->IsNumber() || current->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00004659 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004660 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004661#endif
4662 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004663}
4664
4665
John Reck59135872010-11-02 12:39:01 -07004666MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004667 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
4668 MaybeObject* maybe_result =
4669 accessor->AddElementsToFixedArray(other, this, NULL, NULL);
4670 FixedArray* result;
4671 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
Ben Murdochf87a2032010-10-22 12:50:53 +01004672#ifdef DEBUG
4673 if (FLAG_enable_slow_asserts) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004674 for (int i = 0; i < result->length(); i++) {
4675 Object* current = result->get(i);
4676 ASSERT(current->IsNumber() || current->IsString());
Ben Murdochf87a2032010-10-22 12:50:53 +01004677 }
4678 }
4679#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004680 return result;
4681}
4682
4683
John Reck59135872010-11-02 12:39:01 -07004684MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004685 Heap* heap = GetHeap();
4686 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004687 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004688 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004689 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4690 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004691 FixedArray* result = FixedArray::cast(obj);
4692 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004693 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004694 int len = length();
4695 if (new_length < len) len = new_length;
4696 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004697 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004698 for (int i = 0; i < len; i++) {
4699 result->set(i, get(i), mode);
4700 }
4701 return result;
4702}
4703
4704
4705void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004706 AssertNoAllocation no_gc;
4707 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004708 for (int index = 0; index < len; index++) {
4709 dest->set(dest_pos+index, get(pos+index), mode);
4710 }
4711}
4712
4713
4714#ifdef DEBUG
4715bool FixedArray::IsEqualTo(FixedArray* other) {
4716 if (length() != other->length()) return false;
4717 for (int i = 0 ; i < length(); ++i) {
4718 if (get(i) != other->get(i)) return false;
4719 }
4720 return true;
4721}
4722#endif
4723
4724
John Reck59135872010-11-02 12:39:01 -07004725MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004726 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004727 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004728 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004729 }
4730 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004731 Object* array;
4732 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004733 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004734 if (!maybe_array->ToObject(&array)) return maybe_array;
4735 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004736 // Do not use DescriptorArray::cast on incomplete object.
4737 FixedArray* result = FixedArray::cast(array);
4738
4739 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004740 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004741 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004742 if (!maybe_array->ToObject(&array)) return maybe_array;
4743 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004744 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00004745 result->set(kContentArrayIndex, array);
4746 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004747 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004748 return result;
4749}
4750
4751
4752void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4753 FixedArray* new_cache) {
4754 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4755 if (HasEnumCache()) {
4756 FixedArray::cast(get(kEnumerationIndexIndex))->
4757 set(kEnumCacheBridgeCacheIndex, new_cache);
4758 } else {
4759 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4760 FixedArray::cast(bridge_storage)->
4761 set(kEnumCacheBridgeCacheIndex, new_cache);
4762 fast_set(FixedArray::cast(bridge_storage),
4763 kEnumCacheBridgeEnumIndex,
4764 get(kEnumerationIndexIndex));
4765 set(kEnumerationIndexIndex, bridge_storage);
4766 }
4767}
4768
4769
John Reck59135872010-11-02 12:39:01 -07004770MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4771 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004772 // Transitions are only kept when inserting another transition.
4773 // This precondition is not required by this function's implementation, but
4774 // is currently required by the semantics of maps, so we check it.
4775 // Conversely, we filter after replacing, so replacing a transition and
4776 // removing all other transitions is not supported.
4777 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4778 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4779 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4780
4781 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004782 Object* result;
4783 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4784 if (!maybe_result->ToObject(&result)) return maybe_result;
4785 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004786
4787 int transitions = 0;
4788 int null_descriptors = 0;
4789 if (remove_transitions) {
4790 for (int i = 0; i < number_of_descriptors(); i++) {
4791 if (IsTransition(i)) transitions++;
4792 if (IsNullDescriptor(i)) null_descriptors++;
4793 }
4794 } else {
4795 for (int i = 0; i < number_of_descriptors(); i++) {
4796 if (IsNullDescriptor(i)) null_descriptors++;
4797 }
4798 }
4799 int new_size = number_of_descriptors() - transitions - null_descriptors;
4800
4801 // If key is in descriptor, we replace it in-place when filtering.
4802 // Count a null descriptor for key as inserted, not replaced.
4803 int index = Search(descriptor->GetKey());
4804 const bool inserting = (index == kNotFound);
4805 const bool replacing = !inserting;
4806 bool keep_enumeration_index = false;
4807 if (inserting) {
4808 ++new_size;
4809 }
4810 if (replacing) {
4811 // We are replacing an existing descriptor. We keep the enumeration
4812 // index of a visible property.
4813 PropertyType t = PropertyDetails(GetDetails(index)).type();
4814 if (t == CONSTANT_FUNCTION ||
4815 t == FIELD ||
4816 t == CALLBACKS ||
4817 t == INTERCEPTOR) {
4818 keep_enumeration_index = true;
4819 } else if (remove_transitions) {
4820 // Replaced descriptor has been counted as removed if it is
4821 // a transition that will be replaced. Adjust count in this case.
4822 ++new_size;
4823 }
4824 }
John Reck59135872010-11-02 12:39:01 -07004825 { MaybeObject* maybe_result = Allocate(new_size);
4826 if (!maybe_result->ToObject(&result)) return maybe_result;
4827 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004828 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4829 // Set the enumeration index in the descriptors and set the enumeration index
4830 // in the result.
4831 int enumeration_index = NextEnumerationIndex();
4832 if (!descriptor->GetDetails().IsTransition()) {
4833 if (keep_enumeration_index) {
4834 descriptor->SetEnumerationIndex(
4835 PropertyDetails(GetDetails(index)).index());
4836 } else {
4837 descriptor->SetEnumerationIndex(enumeration_index);
4838 ++enumeration_index;
4839 }
4840 }
4841 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4842
4843 // Copy the descriptors, filtering out transitions and null descriptors,
4844 // and inserting or replacing a descriptor.
4845 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4846 int from_index = 0;
4847 int to_index = 0;
4848
4849 for (; from_index < number_of_descriptors(); from_index++) {
4850 String* key = GetKey(from_index);
4851 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4852 break;
4853 }
4854 if (IsNullDescriptor(from_index)) continue;
4855 if (remove_transitions && IsTransition(from_index)) continue;
4856 new_descriptors->CopyFrom(to_index++, this, from_index);
4857 }
4858
4859 new_descriptors->Set(to_index++, descriptor);
4860 if (replacing) from_index++;
4861
4862 for (; from_index < number_of_descriptors(); from_index++) {
4863 if (IsNullDescriptor(from_index)) continue;
4864 if (remove_transitions && IsTransition(from_index)) continue;
4865 new_descriptors->CopyFrom(to_index++, this, from_index);
4866 }
4867
4868 ASSERT(to_index == new_descriptors->number_of_descriptors());
4869 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4870
4871 return new_descriptors;
4872}
4873
4874
John Reck59135872010-11-02 12:39:01 -07004875MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004876 // Remove all transitions and null descriptors. Return a copy of the array
4877 // with all transitions removed, or a Failure object if the new array could
4878 // not be allocated.
4879
4880 // Compute the size of the map transition entries to be removed.
4881 int num_removed = 0;
4882 for (int i = 0; i < number_of_descriptors(); i++) {
4883 if (!IsProperty(i)) num_removed++;
4884 }
4885
4886 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07004887 Object* result;
4888 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4889 if (!maybe_result->ToObject(&result)) return maybe_result;
4890 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004891 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4892
4893 // Copy the content.
4894 int next_descriptor = 0;
4895 for (int i = 0; i < number_of_descriptors(); i++) {
4896 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
4897 }
4898 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4899
4900 return new_descriptors;
4901}
4902
4903
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004904void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004905 // In-place heap sort.
4906 int len = number_of_descriptors();
4907
4908 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004909 // Index of the last node with children
4910 const int max_parent_index = (len / 2) - 1;
4911 for (int i = max_parent_index; i >= 0; --i) {
4912 int parent_index = i;
4913 const uint32_t parent_hash = GetKey(i)->Hash();
4914 while (parent_index <= max_parent_index) {
4915 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004916 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004917 if (child_index + 1 < len) {
4918 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4919 if (right_child_hash > child_hash) {
4920 child_index++;
4921 child_hash = right_child_hash;
4922 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004923 }
Steve Block6ded16b2010-05-10 14:33:55 +01004924 if (child_hash <= parent_hash) break;
4925 Swap(parent_index, child_index);
4926 // Now element at child_index could be < its children.
4927 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004928 }
4929 }
4930
4931 // Extract elements and create sorted array.
4932 for (int i = len - 1; i > 0; --i) {
4933 // Put max element at the back of the array.
4934 Swap(0, i);
4935 // Sift down the new top element.
4936 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004937 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4938 const int max_parent_index = (i / 2) - 1;
4939 while (parent_index <= max_parent_index) {
4940 int child_index = parent_index * 2 + 1;
4941 uint32_t child_hash = GetKey(child_index)->Hash();
4942 if (child_index + 1 < i) {
4943 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4944 if (right_child_hash > child_hash) {
4945 child_index++;
4946 child_hash = right_child_hash;
4947 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004948 }
Steve Block6ded16b2010-05-10 14:33:55 +01004949 if (child_hash <= parent_hash) break;
4950 Swap(parent_index, child_index);
4951 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004952 }
4953 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004954}
Steve Blocka7e24c12009-10-30 11:49:00 +00004955
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004956
4957void DescriptorArray::Sort() {
4958 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004959 SLOW_ASSERT(IsSortedNoDuplicates());
4960}
4961
4962
4963int DescriptorArray::BinarySearch(String* name, int low, int high) {
4964 uint32_t hash = name->Hash();
4965
4966 while (low <= high) {
4967 int mid = (low + high) / 2;
4968 String* mid_name = GetKey(mid);
4969 uint32_t mid_hash = mid_name->Hash();
4970
4971 if (mid_hash > hash) {
4972 high = mid - 1;
4973 continue;
4974 }
4975 if (mid_hash < hash) {
4976 low = mid + 1;
4977 continue;
4978 }
4979 // Found an element with the same hash-code.
4980 ASSERT(hash == mid_hash);
4981 // There might be more, so we find the first one and
4982 // check them all to see if we have a match.
4983 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4984 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4985 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4986 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4987 }
4988 break;
4989 }
4990 return kNotFound;
4991}
4992
4993
4994int DescriptorArray::LinearSearch(String* name, int len) {
4995 uint32_t hash = name->Hash();
4996 for (int number = 0; number < len; number++) {
4997 String* entry = GetKey(number);
4998 if ((entry->Hash() == hash) &&
4999 name->Equals(entry) &&
5000 !is_null_descriptor(number)) {
5001 return number;
5002 }
5003 }
5004 return kNotFound;
5005}
5006
5007
Ben Murdochb0fe1622011-05-05 13:52:32 +01005008MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5009 PretenureFlag pretenure) {
5010 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005011 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005012 pretenure);
5013}
5014
5015
5016MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5017 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005018 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5019 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005020 pretenure);
5021}
5022
5023
Steve Blocka7e24c12009-10-30 11:49:00 +00005024#ifdef DEBUG
5025bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5026 if (IsEmpty()) return other->IsEmpty();
5027 if (other->IsEmpty()) return false;
5028 if (length() != other->length()) return false;
5029 for (int i = 0; i < length(); ++i) {
5030 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5031 }
5032 return GetContentArray()->IsEqualTo(other->GetContentArray());
5033}
5034#endif
5035
5036
Steve Blocka7e24c12009-10-30 11:49:00 +00005037bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01005038 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005039 return true;
5040}
5041
5042
5043int String::Utf8Length() {
5044 if (IsAsciiRepresentation()) return length();
5045 // Attempt to flatten before accessing the string. It probably
5046 // doesn't make Utf8Length faster, but it is very likely that
5047 // the string will be accessed later (for example by WriteUtf8)
5048 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01005049 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01005050 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01005051 Access<StringInputBuffer> buffer(
5052 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005053 buffer->Reset(0, this);
5054 int result = 0;
5055 while (buffer->has_more())
5056 result += unibrow::Utf8::Length(buffer->GetNext());
5057 return result;
5058}
5059
5060
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005061String::FlatContent String::GetFlatContent() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005062 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005063 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00005064 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00005065 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005066 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005067 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005068 if (cons->second()->length() != 0) {
5069 return FlatContent();
5070 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005071 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005072 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00005073 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005074 if (shape.representation_tag() == kSlicedStringTag) {
5075 SlicedString* slice = SlicedString::cast(string);
5076 offset = slice->offset();
5077 string = slice->parent();
5078 shape = StringShape(string);
5079 ASSERT(shape.representation_tag() != kConsStringTag &&
5080 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00005081 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005082 if (shape.encoding_tag() == kAsciiStringTag) {
5083 const char* start;
5084 if (shape.representation_tag() == kSeqStringTag) {
5085 start = SeqAsciiString::cast(string)->GetChars();
5086 } else {
5087 start = ExternalAsciiString::cast(string)->resource()->data();
5088 }
5089 return FlatContent(Vector<const char>(start + offset, length));
5090 } else {
5091 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
5092 const uc16* start;
5093 if (shape.representation_tag() == kSeqStringTag) {
5094 start = SeqTwoByteString::cast(string)->GetChars();
5095 } else {
5096 start = ExternalTwoByteString::cast(string)->resource()->data();
5097 }
5098 return FlatContent(Vector<const uc16>(start + offset, length));
5099 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005100}
5101
5102
5103SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5104 RobustnessFlag robust_flag,
5105 int offset,
5106 int length,
5107 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005108 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
5109 return SmartPointer<char>(NULL);
5110 }
Steve Block44f0eee2011-05-26 01:26:41 +01005111 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005112
5113 // Negative length means the to the end of the string.
5114 if (length < 0) length = kMaxInt - offset;
5115
5116 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01005117 Access<StringInputBuffer> buffer(
5118 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005119 buffer->Reset(offset, this);
5120 int character_position = offset;
5121 int utf8_bytes = 0;
5122 while (buffer->has_more()) {
5123 uint16_t character = buffer->GetNext();
5124 if (character_position < offset + length) {
5125 utf8_bytes += unibrow::Utf8::Length(character);
5126 }
5127 character_position++;
5128 }
5129
5130 if (length_return) {
5131 *length_return = utf8_bytes;
5132 }
5133
5134 char* result = NewArray<char>(utf8_bytes + 1);
5135
5136 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5137 buffer->Rewind();
5138 buffer->Seek(offset);
5139 character_position = offset;
5140 int utf8_byte_position = 0;
5141 while (buffer->has_more()) {
5142 uint16_t character = buffer->GetNext();
5143 if (character_position < offset + length) {
5144 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5145 character = ' ';
5146 }
5147 utf8_byte_position +=
5148 unibrow::Utf8::Encode(result + utf8_byte_position, character);
5149 }
5150 character_position++;
5151 }
5152 result[utf8_byte_position] = 0;
5153 return SmartPointer<char>(result);
5154}
5155
5156
5157SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5158 RobustnessFlag robust_flag,
5159 int* length_return) {
5160 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5161}
5162
5163
5164const uc16* String::GetTwoByteData() {
5165 return GetTwoByteData(0);
5166}
5167
5168
5169const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005170 ASSERT(!IsAsciiRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00005171 switch (StringShape(this).representation_tag()) {
5172 case kSeqStringTag:
5173 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
5174 case kExternalStringTag:
5175 return ExternalTwoByteString::cast(this)->
5176 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005177 case kSlicedStringTag: {
5178 SlicedString* slice = SlicedString::cast(this);
5179 return slice->parent()->GetTwoByteData(start + slice->offset());
5180 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005181 case kConsStringTag:
5182 UNREACHABLE();
5183 return NULL;
5184 }
5185 UNREACHABLE();
5186 return NULL;
5187}
5188
5189
5190SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005191 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
5192 return SmartPointer<uc16>();
5193 }
Steve Block44f0eee2011-05-26 01:26:41 +01005194 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005195
Steve Block44f0eee2011-05-26 01:26:41 +01005196 Access<StringInputBuffer> buffer(
5197 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005198 buffer->Reset(this);
5199
5200 uc16* result = NewArray<uc16>(length() + 1);
5201
5202 int i = 0;
5203 while (buffer->has_more()) {
5204 uint16_t character = buffer->GetNext();
5205 result[i++] = character;
5206 }
5207 result[i] = 0;
5208 return SmartPointer<uc16>(result);
5209}
5210
5211
5212const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
5213 return reinterpret_cast<uc16*>(
5214 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5215}
5216
5217
5218void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5219 unsigned* offset_ptr,
5220 unsigned max_chars) {
5221 unsigned chars_read = 0;
5222 unsigned offset = *offset_ptr;
5223 while (chars_read < max_chars) {
5224 uint16_t c = *reinterpret_cast<uint16_t*>(
5225 reinterpret_cast<char*>(this) -
5226 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5227 if (c <= kMaxAsciiCharCode) {
5228 // Fast case for ASCII characters. Cursor is an input output argument.
5229 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5230 rbb->util_buffer,
5231 rbb->capacity,
5232 rbb->cursor)) {
5233 break;
5234 }
5235 } else {
5236 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5237 rbb->util_buffer,
5238 rbb->capacity,
5239 rbb->cursor)) {
5240 break;
5241 }
5242 }
5243 offset++;
5244 chars_read++;
5245 }
5246 *offset_ptr = offset;
5247 rbb->remaining += chars_read;
5248}
5249
5250
5251const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5252 unsigned* remaining,
5253 unsigned* offset_ptr,
5254 unsigned max_chars) {
5255 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5256 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5257 *remaining = max_chars;
5258 *offset_ptr += max_chars;
5259 return b;
5260}
5261
5262
5263// This will iterate unless the block of string data spans two 'halves' of
5264// a ConsString, in which case it will recurse. Since the block of string
5265// data to be read has a maximum size this limits the maximum recursion
5266// depth to something sane. Since C++ does not have tail call recursion
5267// elimination, the iteration must be explicit. Since this is not an
5268// -IntoBuffer method it can delegate to one of the efficient
5269// *AsciiStringReadBlock routines.
5270const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5271 unsigned* offset_ptr,
5272 unsigned max_chars) {
5273 ConsString* current = this;
5274 unsigned offset = *offset_ptr;
5275 int offset_correction = 0;
5276
5277 while (true) {
5278 String* left = current->first();
5279 unsigned left_length = (unsigned)left->length();
5280 if (left_length > offset &&
5281 (max_chars <= left_length - offset ||
5282 (rbb->capacity <= left_length - offset &&
5283 (max_chars = left_length - offset, true)))) { // comma operator!
5284 // Left hand side only - iterate unless we have reached the bottom of
5285 // the cons tree. The assignment on the left of the comma operator is
5286 // in order to make use of the fact that the -IntoBuffer routines can
5287 // produce at most 'capacity' characters. This enables us to postpone
5288 // the point where we switch to the -IntoBuffer routines (below) in order
5289 // to maximize the chances of delegating a big chunk of work to the
5290 // efficient *AsciiStringReadBlock routines.
5291 if (StringShape(left).IsCons()) {
5292 current = ConsString::cast(left);
5293 continue;
5294 } else {
5295 const unibrow::byte* answer =
5296 String::ReadBlock(left, rbb, &offset, max_chars);
5297 *offset_ptr = offset + offset_correction;
5298 return answer;
5299 }
5300 } else if (left_length <= offset) {
5301 // Right hand side only - iterate unless we have reached the bottom of
5302 // the cons tree.
5303 String* right = current->second();
5304 offset -= left_length;
5305 offset_correction += left_length;
5306 if (StringShape(right).IsCons()) {
5307 current = ConsString::cast(right);
5308 continue;
5309 } else {
5310 const unibrow::byte* answer =
5311 String::ReadBlock(right, rbb, &offset, max_chars);
5312 *offset_ptr = offset + offset_correction;
5313 return answer;
5314 }
5315 } else {
5316 // The block to be read spans two sides of the ConsString, so we call the
5317 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5318 // are able to assemble data from several part strings because they use
5319 // the util_buffer to store their data and never return direct pointers
5320 // to their storage. We don't try to read more than the buffer capacity
5321 // here or we can get too much recursion.
5322 ASSERT(rbb->remaining == 0);
5323 ASSERT(rbb->cursor == 0);
5324 current->ConsStringReadBlockIntoBuffer(
5325 rbb,
5326 &offset,
5327 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5328 *offset_ptr = offset + offset_correction;
5329 return rbb->util_buffer;
5330 }
5331 }
5332}
5333
5334
Steve Blocka7e24c12009-10-30 11:49:00 +00005335uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5336 ASSERT(index >= 0 && index < length());
5337 return resource()->data()[index];
5338}
5339
5340
5341const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5342 unsigned* remaining,
5343 unsigned* offset_ptr,
5344 unsigned max_chars) {
5345 // Cast const char* to unibrow::byte* (signedness difference).
5346 const unibrow::byte* b =
5347 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
5348 *remaining = max_chars;
5349 *offset_ptr += max_chars;
5350 return b;
5351}
5352
5353
5354const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5355 unsigned start) {
5356 return resource()->data() + start;
5357}
5358
5359
5360uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5361 ASSERT(index >= 0 && index < length());
5362 return resource()->data()[index];
5363}
5364
5365
5366void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5367 ReadBlockBuffer* rbb,
5368 unsigned* offset_ptr,
5369 unsigned max_chars) {
5370 unsigned chars_read = 0;
5371 unsigned offset = *offset_ptr;
5372 const uint16_t* data = resource()->data();
5373 while (chars_read < max_chars) {
5374 uint16_t c = data[offset];
5375 if (c <= kMaxAsciiCharCode) {
5376 // Fast case for ASCII characters. Cursor is an input output argument.
5377 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5378 rbb->util_buffer,
5379 rbb->capacity,
5380 rbb->cursor))
5381 break;
5382 } else {
5383 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5384 rbb->util_buffer,
5385 rbb->capacity,
5386 rbb->cursor))
5387 break;
5388 }
5389 offset++;
5390 chars_read++;
5391 }
5392 *offset_ptr = offset;
5393 rbb->remaining += chars_read;
5394}
5395
5396
5397void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5398 unsigned* offset_ptr,
5399 unsigned max_chars) {
5400 unsigned capacity = rbb->capacity - rbb->cursor;
5401 if (max_chars > capacity) max_chars = capacity;
5402 memcpy(rbb->util_buffer + rbb->cursor,
5403 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5404 *offset_ptr * kCharSize,
5405 max_chars);
5406 rbb->remaining += max_chars;
5407 *offset_ptr += max_chars;
5408 rbb->cursor += max_chars;
5409}
5410
5411
5412void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5413 ReadBlockBuffer* rbb,
5414 unsigned* offset_ptr,
5415 unsigned max_chars) {
5416 unsigned capacity = rbb->capacity - rbb->cursor;
5417 if (max_chars > capacity) max_chars = capacity;
5418 memcpy(rbb->util_buffer + rbb->cursor,
5419 resource()->data() + *offset_ptr,
5420 max_chars);
5421 rbb->remaining += max_chars;
5422 *offset_ptr += max_chars;
5423 rbb->cursor += max_chars;
5424}
5425
5426
5427// This method determines the type of string involved and then copies
5428// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5429// where they can be found. The pointer is not necessarily valid across a GC
5430// (see AsciiStringReadBlock).
5431const unibrow::byte* String::ReadBlock(String* input,
5432 ReadBlockBuffer* rbb,
5433 unsigned* offset_ptr,
5434 unsigned max_chars) {
5435 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5436 if (max_chars == 0) {
5437 rbb->remaining = 0;
5438 return NULL;
5439 }
5440 switch (StringShape(input).representation_tag()) {
5441 case kSeqStringTag:
5442 if (input->IsAsciiRepresentation()) {
5443 SeqAsciiString* str = SeqAsciiString::cast(input);
5444 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5445 offset_ptr,
5446 max_chars);
5447 } else {
5448 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5449 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5450 offset_ptr,
5451 max_chars);
5452 return rbb->util_buffer;
5453 }
5454 case kConsStringTag:
5455 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5456 offset_ptr,
5457 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005458 case kExternalStringTag:
5459 if (input->IsAsciiRepresentation()) {
5460 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5461 &rbb->remaining,
5462 offset_ptr,
5463 max_chars);
5464 } else {
5465 ExternalTwoByteString::cast(input)->
5466 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5467 offset_ptr,
5468 max_chars);
5469 return rbb->util_buffer;
5470 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005471 case kSlicedStringTag:
5472 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
5473 offset_ptr,
5474 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005475 default:
5476 break;
5477 }
5478
5479 UNREACHABLE();
5480 return 0;
5481}
5482
5483
Steve Blocka7e24c12009-10-30 11:49:00 +00005484void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01005485 Isolate* isolate = Isolate::Current();
5486 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00005487 while (current != NULL) {
5488 current->PostGarbageCollection();
5489 current = current->prev_;
5490 }
5491}
5492
5493
5494// Reserve space for statics needing saving and restoring.
5495int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01005496 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005497}
5498
5499
5500// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005501char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01005502 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5503 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005504 return to + ArchiveSpacePerThread();
5505}
5506
5507
5508// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005509char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01005510 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00005511 return from + ArchiveSpacePerThread();
5512}
5513
5514
5515char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5516 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5517 Iterate(v, top);
5518 return thread_storage + ArchiveSpacePerThread();
5519}
5520
5521
5522void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01005523 Isolate* isolate = Isolate::Current();
5524 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005525}
5526
5527
5528void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5529 Relocatable* current = top;
5530 while (current != NULL) {
5531 current->IterateInstance(v);
5532 current = current->prev_;
5533 }
5534}
5535
5536
Steve Block44f0eee2011-05-26 01:26:41 +01005537FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5538 : Relocatable(isolate),
5539 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00005540 length_(str->length()) {
5541 PostGarbageCollection();
5542}
5543
5544
Steve Block44f0eee2011-05-26 01:26:41 +01005545FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5546 : Relocatable(isolate),
5547 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005548 is_ascii_(true),
5549 length_(input.length()),
5550 start_(input.start()) { }
5551
5552
5553void FlatStringReader::PostGarbageCollection() {
5554 if (str_ == NULL) return;
5555 Handle<String> str(str_);
5556 ASSERT(str->IsFlat());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005557 String::FlatContent content = str->GetFlatContent();
5558 ASSERT(content.IsFlat());
5559 is_ascii_ = content.IsAscii();
Steve Blocka7e24c12009-10-30 11:49:00 +00005560 if (is_ascii_) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005561 start_ = content.ToAsciiVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00005562 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005563 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00005564 }
5565}
5566
5567
5568void StringInputBuffer::Seek(unsigned pos) {
5569 Reset(pos, input_);
5570}
5571
5572
5573void SafeStringInputBuffer::Seek(unsigned pos) {
5574 Reset(pos, input_);
5575}
5576
5577
5578// This method determines the type of string involved and then copies
5579// a whole chunk of characters into a buffer. It can be used with strings
5580// that have been glued together to form a ConsString and which must cooperate
5581// to fill up a buffer.
5582void String::ReadBlockIntoBuffer(String* input,
5583 ReadBlockBuffer* rbb,
5584 unsigned* offset_ptr,
5585 unsigned max_chars) {
5586 ASSERT(*offset_ptr <= (unsigned)input->length());
5587 if (max_chars == 0) return;
5588
5589 switch (StringShape(input).representation_tag()) {
5590 case kSeqStringTag:
5591 if (input->IsAsciiRepresentation()) {
5592 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5593 offset_ptr,
5594 max_chars);
5595 return;
5596 } else {
5597 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5598 offset_ptr,
5599 max_chars);
5600 return;
5601 }
5602 case kConsStringTag:
5603 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5604 offset_ptr,
5605 max_chars);
5606 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005607 case kExternalStringTag:
5608 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005609 ExternalAsciiString::cast(input)->
5610 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5611 } else {
5612 ExternalTwoByteString::cast(input)->
5613 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5614 offset_ptr,
5615 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005616 }
5617 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005618 case kSlicedStringTag:
5619 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
5620 offset_ptr,
5621 max_chars);
5622 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005623 default:
5624 break;
5625 }
5626
5627 UNREACHABLE();
5628 return;
5629}
5630
5631
5632const unibrow::byte* String::ReadBlock(String* input,
5633 unibrow::byte* util_buffer,
5634 unsigned capacity,
5635 unsigned* remaining,
5636 unsigned* offset_ptr) {
5637 ASSERT(*offset_ptr <= (unsigned)input->length());
5638 unsigned chars = input->length() - *offset_ptr;
5639 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5640 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5641 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5642 *remaining = rbb.remaining;
5643 return answer;
5644}
5645
5646
5647const unibrow::byte* String::ReadBlock(String** raw_input,
5648 unibrow::byte* util_buffer,
5649 unsigned capacity,
5650 unsigned* remaining,
5651 unsigned* offset_ptr) {
5652 Handle<String> input(raw_input);
5653 ASSERT(*offset_ptr <= (unsigned)input->length());
5654 unsigned chars = input->length() - *offset_ptr;
5655 if (chars > capacity) chars = capacity;
5656 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5657 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5658 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5659 *remaining = rbb.remaining;
5660 return rbb.util_buffer;
5661}
5662
5663
5664// This will iterate unless the block of string data spans two 'halves' of
5665// a ConsString, in which case it will recurse. Since the block of string
5666// data to be read has a maximum size this limits the maximum recursion
5667// depth to something sane. Since C++ does not have tail call recursion
5668// elimination, the iteration must be explicit.
5669void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5670 unsigned* offset_ptr,
5671 unsigned max_chars) {
5672 ConsString* current = this;
5673 unsigned offset = *offset_ptr;
5674 int offset_correction = 0;
5675
5676 while (true) {
5677 String* left = current->first();
5678 unsigned left_length = (unsigned)left->length();
5679 if (left_length > offset &&
5680 max_chars <= left_length - offset) {
5681 // Left hand side only - iterate unless we have reached the bottom of
5682 // the cons tree.
5683 if (StringShape(left).IsCons()) {
5684 current = ConsString::cast(left);
5685 continue;
5686 } else {
5687 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5688 *offset_ptr = offset + offset_correction;
5689 return;
5690 }
5691 } else if (left_length <= offset) {
5692 // Right hand side only - iterate unless we have reached the bottom of
5693 // the cons tree.
5694 offset -= left_length;
5695 offset_correction += left_length;
5696 String* right = current->second();
5697 if (StringShape(right).IsCons()) {
5698 current = ConsString::cast(right);
5699 continue;
5700 } else {
5701 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5702 *offset_ptr = offset + offset_correction;
5703 return;
5704 }
5705 } else {
5706 // The block to be read spans two sides of the ConsString, so we recurse.
5707 // First recurse on the left.
5708 max_chars -= left_length - offset;
5709 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5710 // We may have reached the max or there may not have been enough space
5711 // in the buffer for the characters in the left hand side.
5712 if (offset == left_length) {
5713 // Recurse on the right.
5714 String* right = String::cast(current->second());
5715 offset -= left_length;
5716 offset_correction += left_length;
5717 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5718 }
5719 *offset_ptr = offset + offset_correction;
5720 return;
5721 }
5722 }
5723}
5724
5725
Steve Blocka7e24c12009-10-30 11:49:00 +00005726uint16_t ConsString::ConsStringGet(int index) {
5727 ASSERT(index >= 0 && index < this->length());
5728
5729 // Check for a flattened cons string
5730 if (second()->length() == 0) {
5731 String* left = first();
5732 return left->Get(index);
5733 }
5734
5735 String* string = String::cast(this);
5736
5737 while (true) {
5738 if (StringShape(string).IsCons()) {
5739 ConsString* cons_string = ConsString::cast(string);
5740 String* left = cons_string->first();
5741 if (left->length() > index) {
5742 string = left;
5743 } else {
5744 index -= left->length();
5745 string = cons_string->second();
5746 }
5747 } else {
5748 return string->Get(index);
5749 }
5750 }
5751
5752 UNREACHABLE();
5753 return 0;
5754}
5755
5756
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005757uint16_t SlicedString::SlicedStringGet(int index) {
5758 return parent()->Get(offset() + index);
5759}
5760
5761
5762const unibrow::byte* SlicedString::SlicedStringReadBlock(
5763 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
5764 unsigned offset = this->offset();
5765 *offset_ptr += offset;
5766 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
5767 buffer, offset_ptr, chars);
5768 *offset_ptr -= offset;
5769 return answer;
5770}
5771
5772
5773void SlicedString::SlicedStringReadBlockIntoBuffer(
5774 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
5775 unsigned offset = this->offset();
5776 *offset_ptr += offset;
5777 String::ReadBlockIntoBuffer(String::cast(parent()),
5778 buffer, offset_ptr, chars);
5779 *offset_ptr -= offset;
5780}
5781
Steve Blocka7e24c12009-10-30 11:49:00 +00005782template <typename sinkchar>
5783void String::WriteToFlat(String* src,
5784 sinkchar* sink,
5785 int f,
5786 int t) {
5787 String* source = src;
5788 int from = f;
5789 int to = t;
5790 while (true) {
5791 ASSERT(0 <= from && from <= to && to <= source->length());
5792 switch (StringShape(source).full_representation_tag()) {
5793 case kAsciiStringTag | kExternalStringTag: {
5794 CopyChars(sink,
5795 ExternalAsciiString::cast(source)->resource()->data() + from,
5796 to - from);
5797 return;
5798 }
5799 case kTwoByteStringTag | kExternalStringTag: {
5800 const uc16* data =
5801 ExternalTwoByteString::cast(source)->resource()->data();
5802 CopyChars(sink,
5803 data + from,
5804 to - from);
5805 return;
5806 }
5807 case kAsciiStringTag | kSeqStringTag: {
5808 CopyChars(sink,
5809 SeqAsciiString::cast(source)->GetChars() + from,
5810 to - from);
5811 return;
5812 }
5813 case kTwoByteStringTag | kSeqStringTag: {
5814 CopyChars(sink,
5815 SeqTwoByteString::cast(source)->GetChars() + from,
5816 to - from);
5817 return;
5818 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005819 case kAsciiStringTag | kConsStringTag:
5820 case kTwoByteStringTag | kConsStringTag: {
5821 ConsString* cons_string = ConsString::cast(source);
5822 String* first = cons_string->first();
5823 int boundary = first->length();
5824 if (to - boundary >= boundary - from) {
5825 // Right hand side is longer. Recurse over left.
5826 if (from < boundary) {
5827 WriteToFlat(first, sink, from, boundary);
5828 sink += boundary - from;
5829 from = 0;
5830 } else {
5831 from -= boundary;
5832 }
5833 to -= boundary;
5834 source = cons_string->second();
5835 } else {
5836 // Left hand side is longer. Recurse over right.
5837 if (to > boundary) {
5838 String* second = cons_string->second();
5839 WriteToFlat(second,
5840 sink + boundary - from,
5841 0,
5842 to - boundary);
5843 to = boundary;
5844 }
5845 source = first;
5846 }
5847 break;
5848 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005849 case kAsciiStringTag | kSlicedStringTag:
5850 case kTwoByteStringTag | kSlicedStringTag: {
5851 SlicedString* slice = SlicedString::cast(source);
5852 unsigned offset = slice->offset();
5853 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
5854 return;
5855 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005856 }
5857 }
5858}
5859
5860
Steve Blocka7e24c12009-10-30 11:49:00 +00005861template <typename IteratorA, typename IteratorB>
5862static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5863 // General slow case check. We know that the ia and ib iterators
5864 // have the same length.
5865 while (ia->has_more()) {
5866 uc32 ca = ia->GetNext();
5867 uc32 cb = ib->GetNext();
5868 if (ca != cb)
5869 return false;
5870 }
5871 return true;
5872}
5873
5874
5875// Compares the contents of two strings by reading and comparing
5876// int-sized blocks of characters.
5877template <typename Char>
5878static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5879 int length = a.length();
5880 ASSERT_EQ(length, b.length());
5881 const Char* pa = a.start();
5882 const Char* pb = b.start();
5883 int i = 0;
5884#ifndef V8_HOST_CAN_READ_UNALIGNED
5885 // If this architecture isn't comfortable reading unaligned ints
5886 // then we have to check that the strings are aligned before
5887 // comparing them blockwise.
5888 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5889 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5890 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5891 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5892#endif
5893 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5894 int endpoint = length - kStepSize;
5895 // Compare blocks until we reach near the end of the string.
5896 for (; i <= endpoint; i += kStepSize) {
5897 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5898 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5899 if (wa != wb) {
5900 return false;
5901 }
5902 }
5903#ifndef V8_HOST_CAN_READ_UNALIGNED
5904 }
5905#endif
5906 // Compare the remaining characters that didn't fit into a block.
5907 for (; i < length; i++) {
5908 if (a[i] != b[i]) {
5909 return false;
5910 }
5911 }
5912 return true;
5913}
5914
5915
Steve Blocka7e24c12009-10-30 11:49:00 +00005916template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005917static inline bool CompareStringContentsPartial(Isolate* isolate,
5918 IteratorA* ia,
5919 String* b) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005920 String::FlatContent content = b->GetFlatContent();
5921 if (content.IsFlat()) {
5922 if (content.IsAscii()) {
5923 VectorIterator<char> ib(content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005924 return CompareStringContents(ia, &ib);
5925 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005926 VectorIterator<uc16> ib(content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005927 return CompareStringContents(ia, &ib);
5928 }
5929 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005930 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5931 return CompareStringContents(ia,
5932 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005933 }
5934}
5935
5936
Steve Blocka7e24c12009-10-30 11:49:00 +00005937bool String::SlowEquals(String* other) {
5938 // Fast check: negative check with lengths.
5939 int len = length();
5940 if (len != other->length()) return false;
5941 if (len == 0) return true;
5942
5943 // Fast check: if hash code is computed for both strings
5944 // a fast negative check can be performed.
5945 if (HasHashCode() && other->HasHashCode()) {
5946 if (Hash() != other->Hash()) return false;
5947 }
5948
Leon Clarkef7060e22010-06-03 12:02:55 +01005949 // We know the strings are both non-empty. Compare the first chars
5950 // before we try to flatten the strings.
5951 if (this->Get(0) != other->Get(0)) return false;
5952
5953 String* lhs = this->TryFlattenGetString();
5954 String* rhs = other->TryFlattenGetString();
5955
5956 if (StringShape(lhs).IsSequentialAscii() &&
5957 StringShape(rhs).IsSequentialAscii()) {
5958 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5959 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005960 return CompareRawStringContents(Vector<const char>(str1, len),
5961 Vector<const char>(str2, len));
5962 }
5963
Steve Block44f0eee2011-05-26 01:26:41 +01005964 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005965 String::FlatContent lhs_content = lhs->GetFlatContent();
5966 String::FlatContent rhs_content = rhs->GetFlatContent();
5967 if (lhs_content.IsFlat()) {
5968 if (lhs_content.IsAscii()) {
5969 Vector<const char> vec1 = lhs_content.ToAsciiVector();
5970 if (rhs_content.IsFlat()) {
5971 if (rhs_content.IsAscii()) {
5972 Vector<const char> vec2 = rhs_content.ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005973 return CompareRawStringContents(vec1, vec2);
5974 } else {
5975 VectorIterator<char> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005976 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005977 return CompareStringContents(&buf1, &ib);
5978 }
5979 } else {
5980 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005981 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5982 return CompareStringContents(&buf1,
5983 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005984 }
5985 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005986 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
5987 if (rhs_content.IsFlat()) {
5988 if (rhs_content.IsAscii()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005989 VectorIterator<uc16> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005990 VectorIterator<char> ib(rhs_content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005991 return CompareStringContents(&buf1, &ib);
5992 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005993 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005994 return CompareRawStringContents(vec1, vec2);
5995 }
5996 } else {
5997 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005998 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5999 return CompareStringContents(&buf1,
6000 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006001 }
6002 }
6003 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006004 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6005 return CompareStringContentsPartial(isolate,
6006 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00006007 }
6008}
6009
6010
6011bool String::MarkAsUndetectable() {
6012 if (StringShape(this).IsSymbol()) return false;
6013
6014 Map* map = this->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006015 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01006016 if (map == heap->string_map()) {
6017 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006018 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01006019 } else if (map == heap->ascii_string_map()) {
6020 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006021 return true;
6022 }
6023 // Rest cannot be marked as undetectable
6024 return false;
6025}
6026
6027
6028bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01006029 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006030 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006031 Access<UnicodeCache::Utf8Decoder>
6032 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00006033 decoder->Reset(str.start(), str.length());
6034 int i;
6035 for (i = 0; i < slen && decoder->has_more(); i++) {
6036 uc32 r = decoder->GetNext();
6037 if (Get(i) != r) return false;
6038 }
6039 return i == slen && !decoder->has_more();
6040}
6041
6042
Steve Block9fac8402011-05-12 15:51:54 +01006043bool String::IsAsciiEqualTo(Vector<const char> str) {
6044 int slen = length();
6045 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006046 FlatContent content = GetFlatContent();
6047 if (content.IsAscii()) {
6048 return CompareChars(content.ToAsciiVector().start(),
6049 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006050 }
6051 for (int i = 0; i < slen; i++) {
6052 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01006053 }
6054 return true;
6055}
6056
6057
6058bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6059 int slen = length();
6060 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006061 FlatContent content = GetFlatContent();
6062 if (content.IsTwoByte()) {
6063 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006064 }
Steve Block9fac8402011-05-12 15:51:54 +01006065 for (int i = 0; i < slen; i++) {
6066 if (Get(i) != str[i]) return false;
6067 }
6068 return true;
6069}
6070
6071
Steve Blocka7e24c12009-10-30 11:49:00 +00006072uint32_t String::ComputeAndSetHash() {
6073 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006074 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006075
Steve Block6ded16b2010-05-10 14:33:55 +01006076 const int len = length();
6077
Steve Blocka7e24c12009-10-30 11:49:00 +00006078 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01006079 uint32_t field = 0;
6080 if (StringShape(this).IsSequentialAscii()) {
6081 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
6082 } else if (StringShape(this).IsSequentialTwoByte()) {
6083 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
6084 } else {
6085 StringInputBuffer buffer(this);
6086 field = ComputeHashField(&buffer, len);
6087 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006088
6089 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00006090 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00006091
6092 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006093 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006094 uint32_t result = field >> kHashShift;
6095 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6096 return result;
6097}
6098
6099
6100bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6101 uint32_t* index,
6102 int length) {
6103 if (length == 0 || length > kMaxArrayIndexSize) return false;
6104 uc32 ch = buffer->GetNext();
6105
6106 // If the string begins with a '0' character, it must only consist
6107 // of it to be a legal array index.
6108 if (ch == '0') {
6109 *index = 0;
6110 return length == 1;
6111 }
6112
6113 // Convert string to uint32 array index; character by character.
6114 int d = ch - '0';
6115 if (d < 0 || d > 9) return false;
6116 uint32_t result = d;
6117 while (buffer->has_more()) {
6118 d = buffer->GetNext() - '0';
6119 if (d < 0 || d > 9) return false;
6120 // Check that the new result is below the 32 bit limit.
6121 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6122 result = (result * 10) + d;
6123 }
6124
6125 *index = result;
6126 return true;
6127}
6128
6129
6130bool String::SlowAsArrayIndex(uint32_t* index) {
6131 if (length() <= kMaxCachedArrayIndexLength) {
6132 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00006133 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006134 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00006135 // Isolate the array index form the full hash field.
6136 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00006137 return true;
6138 } else {
6139 StringInputBuffer buffer(this);
6140 return ComputeArrayIndex(&buffer, index, length());
6141 }
6142}
6143
6144
Iain Merrick9ac36c92010-09-13 15:29:50 +01006145uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006146 // For array indexes mix the length into the hash as an array index could
6147 // be zero.
6148 ASSERT(length > 0);
6149 ASSERT(length <= String::kMaxArrayIndexSize);
6150 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6151 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01006152
6153 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006154 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01006155
6156 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6157 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6158 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006159 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00006160}
6161
6162
6163uint32_t StringHasher::GetHashField() {
6164 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00006165 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006166 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01006167 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00006168 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006169 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006170 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006171 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006172 }
6173}
6174
6175
Steve Blockd0582a62009-12-15 09:54:21 +00006176uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
6177 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006178 StringHasher hasher(length);
6179
6180 // Very long strings have a trivial hash that doesn't inspect the
6181 // string contents.
6182 if (hasher.has_trivial_hash()) {
6183 return hasher.GetHashField();
6184 }
6185
6186 // Do the iterative array index computation as long as there is a
6187 // chance this is an array index.
6188 while (buffer->has_more() && hasher.is_array_index()) {
6189 hasher.AddCharacter(buffer->GetNext());
6190 }
6191
6192 // Process the remaining characters without updating the array
6193 // index.
6194 while (buffer->has_more()) {
6195 hasher.AddCharacterNoIndex(buffer->GetNext());
6196 }
6197
6198 return hasher.GetHashField();
6199}
6200
6201
John Reck59135872010-11-02 12:39:01 -07006202MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01006203 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006204 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01006205 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00006206 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00006207}
6208
6209
6210void String::PrintOn(FILE* file) {
6211 int length = this->length();
6212 for (int i = 0; i < length; i++) {
6213 fprintf(file, "%c", Get(i));
6214 }
6215}
6216
6217
6218void Map::CreateBackPointers() {
6219 DescriptorArray* descriptors = instance_descriptors();
6220 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01006221 if (descriptors->GetType(i) == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01006222 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01006223 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006224 // Get target.
6225 Map* target = Map::cast(descriptors->GetValue(i));
6226#ifdef DEBUG
6227 // Verify target.
6228 Object* source_prototype = prototype();
6229 Object* target_prototype = target->prototype();
6230 ASSERT(source_prototype->IsJSObject() ||
6231 source_prototype->IsMap() ||
6232 source_prototype->IsNull());
6233 ASSERT(target_prototype->IsJSObject() ||
6234 target_prototype->IsNull());
6235 ASSERT(source_prototype->IsMap() ||
6236 source_prototype == target_prototype);
6237#endif
6238 // Point target back to source. set_prototype() will not let us set
6239 // the prototype to a map, as we do here.
6240 *RawField(target, kPrototypeOffset) = this;
6241 }
6242 }
6243}
6244
6245
Steve Block44f0eee2011-05-26 01:26:41 +01006246void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006247 // Live DescriptorArray objects will be marked, so we must use
6248 // low-level accessors to get and modify their data.
6249 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00006250 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6251 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006252 Smi* NullDescriptorDetails =
6253 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
6254 FixedArray* contents = reinterpret_cast<FixedArray*>(
6255 d->get(DescriptorArray::kContentArrayIndex));
6256 ASSERT(contents->length() >= 2);
6257 for (int i = 0; i < contents->length(); i += 2) {
6258 // If the pair (value, details) is a map transition,
6259 // check if the target is live. If not, null the descriptor.
6260 // Also drop the back pointer for that map transition, so that this
6261 // map is not reached again by following a back pointer from a
6262 // non-live object.
6263 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01006264 if (details.type() == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01006265 details.type() == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01006266 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006267 Map* target = reinterpret_cast<Map*>(contents->get(i));
6268 ASSERT(target->IsHeapObject());
6269 if (!target->IsMarked()) {
6270 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01006271 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01006272 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00006273 ASSERT(target->prototype() == this ||
6274 target->prototype() == real_prototype);
6275 // Getter prototype() is read-only, set_prototype() has side effects.
6276 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6277 }
6278 }
6279 }
6280}
6281
6282
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006283int Map::Hash() {
6284 // For performance reasons we only hash the 3 most variable fields of a map:
6285 // constructor, prototype and bit_field2.
6286
6287 // Shift away the tag.
6288 int hash = (static_cast<uint32_t>(
6289 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6290
6291 // XOR-ing the prototype and constructor directly yields too many zero bits
6292 // when the two pointers are close (which is fairly common).
6293 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6294 hash ^= (static_cast<uint32_t>(
6295 reinterpret_cast<uintptr_t>(prototype())) << 2);
6296
6297 return hash ^ (hash >> 16) ^ bit_field2();
6298}
6299
6300
6301bool Map::EquivalentToForNormalization(Map* other,
6302 PropertyNormalizationMode mode) {
6303 return
6304 constructor() == other->constructor() &&
6305 prototype() == other->prototype() &&
6306 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6307 0 :
6308 other->inobject_properties()) &&
6309 instance_type() == other->instance_type() &&
6310 bit_field() == other->bit_field() &&
6311 bit_field2() == other->bit_field2() &&
6312 (bit_field3() & ~(1<<Map::kIsShared)) ==
6313 (other->bit_field3() & ~(1<<Map::kIsShared));
6314}
6315
6316
Steve Block791712a2010-08-27 10:21:07 +01006317void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6318 // Iterate over all fields in the body but take care in dealing with
6319 // the code entry.
6320 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6321 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6322 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6323}
6324
6325
Ben Murdochb0fe1622011-05-05 13:52:32 +01006326void JSFunction::MarkForLazyRecompilation() {
6327 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01006328 ASSERT(shared()->allows_lazy_compilation() ||
6329 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01006330 Builtins* builtins = GetIsolate()->builtins();
6331 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006332}
6333
6334
Ben Murdochb0fe1622011-05-05 13:52:32 +01006335bool JSFunction::IsInlineable() {
6336 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006337 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006338 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006339 if (!shared_info->script()->IsScript()) return false;
6340 if (shared_info->optimization_disabled()) return false;
6341 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006342 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6343 // If we never ran this (unlikely) then lets try to optimize it.
6344 if (code->kind() != Code::FUNCTION) return true;
6345 return code->optimizable();
6346}
6347
6348
Steve Blocka7e24c12009-10-30 11:49:00 +00006349Object* JSFunction::SetInstancePrototype(Object* value) {
6350 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01006351 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006352 if (has_initial_map()) {
6353 initial_map()->set_prototype(value);
6354 } else {
6355 // Put the value in the initial map field until an initial map is
6356 // needed. At that point, a new initial map is created and the
6357 // prototype is put into the initial map where it belongs.
6358 set_prototype_or_initial_map(value);
6359 }
Steve Block44f0eee2011-05-26 01:26:41 +01006360 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00006361 return value;
6362}
6363
6364
John Reck59135872010-11-02 12:39:01 -07006365MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01006366 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00006367 Object* construct_prototype = value;
6368
6369 // If the value is not a JSObject, store the value in the map's
6370 // constructor field so it can be accessed. Also, set the prototype
6371 // used for constructing objects to the original object prototype.
6372 // See ECMA-262 13.2.2.
6373 if (!value->IsJSObject()) {
6374 // Copy the map so this does not affect unrelated functions.
6375 // Remove map transitions because they point to maps with a
6376 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006377 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07006378 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006379 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07006380 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01006381 Map* new_map = Map::cast(new_object);
6382 Heap* heap = new_map->heap();
6383 set_map(new_map);
6384 new_map->set_constructor(value);
6385 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006386 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01006387 heap->isolate()->context()->global_context()->
6388 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00006389 } else {
6390 map()->set_non_instance_prototype(false);
6391 }
6392
6393 return SetInstancePrototype(construct_prototype);
6394}
6395
6396
Steve Block6ded16b2010-05-10 14:33:55 +01006397Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01006398 Context* global_context = context()->global_context();
6399 Map* no_prototype_map = shared()->strict_mode()
6400 ? global_context->strict_mode_function_without_prototype_map()
6401 : global_context->function_without_prototype_map();
6402
6403 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006404 // Be idempotent.
6405 return this;
6406 }
Steve Block44f0eee2011-05-26 01:26:41 +01006407
6408 ASSERT(!shared()->strict_mode() ||
6409 map() == global_context->strict_mode_function_map());
6410 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
6411
6412 set_map(no_prototype_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01006413 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01006414 return this;
6415}
6416
6417
Steve Blocka7e24c12009-10-30 11:49:00 +00006418Object* JSFunction::SetInstanceClassName(String* name) {
6419 shared()->set_instance_class_name(name);
6420 return this;
6421}
6422
6423
Ben Murdochb0fe1622011-05-05 13:52:32 +01006424void JSFunction::PrintName(FILE* out) {
6425 SmartPointer<char> name = shared()->DebugName()->ToCString();
6426 PrintF(out, "%s", *name);
6427}
6428
6429
Steve Blocka7e24c12009-10-30 11:49:00 +00006430Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6431 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6432}
6433
6434
Steve Block44f0eee2011-05-26 01:26:41 +01006435MaybeObject* Oddball::Initialize(const char* to_string,
6436 Object* to_number,
6437 byte kind) {
John Reck59135872010-11-02 12:39:01 -07006438 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01006439 { MaybeObject* maybe_symbol =
6440 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07006441 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6442 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006443 set_to_string(String::cast(symbol));
6444 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01006445 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00006446 return this;
6447}
6448
6449
Ben Murdochf87a2032010-10-22 12:50:53 +01006450String* SharedFunctionInfo::DebugName() {
6451 Object* n = name();
6452 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6453 return String::cast(n);
6454}
6455
6456
Steve Blocka7e24c12009-10-30 11:49:00 +00006457bool SharedFunctionInfo::HasSourceCode() {
6458 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01006459 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00006460}
6461
6462
6463Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01006464 Isolate* isolate = GetIsolate();
6465 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6466 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006467 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01006468 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00006469 start_position(), end_position());
6470}
6471
6472
Ben Murdochb0fe1622011-05-05 13:52:32 +01006473int SharedFunctionInfo::SourceSize() {
6474 return end_position() - start_position();
6475}
6476
6477
Steve Blocka7e24c12009-10-30 11:49:00 +00006478int SharedFunctionInfo::CalculateInstanceSize() {
6479 int instance_size =
6480 JSObject::kHeaderSize +
6481 expected_nof_properties() * kPointerSize;
6482 if (instance_size > JSObject::kMaxInstanceSize) {
6483 instance_size = JSObject::kMaxInstanceSize;
6484 }
6485 return instance_size;
6486}
6487
6488
6489int SharedFunctionInfo::CalculateInObjectProperties() {
6490 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6491}
6492
6493
Andrei Popescu402d9372010-02-26 13:31:12 +00006494bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6495 // Check the basic conditions for generating inline constructor code.
6496 if (!FLAG_inline_new
6497 || !has_only_simple_this_property_assignments()
6498 || this_property_assignments_count() == 0) {
6499 return false;
6500 }
6501
6502 // If the prototype is null inline constructors cause no problems.
6503 if (!prototype->IsJSObject()) {
6504 ASSERT(prototype->IsNull());
6505 return true;
6506 }
6507
Ben Murdoch8b112d22011-06-08 16:22:53 +01006508 Heap* heap = GetHeap();
6509
Andrei Popescu402d9372010-02-26 13:31:12 +00006510 // Traverse the proposed prototype chain looking for setters for properties of
6511 // the same names as are set by the inline constructor.
6512 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01006513 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00006514 obj = obj->GetPrototype()) {
6515 JSObject* js_object = JSObject::cast(obj);
6516 for (int i = 0; i < this_property_assignments_count(); i++) {
6517 LookupResult result;
6518 String* name = GetThisPropertyAssignmentName(i);
6519 js_object->LocalLookupRealNamedProperty(name, &result);
6520 if (result.IsProperty() && result.type() == CALLBACKS) {
6521 return false;
6522 }
6523 }
6524 }
6525
6526 return true;
6527}
6528
6529
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006530void SharedFunctionInfo::ForbidInlineConstructor() {
6531 set_compiler_hints(BooleanBit::set(compiler_hints(),
6532 kHasOnlySimpleThisPropertyAssignments,
6533 false));
6534}
6535
6536
Steve Blocka7e24c12009-10-30 11:49:00 +00006537void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00006538 bool only_simple_this_property_assignments,
6539 FixedArray* assignments) {
6540 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006541 kHasOnlySimpleThisPropertyAssignments,
6542 only_simple_this_property_assignments));
6543 set_this_property_assignments(assignments);
6544 set_this_property_assignments_count(assignments->length() / 3);
6545}
6546
6547
6548void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01006549 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006550 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006551 kHasOnlySimpleThisPropertyAssignments,
6552 false));
Steve Block44f0eee2011-05-26 01:26:41 +01006553 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006554 set_this_property_assignments_count(0);
6555}
6556
6557
6558String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6559 Object* obj = this_property_assignments();
6560 ASSERT(obj->IsFixedArray());
6561 ASSERT(index < this_property_assignments_count());
6562 obj = FixedArray::cast(obj)->get(index * 3);
6563 ASSERT(obj->IsString());
6564 return String::cast(obj);
6565}
6566
6567
6568bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6569 Object* obj = this_property_assignments();
6570 ASSERT(obj->IsFixedArray());
6571 ASSERT(index < this_property_assignments_count());
6572 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6573 return Smi::cast(obj)->value() != -1;
6574}
6575
6576
6577int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6578 ASSERT(IsThisPropertyAssignmentArgument(index));
6579 Object* obj =
6580 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6581 return Smi::cast(obj)->value();
6582}
6583
6584
6585Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6586 ASSERT(!IsThisPropertyAssignmentArgument(index));
6587 Object* obj =
6588 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6589 return obj;
6590}
6591
6592
Steve Blocka7e24c12009-10-30 11:49:00 +00006593// Support function for printing the source code to a StringStream
6594// without any allocation in the heap.
6595void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6596 int max_length) {
6597 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006598 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006599 accumulator->Add("<No Source>");
6600 return;
6601 }
6602
Steve Blockd0582a62009-12-15 09:54:21 +00006603 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00006604 // Don't use String::cast because we don't want more assertion errors while
6605 // we are already creating a stack dump.
6606 String* script_source =
6607 reinterpret_cast<String*>(Script::cast(script())->source());
6608
6609 if (!script_source->LooksValid()) {
6610 accumulator->Add("<Invalid Source>");
6611 return;
6612 }
6613
6614 if (!is_toplevel()) {
6615 accumulator->Add("function ");
6616 Object* name = this->name();
6617 if (name->IsString() && String::cast(name)->length() > 0) {
6618 accumulator->PrintName(name);
6619 }
6620 }
6621
6622 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006623 if (len <= max_length || max_length < 0) {
6624 accumulator->Put(script_source, start_position(), end_position());
6625 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006626 accumulator->Put(script_source,
6627 start_position(),
6628 start_position() + max_length);
6629 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006630 }
6631}
6632
6633
Ben Murdochb0fe1622011-05-05 13:52:32 +01006634static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6635 if (code->instruction_size() != recompiled->instruction_size()) return false;
6636 ByteArray* code_relocation = code->relocation_info();
6637 ByteArray* recompiled_relocation = recompiled->relocation_info();
6638 int length = code_relocation->length();
6639 if (length != recompiled_relocation->length()) return false;
6640 int compare = memcmp(code_relocation->GetDataStartAddress(),
6641 recompiled_relocation->GetDataStartAddress(),
6642 length);
6643 return compare == 0;
6644}
6645
6646
6647void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6648 ASSERT(!has_deoptimization_support());
6649 AssertNoAllocation no_allocation;
6650 Code* code = this->code();
6651 if (IsCodeEquivalent(code, recompiled)) {
6652 // Copy the deoptimization data from the recompiled code.
6653 code->set_deoptimization_data(recompiled->deoptimization_data());
6654 code->set_has_deoptimization_support(true);
6655 } else {
6656 // TODO(3025757): In case the recompiled isn't equivalent to the
6657 // old code, we have to replace it. We should try to avoid this
6658 // altogether because it flushes valuable type feedback by
6659 // effectively resetting all IC state.
6660 set_code(recompiled);
6661 }
6662 ASSERT(has_deoptimization_support());
6663}
6664
6665
Ben Murdoch257744e2011-11-30 15:57:28 +00006666void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6667 // Disable optimization for the shared function info and mark the
6668 // code as non-optimizable. The marker on the shared function info
6669 // is there because we flush non-optimized code thereby loosing the
6670 // non-optimizable information for the code. When the code is
6671 // regenerated and set on the shared function info it is marked as
6672 // non-optimizable if optimization is disabled for the shared
6673 // function info.
6674 set_optimization_disabled(true);
6675 // Code should be the lazy compilation stub or else unoptimized. If the
6676 // latter, disable optimization for the code too.
6677 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6678 if (code()->kind() == Code::FUNCTION) {
6679 code()->set_optimizable(false);
6680 }
6681 if (FLAG_trace_opt) {
6682 PrintF("[disabled optimization for: ");
6683 function->PrintName();
6684 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6685 }
6686}
6687
6688
Ben Murdochb0fe1622011-05-05 13:52:32 +01006689bool SharedFunctionInfo::VerifyBailoutId(int id) {
6690 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6691 // we are always bailing out on ARM.
6692
6693 ASSERT(id != AstNode::kNoNumber);
6694 Code* unoptimized = code();
6695 DeoptimizationOutputData* data =
6696 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6697 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6698 USE(ignore);
6699 return true; // Return true if there was no ASSERT.
6700}
6701
6702
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006703void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6704 ASSERT(!IsInobjectSlackTrackingInProgress());
6705
6706 // Only initiate the tracking the first time.
6707 if (live_objects_may_exist()) return;
6708 set_live_objects_may_exist(true);
6709
6710 // No tracking during the snapshot construction phase.
6711 if (Serializer::enabled()) return;
6712
6713 if (map->unused_property_fields() == 0) return;
6714
6715 // Nonzero counter is a leftover from the previous attempt interrupted
6716 // by GC, keep it.
6717 if (construction_count() == 0) {
6718 set_construction_count(kGenerousAllocationCount);
6719 }
6720 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006721 Builtins* builtins = map->heap()->isolate()->builtins();
6722 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006723 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006724 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006725}
6726
6727
6728// Called from GC, hence reinterpret_cast and unchecked accessors.
6729void SharedFunctionInfo::DetachInitialMap() {
6730 Map* map = reinterpret_cast<Map*>(initial_map());
6731
6732 // Make the map remember to restore the link if it survives the GC.
6733 map->set_bit_field2(
6734 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6735
6736 // Undo state changes made by StartInobjectTracking (except the
6737 // construction_count). This way if the initial map does not survive the GC
6738 // then StartInobjectTracking will be called again the next time the
6739 // constructor is called. The countdown will continue and (possibly after
6740 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006741 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6742 Builtins* builtins = map->heap()->isolate()->builtins();
6743 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006744 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006745 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006746 // It is safe to clear the flag: it will be set again if the map is live.
6747 set_live_objects_may_exist(false);
6748}
6749
6750
6751// Called from GC, hence reinterpret_cast and unchecked accessors.
6752void SharedFunctionInfo::AttachInitialMap(Map* map) {
6753 map->set_bit_field2(
6754 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6755
6756 // Resume inobject slack tracking.
6757 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006758 Builtins* builtins = map->heap()->isolate()->builtins();
6759 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006760 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006761 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006762 // The map survived the gc, so there may be objects referencing it.
6763 set_live_objects_may_exist(true);
6764}
6765
6766
6767static void GetMinInobjectSlack(Map* map, void* data) {
6768 int slack = map->unused_property_fields();
6769 if (*reinterpret_cast<int*>(data) > slack) {
6770 *reinterpret_cast<int*>(data) = slack;
6771 }
6772}
6773
6774
6775static void ShrinkInstanceSize(Map* map, void* data) {
6776 int slack = *reinterpret_cast<int*>(data);
6777 map->set_inobject_properties(map->inobject_properties() - slack);
6778 map->set_unused_property_fields(map->unused_property_fields() - slack);
6779 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6780
6781 // Visitor id might depend on the instance size, recalculate it.
6782 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6783}
6784
6785
6786void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6787 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6788 Map* map = Map::cast(initial_map());
6789
Steve Block44f0eee2011-05-26 01:26:41 +01006790 Heap* heap = map->heap();
6791 set_initial_map(heap->undefined_value());
6792 Builtins* builtins = heap->isolate()->builtins();
6793 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006794 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006795 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006796
6797 int slack = map->unused_property_fields();
6798 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6799 if (slack != 0) {
6800 // Resize the initial map and all maps in its transition tree.
6801 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006802
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006803 // Give the correct expected_nof_properties to initial maps created later.
6804 ASSERT(expected_nof_properties() >= slack);
6805 set_expected_nof_properties(expected_nof_properties() - slack);
6806 }
6807}
6808
6809
Steve Blocka7e24c12009-10-30 11:49:00 +00006810void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6811 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6812 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6813 Object* old_target = target;
6814 VisitPointer(&target);
6815 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6816}
6817
6818
Steve Block791712a2010-08-27 10:21:07 +01006819void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6820 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6821 Object* old_code = code;
6822 VisitPointer(&code);
6823 if (code != old_code) {
6824 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6825 }
6826}
6827
6828
Ben Murdochb0fe1622011-05-05 13:52:32 +01006829void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6830 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6831 Object* cell = rinfo->target_cell();
6832 Object* old_cell = cell;
6833 VisitPointer(&cell);
6834 if (cell != old_cell) {
6835 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6836 }
6837}
6838
6839
Steve Blocka7e24c12009-10-30 11:49:00 +00006840void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006841 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6842 rinfo->IsPatchedReturnSequence()) ||
6843 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6844 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006845 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6846 Object* old_target = target;
6847 VisitPointer(&target);
6848 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6849}
6850
6851
Ben Murdochb0fe1622011-05-05 13:52:32 +01006852void Code::InvalidateRelocation() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006853 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006854}
6855
6856
Steve Blockd0582a62009-12-15 09:54:21 +00006857void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006858 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6859 it.rinfo()->apply(delta);
6860 }
6861 CPU::FlushICache(instruction_start(), instruction_size());
6862}
6863
6864
6865void Code::CopyFrom(const CodeDesc& desc) {
6866 // copy code
6867 memmove(instruction_start(), desc.buffer, desc.instr_size);
6868
Steve Blocka7e24c12009-10-30 11:49:00 +00006869 // copy reloc info
6870 memmove(relocation_start(),
6871 desc.buffer + desc.buffer_size - desc.reloc_size,
6872 desc.reloc_size);
6873
6874 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006875 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006876 int mode_mask = RelocInfo::kCodeTargetMask |
6877 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006878 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006879 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006880 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006881 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6882 RelocInfo::Mode mode = it.rinfo()->rmode();
6883 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006884 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006885 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006886 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006887 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006888 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006889 } else if (RelocInfo::IsCodeTarget(mode)) {
6890 // rewrite code handles in inline cache targets to direct
6891 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006892 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006893 Code* code = Code::cast(*p);
6894 it.rinfo()->set_target_address(code->instruction_start());
6895 } else {
6896 it.rinfo()->apply(delta);
6897 }
6898 }
6899 CPU::FlushICache(instruction_start(), instruction_size());
6900}
6901
6902
6903// Locate the source position which is closest to the address in the code. This
6904// is using the source position information embedded in the relocation info.
6905// The position returned is relative to the beginning of the script where the
6906// source for this function is found.
6907int Code::SourcePosition(Address pc) {
6908 int distance = kMaxInt;
6909 int position = RelocInfo::kNoPosition; // Initially no position found.
6910 // Run through all the relocation info to find the best matching source
6911 // position. All the code needs to be considered as the sequence of the
6912 // instructions in the code does not necessarily follow the same order as the
6913 // source.
6914 RelocIterator it(this, RelocInfo::kPositionMask);
6915 while (!it.done()) {
6916 // Only look at positions after the current pc.
6917 if (it.rinfo()->pc() < pc) {
6918 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006919
6920 int dist = static_cast<int>(pc - it.rinfo()->pc());
6921 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006922 // If this position is closer than the current candidate or if it has the
6923 // same distance as the current candidate and the position is higher then
6924 // this position is the new candidate.
6925 if ((dist < distance) ||
6926 (dist == distance && pos > position)) {
6927 position = pos;
6928 distance = dist;
6929 }
6930 }
6931 it.next();
6932 }
6933 return position;
6934}
6935
6936
6937// Same as Code::SourcePosition above except it only looks for statement
6938// positions.
6939int Code::SourceStatementPosition(Address pc) {
6940 // First find the position as close as possible using all position
6941 // information.
6942 int position = SourcePosition(pc);
6943 // Now find the closest statement position before the position.
6944 int statement_position = 0;
6945 RelocIterator it(this, RelocInfo::kPositionMask);
6946 while (!it.done()) {
6947 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006948 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006949 if (statement_position < p && p <= position) {
6950 statement_position = p;
6951 }
6952 }
6953 it.next();
6954 }
6955 return statement_position;
6956}
6957
6958
Ben Murdochb8e0da22011-05-16 14:20:40 +01006959SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006960 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006961 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006962}
6963
6964
6965void Code::SetNoStackCheckTable() {
6966 // Indicate the absence of a stack-check table by a table start after the
6967 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006968 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006969}
6970
6971
6972Map* Code::FindFirstMap() {
6973 ASSERT(is_inline_cache_stub());
6974 AssertNoAllocation no_allocation;
6975 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6976 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6977 RelocInfo* info = it.rinfo();
6978 Object* object = info->target_object();
6979 if (object->IsMap()) return Map::cast(object);
6980 }
6981 return NULL;
6982}
6983
6984
Steve Blocka7e24c12009-10-30 11:49:00 +00006985#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006986
Ben Murdochb0fe1622011-05-05 13:52:32 +01006987void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6988 disasm::NameConverter converter;
6989 int deopt_count = DeoptCount();
6990 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6991 if (0 == deopt_count) return;
6992
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006993 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc",
6994 FLAG_print_code_verbose ? "commands" : "");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006995 for (int i = 0; i < deopt_count; i++) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006996 PrintF(out, "%6d %6d %6d",
6997 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006998
6999 if (!FLAG_print_code_verbose) {
7000 PrintF(out, "\n");
7001 continue;
7002 }
7003 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01007004 int translation_index = TranslationIndex(i)->value();
7005 TranslationIterator iterator(TranslationByteArray(), translation_index);
7006 Translation::Opcode opcode =
7007 static_cast<Translation::Opcode>(iterator.Next());
7008 ASSERT(Translation::BEGIN == opcode);
7009 int frame_count = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007010 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
7011 frame_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007012
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007013 while (iterator.HasNext() &&
7014 Translation::BEGIN !=
7015 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
7016 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
7017
7018 switch (opcode) {
7019 case Translation::BEGIN:
7020 UNREACHABLE();
7021 break;
7022
7023 case Translation::FRAME: {
7024 int ast_id = iterator.Next();
7025 int function_id = iterator.Next();
7026 JSFunction* function =
7027 JSFunction::cast(LiteralArray()->get(function_id));
7028 unsigned height = iterator.Next();
7029 PrintF(out, "{ast_id=%d, \nfunction=", ast_id);
7030 function->PrintName(out);
7031 PrintF(out, ", height=%u}", height);
7032 break;
7033 }
7034
7035 case Translation::DUPLICATE:
7036 break;
7037
7038 case Translation::REGISTER: {
7039 int reg_code = iterator.Next();
7040 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7041 break;
7042 }
7043
7044 case Translation::INT32_REGISTER: {
7045 int reg_code = iterator.Next();
7046 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7047 break;
7048 }
7049
7050 case Translation::DOUBLE_REGISTER: {
7051 int reg_code = iterator.Next();
7052 PrintF(out, "{input=%s}",
7053 DoubleRegister::AllocationIndexToString(reg_code));
7054 break;
7055 }
7056
7057 case Translation::STACK_SLOT: {
7058 int input_slot_index = iterator.Next();
7059 PrintF(out, "{input=%d}", input_slot_index);
7060 break;
7061 }
7062
7063 case Translation::INT32_STACK_SLOT: {
7064 int input_slot_index = iterator.Next();
7065 PrintF(out, "{input=%d}", input_slot_index);
7066 break;
7067 }
7068
7069 case Translation::DOUBLE_STACK_SLOT: {
7070 int input_slot_index = iterator.Next();
7071 PrintF(out, "{input=%d}", input_slot_index);
7072 break;
7073 }
7074
7075 case Translation::LITERAL: {
7076 unsigned literal_index = iterator.Next();
7077 PrintF(out, "{literal_id=%u}", literal_index);
7078 break;
7079 }
7080
7081 case Translation::ARGUMENTS_OBJECT:
7082 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007083 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007084 PrintF(out, "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007085 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007086 }
7087}
7088
7089
7090void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7091 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
7092 this->DeoptPoints());
7093 if (this->DeoptPoints() == 0) return;
7094
7095 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7096 for (int i = 0; i < this->DeoptPoints(); i++) {
7097 int pc_and_state = this->PcAndState(i)->value();
7098 PrintF("%6d %8d %s\n",
7099 this->AstId(i)->value(),
7100 FullCodeGenerator::PcField::decode(pc_and_state),
7101 FullCodeGenerator::State2String(
7102 FullCodeGenerator::StateField::decode(pc_and_state)));
7103 }
7104}
7105
Ben Murdochb0fe1622011-05-05 13:52:32 +01007106
Steve Blocka7e24c12009-10-30 11:49:00 +00007107// Identify kind of code.
7108const char* Code::Kind2String(Kind kind) {
7109 switch (kind) {
7110 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007111 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007112 case STUB: return "STUB";
7113 case BUILTIN: return "BUILTIN";
7114 case LOAD_IC: return "LOAD_IC";
7115 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7116 case STORE_IC: return "STORE_IC";
7117 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7118 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007119 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00007120 case UNARY_OP_IC: return "UNARY_OP_IC";
7121 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007122 case COMPARE_IC: return "COMPARE_IC";
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007123 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00007124 }
7125 UNREACHABLE();
7126 return NULL;
7127}
7128
7129
7130const char* Code::ICState2String(InlineCacheState state) {
7131 switch (state) {
7132 case UNINITIALIZED: return "UNINITIALIZED";
7133 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7134 case MONOMORPHIC: return "MONOMORPHIC";
7135 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7136 case MEGAMORPHIC: return "MEGAMORPHIC";
7137 case DEBUG_BREAK: return "DEBUG_BREAK";
7138 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7139 }
7140 UNREACHABLE();
7141 return NULL;
7142}
7143
7144
7145const char* Code::PropertyType2String(PropertyType type) {
7146 switch (type) {
7147 case NORMAL: return "NORMAL";
7148 case FIELD: return "FIELD";
7149 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7150 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00007151 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00007152 case INTERCEPTOR: return "INTERCEPTOR";
7153 case MAP_TRANSITION: return "MAP_TRANSITION";
Steve Block44f0eee2011-05-26 01:26:41 +01007154 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007155 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7156 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7157 }
7158 UNREACHABLE();
7159 return NULL;
7160}
7161
Ben Murdochb0fe1622011-05-05 13:52:32 +01007162
Steve Block1e0659c2011-05-24 12:43:12 +01007163void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7164 const char* name = NULL;
7165 switch (kind) {
7166 case CALL_IC:
7167 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7168 name = "STRING_INDEX_OUT_OF_BOUNDS";
7169 }
7170 break;
7171 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007172 case KEYED_STORE_IC:
7173 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01007174 name = "STRICT";
7175 }
7176 break;
7177 default:
7178 break;
7179 }
7180 if (name != NULL) {
7181 PrintF(out, "extra_ic_state = %s\n", name);
7182 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007183 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01007184 }
7185}
7186
7187
Ben Murdochb0fe1622011-05-05 13:52:32 +01007188void Code::Disassemble(const char* name, FILE* out) {
7189 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007190 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007191 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01007192 PrintExtraICState(out, kind(), extra_ic_state());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007193 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
Steve Blocka7e24c12009-10-30 11:49:00 +00007194 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007195 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007196 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007197 if (is_call_stub() || is_keyed_call_stub()) {
7198 PrintF(out, "argc = %d\n", arguments_count());
7199 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007200 }
7201 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007202 PrintF(out, "name = %s\n", name);
7203 }
7204 if (kind() == OPTIMIZED_FUNCTION) {
7205 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00007206 }
7207
Ben Murdochb0fe1622011-05-05 13:52:32 +01007208 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7209 Disassembler::Decode(out, this);
7210 PrintF(out, "\n");
7211
Ben Murdochb0fe1622011-05-05 13:52:32 +01007212 if (kind() == FUNCTION) {
7213 DeoptimizationOutputData* data =
7214 DeoptimizationOutputData::cast(this->deoptimization_data());
7215 data->DeoptimizationOutputDataPrint(out);
7216 } else if (kind() == OPTIMIZED_FUNCTION) {
7217 DeoptimizationInputData* data =
7218 DeoptimizationInputData::cast(this->deoptimization_data());
7219 data->DeoptimizationInputDataPrint(out);
7220 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007221 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007222
7223 if (kind() == OPTIMIZED_FUNCTION) {
7224 SafepointTable table(this);
7225 PrintF(out, "Safepoints (size = %u)\n", table.size());
7226 for (unsigned i = 0; i < table.length(); i++) {
7227 unsigned pc_offset = table.GetPcOffset(i);
7228 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
7229 table.PrintEntry(i);
7230 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01007231 SafepointEntry entry = table.GetEntry(i);
7232 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7233 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007234 } else {
7235 PrintF(out, " <none>");
7236 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01007237 if (entry.argument_count() > 0) {
7238 PrintF(out, " argc: %d", entry.argument_count());
7239 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007240 PrintF(out, "\n");
7241 }
7242 PrintF(out, "\n");
7243 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01007244 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007245 // If there is no stack check table, the "table start" will at or after
7246 // (due to alignment) the end of the instruction stream.
7247 if (static_cast<int>(offset) < instruction_size()) {
7248 unsigned* address =
7249 reinterpret_cast<unsigned*>(instruction_start() + offset);
7250 unsigned length = address[0];
7251 PrintF(out, "Stack checks (size = %u)\n", length);
7252 PrintF(out, "ast_id pc_offset\n");
7253 for (unsigned i = 0; i < length; ++i) {
7254 unsigned index = (2 * i) + 1;
7255 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
7256 }
7257 PrintF(out, "\n");
7258 }
7259 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007260
7261 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007262 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7263 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007264}
7265#endif // ENABLE_DISASSEMBLER
7266
7267
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007268static void CopyFastElementsToFast(FixedArray* source,
7269 FixedArray* destination,
7270 WriteBarrierMode mode) {
7271 uint32_t count = static_cast<uint32_t>(source->length());
7272 for (uint32_t i = 0; i < count; ++i) {
7273 destination->set(i, source->get(i), mode);
7274 }
7275}
7276
7277
7278static void CopySlowElementsToFast(NumberDictionary* source,
7279 FixedArray* destination,
7280 WriteBarrierMode mode) {
7281 for (int i = 0; i < source->Capacity(); ++i) {
7282 Object* key = source->KeyAt(i);
7283 if (key->IsNumber()) {
7284 uint32_t entry = static_cast<uint32_t>(key->Number());
7285 destination->set(entry, source->ValueAt(i), mode);
7286 }
7287 }
7288}
7289
7290
John Reck59135872010-11-02 12:39:01 -07007291MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7292 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01007293 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00007294 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007295 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01007296
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007297 // Allocate a new fast elements backing store.
7298 FixedArray* new_elements = NULL;
7299 { Object* object;
7300 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
7301 if (!maybe->ToObject(&object)) return maybe;
7302 new_elements = FixedArray::cast(object);
7303 }
7304
7305 // Find the new map to use for this object if there is a map change.
7306 Map* new_map = NULL;
7307 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
7308 Object* object;
7309 MaybeObject* maybe = map()->GetFastElementsMap();
7310 if (!maybe->ToObject(&object)) return maybe;
7311 new_map = Map::cast(object);
7312 }
7313
7314 switch (GetElementsKind()) {
7315 case FAST_ELEMENTS: {
7316 AssertNoAllocation no_gc;
7317 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7318 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
7319 set_map(new_map);
7320 set_elements(new_elements);
7321 break;
7322 }
7323 case DICTIONARY_ELEMENTS: {
7324 AssertNoAllocation no_gc;
7325 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7326 CopySlowElementsToFast(NumberDictionary::cast(elements()),
7327 new_elements,
7328 mode);
7329 set_map(new_map);
7330 set_elements(new_elements);
7331 break;
7332 }
7333 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7334 AssertNoAllocation no_gc;
7335 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7336 // The object's map and the parameter map are unchanged, the unaliased
7337 // arguments are copied to the new backing store.
7338 FixedArray* parameter_map = FixedArray::cast(elements());
7339 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7340 if (arguments->IsDictionary()) {
7341 CopySlowElementsToFast(NumberDictionary::cast(arguments),
7342 new_elements,
7343 mode);
7344 } else {
7345 CopyFastElementsToFast(arguments, new_elements, mode);
7346 }
7347 parameter_map->set(1, new_elements);
7348 break;
7349 }
7350 case FAST_DOUBLE_ELEMENTS: {
7351 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7352 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7353 // Fill out the new array with this content and array holes.
7354 for (uint32_t i = 0; i < old_length; i++) {
7355 if (!old_elements->is_the_hole(i)) {
7356 Object* obj;
7357 // Objects must be allocated in the old object space, since the
7358 // overall number of HeapNumbers needed for the conversion might
7359 // exceed the capacity of new space, and we would fail repeatedly
7360 // trying to convert the FixedDoubleArray.
7361 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007362 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
7363 TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007364 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7365 // Force write barrier. It's not worth trying to exploit
7366 // elems->GetWriteBarrierMode(), since it requires an
7367 // AssertNoAllocation stack object that would have to be positioned
7368 // after the HeapNumber allocation anyway.
7369 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
7370 }
7371 }
7372 set_map(new_map);
7373 set_elements(new_elements);
7374 break;
7375 }
7376 case EXTERNAL_BYTE_ELEMENTS:
7377 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7378 case EXTERNAL_SHORT_ELEMENTS:
7379 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7380 case EXTERNAL_INT_ELEMENTS:
7381 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7382 case EXTERNAL_FLOAT_ELEMENTS:
7383 case EXTERNAL_DOUBLE_ELEMENTS:
7384 case EXTERNAL_PIXEL_ELEMENTS:
7385 UNREACHABLE();
7386 break;
7387 }
7388
7389 // Update the length if necessary.
7390 if (IsJSArray()) {
7391 JSArray::cast(this)->set_length(Smi::FromInt(length));
7392 }
7393
7394 return new_elements;
7395}
7396
7397
7398MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7399 int capacity,
7400 int length) {
7401 Heap* heap = GetHeap();
7402 // We should never end in here with a pixel or external array.
7403 ASSERT(!HasExternalArrayElements());
7404
John Reck59135872010-11-02 12:39:01 -07007405 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007406 { MaybeObject* maybe_obj =
7407 heap->AllocateUninitializedFixedDoubleArray(capacity);
John Reck59135872010-11-02 12:39:01 -07007408 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7409 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007410 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
Steve Block8defd9f2010-07-08 12:39:36 +01007411
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007412 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
John Reck59135872010-11-02 12:39:01 -07007413 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7414 }
Steve Block8defd9f2010-07-08 12:39:36 +01007415 Map* new_map = Map::cast(obj);
7416
Leon Clarke4515c472010-02-03 11:58:03 +00007417 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00007418 switch (GetElementsKind()) {
7419 case FAST_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007420 elems->Initialize(FixedArray::cast(elements()));
7421 break;
7422 }
7423 case FAST_DOUBLE_ELEMENTS: {
7424 elems->Initialize(FixedDoubleArray::cast(elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007425 break;
7426 }
7427 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007428 elems->Initialize(NumberDictionary::cast(elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007429 break;
7430 }
7431 default:
7432 UNREACHABLE();
7433 break;
7434 }
Steve Block8defd9f2010-07-08 12:39:36 +01007435
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007436 ASSERT(new_map->has_fast_double_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01007437 set_map(new_map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007438 ASSERT(elems->IsFixedDoubleArray());
Steve Blocka7e24c12009-10-30 11:49:00 +00007439 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01007440
7441 if (IsJSArray()) {
7442 JSArray::cast(this)->set_length(Smi::FromInt(length));
7443 }
7444
7445 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00007446}
7447
7448
John Reck59135872010-11-02 12:39:01 -07007449MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007450 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007451 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007452
7453 uint32_t new_length = static_cast<uint32_t>(len->Number());
7454
7455 switch (GetElementsKind()) {
7456 case FAST_ELEMENTS: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007457 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007458 // Make sure we never try to shrink dense arrays into sparse arrays.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007459 ASSERT(static_cast<uint32_t>(
7460 FixedArrayBase::cast(elements())->length()) <= new_length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007461 MaybeObject* result = NormalizeElements();
7462 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007463
7464 // Update length for JSArrays.
7465 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7466 break;
7467 }
7468 case DICTIONARY_ELEMENTS: {
7469 if (IsJSArray()) {
7470 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01007471 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00007472 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7473 JSArray::cast(this)->set_length(len);
7474 }
7475 break;
7476 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007477 case NON_STRICT_ARGUMENTS_ELEMENTS:
7478 UNIMPLEMENTED();
7479 break;
7480 case EXTERNAL_BYTE_ELEMENTS:
7481 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7482 case EXTERNAL_SHORT_ELEMENTS:
7483 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7484 case EXTERNAL_INT_ELEMENTS:
7485 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7486 case EXTERNAL_FLOAT_ELEMENTS:
7487 case EXTERNAL_DOUBLE_ELEMENTS:
7488 case EXTERNAL_PIXEL_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007489 UNREACHABLE();
7490 break;
7491 }
7492 return this;
7493}
7494
7495
John Reck59135872010-11-02 12:39:01 -07007496MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01007497 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007498 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00007499 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00007500 FixedArray* new_elements;
7501 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01007502 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00007503 } else {
John Reck59135872010-11-02 12:39:01 -07007504 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007505 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07007506 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7507 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007508 new_elements = FixedArray::cast(obj);
7509 }
7510 set_elements(new_elements);
7511 return this;
7512}
7513
7514
7515void JSArray::Expand(int required_size) {
7516 Handle<JSArray> self(this);
7517 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
7518 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00007519 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01007520 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00007521 // Can't use this any more now because we may have had a GC!
7522 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7523 self->SetContent(*new_backing);
7524}
7525
7526
Steve Block44f0eee2011-05-26 01:26:41 +01007527static Failure* ArrayLengthRangeError(Heap* heap) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007528 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007529 return heap->isolate()->Throw(
7530 *FACTORY->NewRangeError("invalid_array_length",
7531 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007532}
7533
7534
John Reck59135872010-11-02 12:39:01 -07007535MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007536 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01007537 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00007538
John Reck59135872010-11-02 12:39:01 -07007539 MaybeObject* maybe_smi_length = len->ToSmi();
7540 Object* smi_length = Smi::FromInt(0);
7541 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01007542 const int value = Smi::cast(smi_length)->value();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007543 if (value < 0) return ArrayLengthRangeError(GetHeap());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007544 JSObject::ElementsKind elements_kind = GetElementsKind();
7545 switch (elements_kind) {
7546 case FAST_ELEMENTS:
7547 case FAST_DOUBLE_ELEMENTS: {
7548 int old_capacity = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00007549 if (value <= old_capacity) {
7550 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07007551 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007552 if (elements_kind == FAST_ELEMENTS) {
7553 MaybeObject* maybe_obj = EnsureWritableFastElements();
John Reck59135872010-11-02 12:39:01 -07007554 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7555 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007556 if (2 * value <= old_capacity) {
7557 // If more than half the elements won't be used, trim the array.
7558 if (value == 0) {
7559 initialize_elements();
7560 } else {
7561 Address filler_start;
7562 int filler_size;
7563 if (GetElementsKind() == FAST_ELEMENTS) {
7564 FixedArray* fast_elements = FixedArray::cast(elements());
7565 fast_elements->set_length(value);
7566 filler_start = fast_elements->address() +
7567 FixedArray::OffsetOfElementAt(value);
7568 filler_size = (old_capacity - value) * kPointerSize;
7569 } else {
7570 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7571 FixedDoubleArray* fast_double_elements =
7572 FixedDoubleArray::cast(elements());
7573 fast_double_elements->set_length(value);
7574 filler_start = fast_double_elements->address() +
7575 FixedDoubleArray::OffsetOfElementAt(value);
7576 filler_size = (old_capacity - value) * kDoubleSize;
7577 }
7578 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
7579 }
7580 } else {
7581 // Otherwise, fill the unused tail with holes.
7582 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
7583 if (GetElementsKind() == FAST_ELEMENTS) {
7584 FixedArray* fast_elements = FixedArray::cast(elements());
7585 for (int i = value; i < old_length; i++) {
7586 fast_elements->set_the_hole(i);
7587 }
7588 } else {
7589 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7590 FixedDoubleArray* fast_double_elements =
7591 FixedDoubleArray::cast(elements());
7592 for (int i = value; i < old_length; i++) {
7593 fast_double_elements->set_the_hole(i);
7594 }
7595 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007596 }
Leon Clarke4515c472010-02-03 11:58:03 +00007597 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007598 }
7599 return this;
7600 }
7601 int min = NewElementsCapacity(old_capacity);
7602 int new_capacity = value > min ? value : min;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007603 if (!ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007604 MaybeObject* result;
7605 if (GetElementsKind() == FAST_ELEMENTS) {
7606 result = SetFastElementsCapacityAndLength(new_capacity, value);
7607 } else {
7608 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7609 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
7610 value);
John Reck59135872010-11-02 12:39:01 -07007611 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007612 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007613 return this;
7614 }
7615 break;
7616 }
7617 case DICTIONARY_ELEMENTS: {
7618 if (IsJSArray()) {
7619 if (value == 0) {
7620 // If the length of a slow array is reset to zero, we clear
7621 // the array and flush backing storage. This has the added
7622 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07007623 Object* obj;
7624 { MaybeObject* maybe_obj = ResetElements();
7625 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7626 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007627 } else {
7628 // Remove deleted elements.
7629 uint32_t old_length =
7630 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7631 element_dictionary()->RemoveNumberEntries(value, old_length);
7632 }
Leon Clarke4515c472010-02-03 11:58:03 +00007633 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007634 }
7635 return this;
7636 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007637 case NON_STRICT_ARGUMENTS_ELEMENTS:
7638 case EXTERNAL_BYTE_ELEMENTS:
7639 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7640 case EXTERNAL_SHORT_ELEMENTS:
7641 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7642 case EXTERNAL_INT_ELEMENTS:
7643 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7644 case EXTERNAL_FLOAT_ELEMENTS:
7645 case EXTERNAL_DOUBLE_ELEMENTS:
7646 case EXTERNAL_PIXEL_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007647 UNREACHABLE();
7648 break;
7649 }
7650 }
7651
7652 // General slow case.
7653 if (len->IsNumber()) {
7654 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007655 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007656 return SetSlowElements(len);
7657 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007658 return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00007659 }
7660 }
7661
7662 // len is not a number so make the array size one and
7663 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07007664 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007665 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07007666 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7667 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007668 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00007669 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007670 set_elements(FixedArray::cast(obj));
7671 return this;
7672}
7673
7674
Steve Block053d10c2011-06-13 19:13:29 +01007675Object* Map::GetPrototypeTransition(Object* prototype) {
7676 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007677 int number_of_transitions = NumberOfProtoTransitions();
7678 const int proto_offset =
7679 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7680 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7681 const int step = kProtoTransitionElementsPerEntry;
7682 for (int i = 0; i < number_of_transitions; i++) {
7683 if (cache->get(proto_offset + i * step) == prototype) {
7684 Object* map = cache->get(map_offset + i * step);
7685 ASSERT(map->IsMap());
7686 return map;
7687 }
Steve Block053d10c2011-06-13 19:13:29 +01007688 }
7689 return NULL;
7690}
7691
7692
7693MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007694 ASSERT(map->IsMap());
7695 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01007696 // Don't cache prototype transition if this map is shared.
7697 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7698
7699 FixedArray* cache = prototype_transitions();
7700
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007701 const int step = kProtoTransitionElementsPerEntry;
7702 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01007703
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007704 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01007705
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007706 int transitions = NumberOfProtoTransitions() + 1;
7707
7708 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01007709 if (capacity > kMaxCachedPrototypeTransitions) return this;
7710
7711 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007712 // Grow array by factor 2 over and above what we need.
7713 { MaybeObject* maybe_cache =
7714 heap()->AllocateFixedArray(transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +01007715 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7716 }
7717
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007718 for (int i = 0; i < capacity * step; i++) {
7719 new_cache->set(i + header, cache->get(i + header));
7720 }
Steve Block053d10c2011-06-13 19:13:29 +01007721 cache = new_cache;
7722 set_prototype_transitions(cache);
7723 }
7724
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007725 int last = transitions - 1;
7726
7727 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7728 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7729 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01007730
7731 return cache;
7732}
7733
7734
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007735MaybeObject* JSReceiver::SetPrototype(Object* value,
7736 bool skip_hidden_prototypes) {
7737#ifdef DEBUG
7738 int size = Size();
7739#endif
7740
Steve Block44f0eee2011-05-26 01:26:41 +01007741 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00007742 // Silently ignore the change if value is not a JSObject or null.
7743 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007744 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00007745
Ben Murdoch8b112d22011-06-08 16:22:53 +01007746 // From 8.6.2 Object Internal Methods
7747 // ...
7748 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7749 // [[Prototype]] internal properties of the object may not be modified.
7750 // ...
7751 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7752 // or [[Extensible]] must not violate the invariants defined in the preceding
7753 // paragraph.
7754 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007755 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01007756 Handle<Object> handle(this, heap->isolate());
7757 return heap->isolate()->Throw(
7758 *FACTORY->NewTypeError("non_extensible_proto",
7759 HandleVector<Object>(&handle, 1)));
7760 }
7761
Andrei Popescu402d9372010-02-26 13:31:12 +00007762 // Before we can set the prototype we need to be sure
7763 // prototype cycles are prevented.
7764 // It is sufficient to validate that the receiver is not in the new prototype
7765 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01007766 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007767 if (JSObject::cast(pt) == this) {
7768 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007769 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007770 return heap->isolate()->Throw(
7771 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00007772 }
7773 }
7774
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007775 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00007776
7777 if (skip_hidden_prototypes) {
7778 // Find the first object in the chain whose prototype object is not
7779 // hidden and set the new prototype on that object.
7780 Object* current_proto = real_receiver->GetPrototype();
7781 while (current_proto->IsJSObject() &&
7782 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7783 real_receiver = JSObject::cast(current_proto);
7784 current_proto = current_proto->GetPrototype();
7785 }
7786 }
7787
7788 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01007789 Map* map = real_receiver->map();
7790
7791 // Nothing to do if prototype is already set.
7792 if (map->prototype() == value) return value;
7793
7794 Object* new_map = map->GetPrototypeTransition(value);
7795 if (new_map == NULL) {
7796 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7797 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7798 }
7799
7800 { MaybeObject* maybe_new_cache =
7801 map->PutPrototypeTransition(value, Map::cast(new_map));
7802 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7803 }
7804
7805 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07007806 }
Steve Block053d10c2011-06-13 19:13:29 +01007807 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00007808 real_receiver->set_map(Map::cast(new_map));
7809
Steve Block44f0eee2011-05-26 01:26:41 +01007810 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007811 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00007812 return value;
7813}
7814
7815
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007816bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007817 switch (GetElementsKind()) {
7818 case FAST_ELEMENTS: {
7819 uint32_t length = IsJSArray() ?
7820 static_cast<uint32_t>
7821 (Smi::cast(JSArray::cast(this)->length())->value()) :
7822 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7823 if ((index < length) &&
7824 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7825 return true;
7826 }
7827 break;
7828 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007829 case FAST_DOUBLE_ELEMENTS: {
7830 uint32_t length = IsJSArray() ?
7831 static_cast<uint32_t>
7832 (Smi::cast(JSArray::cast(this)->length())->value()) :
7833 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7834 if ((index < length) &&
7835 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7836 return true;
7837 }
7838 break;
7839 }
Steve Block44f0eee2011-05-26 01:26:41 +01007840 case EXTERNAL_PIXEL_ELEMENTS: {
7841 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007842 if (index < static_cast<uint32_t>(pixels->length())) {
7843 return true;
7844 }
7845 break;
7846 }
Steve Block3ce2e202009-11-05 08:53:23 +00007847 case EXTERNAL_BYTE_ELEMENTS:
7848 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7849 case EXTERNAL_SHORT_ELEMENTS:
7850 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7851 case EXTERNAL_INT_ELEMENTS:
7852 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007853 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007854 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007855 ExternalArray* array = ExternalArray::cast(elements());
7856 if (index < static_cast<uint32_t>(array->length())) {
7857 return true;
7858 }
7859 break;
7860 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007861 case DICTIONARY_ELEMENTS: {
7862 if (element_dictionary()->FindEntry(index)
7863 != NumberDictionary::kNotFound) {
7864 return true;
7865 }
7866 break;
7867 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007868 case NON_STRICT_ARGUMENTS_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007869 UNREACHABLE();
7870 break;
7871 }
7872
7873 // Handle [] on String objects.
7874 if (this->IsStringObjectWithCharacterAt(index)) return true;
7875
7876 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007877 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007878 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7879}
7880
7881
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007882bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007883 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007884 // Make sure that the top context does not change when doing
7885 // callbacks or interceptor calls.
7886 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007887 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007888 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007889 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00007890 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007891 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007892 v8::AccessorInfo info(args.end());
7893 if (!interceptor->query()->IsUndefined()) {
7894 v8::IndexedPropertyQuery query =
7895 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007896 LOG(isolate,
7897 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007898 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007899 {
7900 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007901 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007902 result = query(index, info);
7903 }
Iain Merrick75681382010-08-19 15:07:18 +01007904 if (!result.IsEmpty()) {
7905 ASSERT(result->IsInt32());
7906 return true; // absence of property is signaled by empty handle.
7907 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007908 } else if (!interceptor->getter()->IsUndefined()) {
7909 v8::IndexedPropertyGetter getter =
7910 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007911 LOG(isolate,
7912 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007913 v8::Handle<v8::Value> result;
7914 {
7915 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007916 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007917 result = getter(index, info);
7918 }
7919 if (!result.IsEmpty()) return true;
7920 }
7921 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7922}
7923
7924
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007925JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007926 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007927 if (IsAccessCheckNeeded()) {
7928 Heap* heap = GetHeap();
7929 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7930 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7931 return UNDEFINED_ELEMENT;
7932 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007933 }
7934
Steve Block1e0659c2011-05-24 12:43:12 +01007935 if (IsJSGlobalProxy()) {
7936 Object* proto = GetPrototype();
7937 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7938 ASSERT(proto->IsJSGlobalObject());
7939 return JSObject::cast(proto)->HasLocalElement(index);
7940 }
7941
Steve Blocka7e24c12009-10-30 11:49:00 +00007942 // Check for lookup interceptor
7943 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007944 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7945 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007946 }
7947
7948 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007949 if (this->IsStringObjectWithCharacterAt(index)) {
7950 return STRING_CHARACTER_ELEMENT;
7951 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007952
7953 switch (GetElementsKind()) {
7954 case FAST_ELEMENTS: {
7955 uint32_t length = IsJSArray() ?
7956 static_cast<uint32_t>
7957 (Smi::cast(JSArray::cast(this)->length())->value()) :
7958 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007959 if ((index < length) &&
7960 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7961 return FAST_ELEMENT;
7962 }
7963 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007964 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007965 case FAST_DOUBLE_ELEMENTS: {
7966 uint32_t length = IsJSArray() ?
7967 static_cast<uint32_t>
7968 (Smi::cast(JSArray::cast(this)->length())->value()) :
7969 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7970 if ((index < length) &&
7971 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7972 return FAST_ELEMENT;
7973 }
7974 break;
7975 }
Steve Block44f0eee2011-05-26 01:26:41 +01007976 case EXTERNAL_PIXEL_ELEMENTS: {
7977 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007978 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7979 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007980 }
Steve Block3ce2e202009-11-05 08:53:23 +00007981 case EXTERNAL_BYTE_ELEMENTS:
7982 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7983 case EXTERNAL_SHORT_ELEMENTS:
7984 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7985 case EXTERNAL_INT_ELEMENTS:
7986 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007987 case EXTERNAL_FLOAT_ELEMENTS:
7988 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007989 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007990 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7991 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007992 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007993 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007994 if (element_dictionary()->FindEntry(index) !=
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007995 NumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007996 return DICTIONARY_ELEMENT;
7997 }
7998 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007999 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008000 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8001 // Aliased parameters and non-aliased elements in a fast backing store
8002 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8003 // backing store behave as DICTIONARY_ELEMENT.
8004 FixedArray* parameter_map = FixedArray::cast(elements());
8005 uint32_t length = parameter_map->length();
8006 Object* probe =
8007 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8008 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8009 // If not aliased, check the arguments.
8010 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8011 if (arguments->IsDictionary()) {
8012 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
8013 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
8014 return DICTIONARY_ELEMENT;
8015 }
8016 } else {
8017 length = arguments->length();
8018 probe = (index < length) ? arguments->get(index) : NULL;
8019 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8020 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008021 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008022 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008023 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008024
8025 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008026}
8027
8028
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008029bool JSObject::HasElementInElements(FixedArray* elements,
8030 ElementsKind kind,
8031 uint32_t index) {
8032 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8033 if (kind == FAST_ELEMENTS) {
8034 int length = IsJSArray()
8035 ? Smi::cast(JSArray::cast(this)->length())->value()
8036 : elements->length();
8037 if (index < static_cast<uint32_t>(length) &&
8038 !elements->get(index)->IsTheHole()) {
8039 return true;
8040 }
8041 } else {
8042 if (NumberDictionary::cast(elements)->FindEntry(index) !=
8043 NumberDictionary::kNotFound) {
8044 return true;
8045 }
8046 }
8047 return false;
8048}
8049
8050
8051bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008052 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008053 if (IsAccessCheckNeeded()) {
8054 Heap* heap = GetHeap();
8055 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8056 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8057 return false;
8058 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008059 }
8060
8061 // Check for lookup interceptor
8062 if (HasIndexedInterceptor()) {
8063 return HasElementWithInterceptor(receiver, index);
8064 }
8065
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008066 ElementsKind kind = GetElementsKind();
8067 switch (kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008068 case FAST_ELEMENTS: {
8069 uint32_t length = IsJSArray() ?
8070 static_cast<uint32_t>
8071 (Smi::cast(JSArray::cast(this)->length())->value()) :
8072 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8073 if ((index < length) &&
8074 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8075 break;
8076 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008077 case FAST_DOUBLE_ELEMENTS: {
8078 uint32_t length = IsJSArray() ?
8079 static_cast<uint32_t>
8080 (Smi::cast(JSArray::cast(this)->length())->value()) :
8081 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8082 if ((index < length) &&
8083 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8084 break;
8085 }
Steve Block44f0eee2011-05-26 01:26:41 +01008086 case EXTERNAL_PIXEL_ELEMENTS: {
8087 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008088 if (index < static_cast<uint32_t>(pixels->length())) {
8089 return true;
8090 }
8091 break;
8092 }
Steve Block3ce2e202009-11-05 08:53:23 +00008093 case EXTERNAL_BYTE_ELEMENTS:
8094 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8095 case EXTERNAL_SHORT_ELEMENTS:
8096 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8097 case EXTERNAL_INT_ELEMENTS:
8098 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008099 case EXTERNAL_FLOAT_ELEMENTS:
8100 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008101 ExternalArray* array = ExternalArray::cast(elements());
8102 if (index < static_cast<uint32_t>(array->length())) {
8103 return true;
8104 }
8105 break;
8106 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008107 case DICTIONARY_ELEMENTS: {
8108 if (element_dictionary()->FindEntry(index)
8109 != NumberDictionary::kNotFound) {
8110 return true;
8111 }
8112 break;
8113 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008114 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8115 FixedArray* parameter_map = FixedArray::cast(elements());
8116 uint32_t length = parameter_map->length();
8117 Object* probe =
8118 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8119 if (probe != NULL && !probe->IsTheHole()) return true;
8120
8121 // Not a mapped parameter, check the arguments.
8122 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8123 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8124 if (HasElementInElements(arguments, kind, index)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008125 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008126 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008127 }
8128
8129 // Handle [] on String objects.
8130 if (this->IsStringObjectWithCharacterAt(index)) return true;
8131
8132 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008133 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008134 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8135}
8136
8137
John Reck59135872010-11-02 12:39:01 -07008138MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008139 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008140 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008141 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008142 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008143 // Make sure that the top context does not change when doing
8144 // callbacks or interceptor calls.
8145 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008146 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008147 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8148 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008149 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008150 if (!interceptor->setter()->IsUndefined()) {
8151 v8::IndexedPropertySetter setter =
8152 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01008153 LOG(isolate,
8154 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8155 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008156 v8::AccessorInfo info(args.end());
8157 v8::Handle<v8::Value> result;
8158 {
8159 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008160 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008161 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8162 }
Steve Block44f0eee2011-05-26 01:26:41 +01008163 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008164 if (!result.IsEmpty()) return *value_handle;
8165 }
John Reck59135872010-11-02 12:39:01 -07008166 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01008167 this_handle->SetElementWithoutInterceptor(index,
8168 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008169 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008170 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008171 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008172 return raw_result;
8173}
8174
8175
John Reck59135872010-11-02 12:39:01 -07008176MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8177 Object* structure,
8178 uint32_t index,
8179 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01008180 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00008181 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008182
8183 // api style callbacks.
8184 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00008185 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008186 Object* fun_obj = data->getter();
8187 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008188 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008189 Handle<JSObject> self(JSObject::cast(receiver));
8190 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01008191 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008192 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01008193 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8194 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008195 v8::AccessorInfo info(args.end());
8196 v8::Handle<v8::Value> result;
8197 {
8198 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008199 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008200 result = call_fun(v8::Utils::ToLocal(key), info);
8201 }
Steve Block44f0eee2011-05-26 01:26:41 +01008202 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8203 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008204 return *v8::Utils::OpenHandle(*result);
8205 }
8206
8207 // __defineGetter__ callback
8208 if (structure->IsFixedArray()) {
8209 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
8210 if (getter->IsJSFunction()) {
8211 return Object::GetPropertyWithDefinedGetter(receiver,
8212 JSFunction::cast(getter));
8213 }
8214 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01008215 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008216 }
8217
8218 UNREACHABLE();
8219 return NULL;
8220}
8221
8222
John Reck59135872010-11-02 12:39:01 -07008223MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8224 uint32_t index,
8225 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008226 JSObject* holder,
8227 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008228 Isolate* isolate = GetIsolate();
8229 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008230
8231 // We should never get here to initialize a const with the hole
8232 // value since a const declaration would conflict with the setter.
8233 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01008234 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008235
8236 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00008237 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01008238 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00008239 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008240
8241 if (structure->IsAccessorInfo()) {
8242 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00008243 Handle<JSObject> self(this);
8244 Handle<JSObject> holder_handle(JSObject::cast(holder));
8245 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008246 Object* call_obj = data->setter();
8247 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8248 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01008249 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8250 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00008251 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8252 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008253 v8::AccessorInfo info(args.end());
8254 {
8255 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008256 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008257 call_fun(v8::Utils::ToLocal(key),
8258 v8::Utils::ToLocal(value_handle),
8259 info);
8260 }
Steve Block44f0eee2011-05-26 01:26:41 +01008261 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008262 return *value_handle;
8263 }
8264
8265 if (structure->IsFixedArray()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008266 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
Leon Clarkef7060e22010-06-03 12:02:55 +01008267 if (setter->IsJSFunction()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008268 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01008269 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008270 if (strict_mode == kNonStrictMode) {
8271 return value;
8272 }
Steve Block44f0eee2011-05-26 01:26:41 +01008273 Handle<Object> holder_handle(holder, isolate);
8274 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01008275 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01008276 return isolate->Throw(
8277 *isolate->factory()->NewTypeError("no_setter_in_callback",
8278 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01008279 }
8280 }
8281
8282 UNREACHABLE();
8283 return NULL;
8284}
8285
8286
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008287bool JSObject::HasFastArgumentsElements() {
8288 Heap* heap = GetHeap();
8289 if (!elements()->IsFixedArray()) return false;
8290 FixedArray* elements = FixedArray::cast(this->elements());
8291 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8292 return false;
8293 }
8294 FixedArray* arguments = FixedArray::cast(elements->get(1));
8295 return !arguments->IsDictionary();
8296}
8297
8298
8299bool JSObject::HasDictionaryArgumentsElements() {
8300 Heap* heap = GetHeap();
8301 if (!elements()->IsFixedArray()) return false;
8302 FixedArray* elements = FixedArray::cast(this->elements());
8303 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8304 return false;
8305 }
8306 FixedArray* arguments = FixedArray::cast(elements->get(1));
8307 return arguments->IsDictionary();
8308}
8309
8310
Steve Blocka7e24c12009-10-30 11:49:00 +00008311// Adding n elements in fast case is O(n*n).
8312// Note: revisit design to have dual undefined values to capture absent
8313// elements.
Steve Block9fac8402011-05-12 15:51:54 +01008314MaybeObject* JSObject::SetFastElement(uint32_t index,
8315 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008316 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008317 bool check_prototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008318 ASSERT(HasFastElements() || HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008319
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008320 FixedArray* backing_store = FixedArray::cast(elements());
8321 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
8322 backing_store = FixedArray::cast(backing_store->get(1));
8323 } else {
8324 Object* writable;
8325 MaybeObject* maybe = EnsureWritableFastElements();
8326 if (!maybe->ToObject(&writable)) return maybe;
8327 backing_store = FixedArray::cast(writable);
John Reck59135872010-11-02 12:39:01 -07008328 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008329 uint32_t length = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008330
Steve Block9fac8402011-05-12 15:51:54 +01008331 if (check_prototype &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008332 (index >= length || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01008333 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008334 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8335 value,
8336 &found,
8337 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01008338 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008339 }
8340
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008341 // Check whether there is extra space in fixed array.
8342 if (index < length) {
8343 backing_store->set(index, value);
8344 if (IsJSArray()) {
8345 // Update the length of the array if needed.
8346 uint32_t array_length = 0;
8347 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8348 if (index >= array_length) {
8349 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
8350 }
8351 }
8352 return value;
8353 }
Steve Block9fac8402011-05-12 15:51:54 +01008354
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008355 // Allow gap in fast case.
8356 if ((index - length) < kMaxGap) {
8357 // Try allocating extra space.
8358 int new_capacity = NewElementsCapacity(index + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008359 if (!ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008360 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8361 Object* new_elements;
8362 MaybeObject* maybe =
8363 SetFastElementsCapacityAndLength(new_capacity, index + 1);
8364 if (!maybe->ToObject(&new_elements)) return maybe;
8365 FixedArray::cast(new_elements)->set(index, value);
8366 return value;
8367 }
8368 }
8369
8370 // Otherwise default to slow case.
8371 MaybeObject* result = NormalizeElements();
8372 if (result->IsFailure()) return result;
8373 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8374}
8375
8376
8377MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
8378 Object* value,
8379 StrictModeFlag strict_mode,
8380 bool check_prototype) {
8381 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
8382 Isolate* isolate = GetIsolate();
8383 Heap* heap = isolate->heap();
8384
8385 // Insert element in the dictionary.
8386 FixedArray* elements = FixedArray::cast(this->elements());
8387 bool is_arguments =
8388 (elements->map() == heap->non_strict_arguments_elements_map());
8389 NumberDictionary* dictionary = NULL;
8390 if (is_arguments) {
8391 dictionary = NumberDictionary::cast(elements->get(1));
8392 } else {
8393 dictionary = NumberDictionary::cast(elements);
8394 }
8395
8396 int entry = dictionary->FindEntry(index);
8397 if (entry != NumberDictionary::kNotFound) {
8398 Object* element = dictionary->ValueAt(entry);
8399 PropertyDetails details = dictionary->DetailsAt(entry);
8400 if (details.type() == CALLBACKS) {
8401 return SetElementWithCallback(element, index, value, this, strict_mode);
8402 } else {
8403 dictionary->UpdateMaxNumberKey(index);
8404 // If put fails in strict mode, throw an exception.
8405 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
8406 Handle<Object> holder(this);
8407 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8408 Handle<Object> args[2] = { number, holder };
8409 Handle<Object> error =
8410 isolate->factory()->NewTypeError("strict_read_only_property",
8411 HandleVector(args, 2));
8412 return isolate->Throw(*error);
8413 }
8414 }
8415 } else {
8416 // Index not already used. Look for an accessor in the prototype chain.
8417 if (check_prototype) {
8418 bool found;
8419 MaybeObject* result =
8420 SetElementWithCallbackSetterInPrototypes(
8421 index, value, &found, strict_mode);
8422 if (found) return result;
8423 }
8424 // When we set the is_extensible flag to false we always force the
8425 // element into dictionary mode (and force them to stay there).
8426 if (!map()->is_extensible()) {
8427 if (strict_mode == kNonStrictMode) {
8428 return isolate->heap()->undefined_value();
8429 } else {
8430 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8431 Handle<String> name = isolate->factory()->NumberToString(number);
8432 Handle<Object> args[1] = { name };
8433 Handle<Object> error =
8434 isolate->factory()->NewTypeError("object_not_extensible",
8435 HandleVector(args, 1));
8436 return isolate->Throw(*error);
8437 }
8438 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008439 FixedArrayBase* new_dictionary;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008440 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008441 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008442 if (dictionary != NumberDictionary::cast(new_dictionary)) {
8443 if (is_arguments) {
8444 elements->set(1, new_dictionary);
8445 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008446 set_elements(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008447 }
8448 dictionary = NumberDictionary::cast(new_dictionary);
8449 }
8450 }
8451
8452 // Update the array length if this JSObject is an array.
8453 if (IsJSArray()) {
8454 MaybeObject* result =
8455 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
8456 if (result->IsFailure()) return result;
8457 }
8458
8459 // Attempt to put this object back in fast case.
8460 if (ShouldConvertToFastElements()) {
8461 uint32_t new_length = 0;
8462 if (IsJSArray()) {
8463 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
8464 } else {
8465 new_length = dictionary->max_number_key() + 1;
8466 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008467 MaybeObject* result = CanConvertToFastDoubleElements()
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008468 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
8469 : SetFastElementsCapacityAndLength(new_length, new_length);
8470 if (result->IsFailure()) return result;
8471#ifdef DEBUG
8472 if (FLAG_trace_normalization) {
8473 PrintF("Object elements are fast case again:\n");
8474 Print();
8475 }
8476#endif
8477 }
8478 return value;
8479}
8480
8481
8482MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8483 uint32_t index,
8484 Object* value,
8485 StrictModeFlag strict_mode,
8486 bool check_prototype) {
8487 ASSERT(HasFastDoubleElements());
8488
8489 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8490 uint32_t elms_length = static_cast<uint32_t>(elms->length());
8491
8492 // If storing to an element that isn't in the array, pass the store request
8493 // up the prototype chain before storing in the receiver's elements.
8494 if (check_prototype &&
8495 (index >= elms_length || elms->is_the_hole(index))) {
8496 bool found;
8497 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8498 value,
8499 &found,
8500 strict_mode);
8501 if (found) return result;
8502 }
8503
8504 // If the value object is not a heap number, switch to fast elements and try
8505 // again.
8506 bool value_is_smi = value->IsSmi();
8507 if (!value->IsNumber()) {
8508 Object* obj;
8509 uint32_t length = elms_length;
8510 if (IsJSArray()) {
8511 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8512 }
8513 MaybeObject* maybe_obj =
8514 SetFastElementsCapacityAndLength(elms_length, length);
8515 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8516 return SetFastElement(index, value, strict_mode, check_prototype);
8517 }
8518
8519 double double_value = value_is_smi
8520 ? static_cast<double>(Smi::cast(value)->value())
8521 : HeapNumber::cast(value)->value();
8522
8523 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00008524 if (index < elms_length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008525 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008526 if (IsJSArray()) {
8527 // Update the length of the array if needed.
8528 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008529 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00008530 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00008531 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00008532 }
8533 }
8534 return value;
8535 }
8536
8537 // Allow gap in fast case.
8538 if ((index - elms_length) < kMaxGap) {
8539 // Try allocating extra space.
8540 int new_capacity = NewElementsCapacity(index+1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008541 if (!ShouldConvertToSlowElements(new_capacity)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008542 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07008543 Object* obj;
8544 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008545 SetFastDoubleElementsCapacityAndLength(new_capacity,
8546 index + 1);
John Reck59135872010-11-02 12:39:01 -07008547 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8548 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008549 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008550 return value;
8551 }
8552 }
8553
8554 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008555 ASSERT(HasFastDoubleElements());
8556 ASSERT(map()->has_fast_double_elements());
8557 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07008558 Object* obj;
8559 { MaybeObject* maybe_obj = NormalizeElements();
8560 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8561 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008562 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008563 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008564}
8565
Iain Merrick75681382010-08-19 15:07:18 +01008566
Steve Block9fac8402011-05-12 15:51:54 +01008567MaybeObject* JSObject::SetElement(uint32_t index,
8568 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008569 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008570 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008571 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008572 if (IsAccessCheckNeeded()) {
8573 Heap* heap = GetHeap();
8574 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008575 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008576 Handle<Object> value_handle(value);
8577 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8578 return *value_handle;
8579 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008580 }
8581
8582 if (IsJSGlobalProxy()) {
8583 Object* proto = GetPrototype();
8584 if (proto->IsNull()) return value;
8585 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008586 return JSObject::cast(proto)->SetElement(index,
8587 value,
8588 strict_mode,
8589 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008590 }
8591
8592 // Check for lookup interceptor
8593 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008594 return SetElementWithInterceptor(index,
8595 value,
8596 strict_mode,
8597 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008598 }
8599
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008600 return SetElementWithoutInterceptor(index,
8601 value,
8602 strict_mode,
8603 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008604}
8605
8606
John Reck59135872010-11-02 12:39:01 -07008607MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008608 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008609 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008610 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008611 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008612 switch (GetElementsKind()) {
8613 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008614 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008615 case FAST_DOUBLE_ELEMENTS:
8616 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008617 case EXTERNAL_PIXEL_ELEMENTS: {
8618 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008619 return pixels->SetValue(index, value);
8620 }
Steve Block3ce2e202009-11-05 08:53:23 +00008621 case EXTERNAL_BYTE_ELEMENTS: {
8622 ExternalByteArray* array = ExternalByteArray::cast(elements());
8623 return array->SetValue(index, value);
8624 }
8625 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8626 ExternalUnsignedByteArray* array =
8627 ExternalUnsignedByteArray::cast(elements());
8628 return array->SetValue(index, value);
8629 }
8630 case EXTERNAL_SHORT_ELEMENTS: {
8631 ExternalShortArray* array = ExternalShortArray::cast(elements());
8632 return array->SetValue(index, value);
8633 }
8634 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8635 ExternalUnsignedShortArray* array =
8636 ExternalUnsignedShortArray::cast(elements());
8637 return array->SetValue(index, value);
8638 }
8639 case EXTERNAL_INT_ELEMENTS: {
8640 ExternalIntArray* array = ExternalIntArray::cast(elements());
8641 return array->SetValue(index, value);
8642 }
8643 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8644 ExternalUnsignedIntArray* array =
8645 ExternalUnsignedIntArray::cast(elements());
8646 return array->SetValue(index, value);
8647 }
8648 case EXTERNAL_FLOAT_ELEMENTS: {
8649 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8650 return array->SetValue(index, value);
8651 }
Ben Murdoch257744e2011-11-30 15:57:28 +00008652 case EXTERNAL_DOUBLE_ELEMENTS: {
8653 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8654 return array->SetValue(index, value);
8655 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008656 case DICTIONARY_ELEMENTS:
8657 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8658 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8659 FixedArray* parameter_map = FixedArray::cast(elements());
8660 uint32_t length = parameter_map->length();
8661 Object* probe =
8662 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8663 if (probe != NULL && !probe->IsTheHole()) {
8664 Context* context = Context::cast(parameter_map->get(0));
8665 int context_index = Smi::cast(probe)->value();
8666 ASSERT(!context->get(context_index)->IsTheHole());
8667 context->set(context_index, value);
8668 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00008669 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008670 // Object is not mapped, defer to the arguments.
8671 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8672 if (arguments->IsDictionary()) {
8673 return SetDictionaryElement(index, value, strict_mode,
8674 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008675 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008676 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008677 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008678 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008679 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008680 }
8681 // All possible cases have been handled above. Add a return to avoid the
8682 // complaints from the compiler.
8683 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01008684 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008685}
8686
8687
John Reck59135872010-11-02 12:39:01 -07008688MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8689 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008690 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008691 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00008692 // Check to see if we need to update the length. For now, we make
8693 // sure that the length stays within 32-bits (unsigned).
8694 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07008695 Object* len;
8696 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01008697 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07008698 if (!maybe_len->ToObject(&len)) return maybe_len;
8699 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008700 set_length(len);
8701 }
8702 return value;
8703}
8704
8705
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008706MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07008707 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008708 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008709 // Make sure that the top context does not change when doing
8710 // callbacks or interceptor calls.
8711 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008712 HandleScope scope(isolate);
8713 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8714 Handle<Object> this_handle(receiver, isolate);
8715 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008716 if (!interceptor->getter()->IsUndefined()) {
8717 v8::IndexedPropertyGetter getter =
8718 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008719 LOG(isolate,
8720 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8721 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008722 v8::AccessorInfo info(args.end());
8723 v8::Handle<v8::Value> result;
8724 {
8725 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008726 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008727 result = getter(index, info);
8728 }
Steve Block44f0eee2011-05-26 01:26:41 +01008729 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008730 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8731 }
8732
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008733 Heap* heap = holder_handle->GetHeap();
8734 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
8735 MaybeObject* raw_result = handler->Get(holder_handle->elements(),
8736 index,
8737 *holder_handle,
8738 *this_handle);
8739 if (raw_result != heap->the_hole_value()) return raw_result;
8740
Steve Block44f0eee2011-05-26 01:26:41 +01008741 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008742
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008743 Object* pt = holder_handle->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008744 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008745 return pt->GetElementWithReceiver(*this_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008746}
8747
8748
8749bool JSObject::HasDenseElements() {
8750 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008751 int used = 0;
8752 GetElementsCapacityAndUsage(&capacity, &used);
8753 return (capacity == 0) || (used > (capacity / 2));
8754}
8755
8756
8757void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
8758 *capacity = 0;
8759 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008760
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008761 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
8762 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00008763 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008764 case NON_STRICT_ARGUMENTS_ELEMENTS:
8765 backing_store_base =
8766 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
8767 backing_store = FixedArray::cast(backing_store_base);
8768 if (backing_store->IsDictionary()) {
8769 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008770 *capacity = dictionary->Capacity();
8771 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008772 break;
8773 }
8774 // Fall through.
8775 case FAST_ELEMENTS:
8776 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008777 *capacity = backing_store->length();
8778 for (int i = 0; i < *capacity; ++i) {
8779 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008780 }
8781 break;
8782 case DICTIONARY_ELEMENTS: {
8783 NumberDictionary* dictionary =
8784 NumberDictionary::cast(FixedArray::cast(elements()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008785 *capacity = dictionary->Capacity();
8786 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008787 break;
8788 }
8789 case FAST_DOUBLE_ELEMENTS: {
8790 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008791 *capacity = elms->length();
8792 for (int i = 0; i < *capacity; i++) {
8793 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +00008794 }
8795 break;
8796 }
Steve Block3ce2e202009-11-05 08:53:23 +00008797 case EXTERNAL_BYTE_ELEMENTS:
8798 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8799 case EXTERNAL_SHORT_ELEMENTS:
8800 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8801 case EXTERNAL_INT_ELEMENTS:
8802 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008803 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008804 case EXTERNAL_DOUBLE_ELEMENTS:
8805 case EXTERNAL_PIXEL_ELEMENTS:
8806 // External arrays are considered 100% used.
8807 ExternalArray* external_array = ExternalArray::cast(elements());
8808 *capacity = external_array->length();
8809 *used = external_array->length();
8810 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008811 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008812}
8813
8814
8815bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008816 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
8817 kMaxUncheckedFastElementsLength);
8818 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
8819 (new_capacity <= kMaxUncheckedFastElementsLength &&
8820 GetHeap()->InNewSpace(this))) {
8821 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008822 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008823 // If the fast-case backing storage takes up roughly three times as
8824 // much space (in machine words) as a dictionary backing storage
8825 // would, the object should have slow elements.
8826 int old_capacity = 0;
8827 int used_elements = 0;
8828 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
8829 int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
8830 NumberDictionary::kEntrySize;
8831 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +00008832}
8833
8834
8835bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008836 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008837 // If the elements are sparse, we should not go back to fast case.
8838 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008839 // An object requiring access checks is never allowed to have fast
8840 // elements. If it had fast elements we would skip security checks.
8841 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008842
8843 FixedArray* elements = FixedArray::cast(this->elements());
8844 NumberDictionary* dictionary = NULL;
8845 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
8846 dictionary = NumberDictionary::cast(elements->get(1));
8847 } else {
8848 dictionary = NumberDictionary::cast(elements);
8849 }
8850 // If an element has been added at a very high index in the elements
8851 // dictionary, we cannot go back to fast case.
8852 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008853 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008854 // space (in machine words) as a fast-case backing storage would,
8855 // the object should have fast elements.
8856 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008857 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008858 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +00008859 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008860 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +00008861 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008862 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
8863 NumberDictionary::kEntrySize;
8864 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00008865}
8866
8867
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008868bool JSObject::CanConvertToFastDoubleElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008869 if (FLAG_unbox_double_arrays) {
8870 ASSERT(HasDictionaryElements());
8871 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8872 for (int i = 0; i < dictionary->Capacity(); i++) {
8873 Object* key = dictionary->KeyAt(i);
8874 if (key->IsNumber()) {
8875 if (!dictionary->ValueAt(i)->IsNumber()) return false;
8876 }
8877 }
8878 return true;
8879 } else {
8880 return false;
8881 }
8882}
8883
8884
Steve Blocka7e24c12009-10-30 11:49:00 +00008885// Certain compilers request function template instantiation when they
8886// see the definition of the other template functions in the
8887// class. This requires us to have the template functions put
8888// together, so even though this function belongs in objects-debug.cc,
8889// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008890#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00008891template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01008892void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008893 int capacity = HashTable<Shape, Key>::Capacity();
8894 for (int i = 0; i < capacity; i++) {
8895 Object* k = HashTable<Shape, Key>::KeyAt(i);
8896 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008897 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00008898 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008899 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008900 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008901 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008902 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008903 PrintF(out, ": ");
8904 ValueAt(i)->ShortPrint(out);
8905 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008906 }
8907 }
8908}
8909#endif
8910
8911
8912template<typename Shape, typename Key>
8913void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
8914 int pos = 0;
8915 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00008916 AssertNoAllocation no_gc;
8917 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008918 for (int i = 0; i < capacity; i++) {
8919 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8920 if (Dictionary<Shape, Key>::IsKey(k)) {
8921 elements->set(pos++, ValueAt(i), mode);
8922 }
8923 }
8924 ASSERT(pos == elements->length());
8925}
8926
8927
8928InterceptorInfo* JSObject::GetNamedInterceptor() {
8929 ASSERT(map()->has_named_interceptor());
8930 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008931 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008932 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008933 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008934 return InterceptorInfo::cast(result);
8935}
8936
8937
8938InterceptorInfo* JSObject::GetIndexedInterceptor() {
8939 ASSERT(map()->has_indexed_interceptor());
8940 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008941 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008942 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008943 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008944 return InterceptorInfo::cast(result);
8945}
8946
8947
John Reck59135872010-11-02 12:39:01 -07008948MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008949 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -07008950 String* name,
8951 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008952 // Check local property in holder, ignore interceptor.
8953 LookupResult result;
8954 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008955 if (result.IsProperty()) {
8956 return GetProperty(receiver, &result, name, attributes);
8957 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008958 // Continue searching via the prototype chain.
8959 Object* pt = GetPrototype();
8960 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008961 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008962 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8963}
8964
8965
John Reck59135872010-11-02 12:39:01 -07008966MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008967 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +00008968 String* name,
8969 PropertyAttributes* attributes) {
8970 // Check local property in holder, ignore interceptor.
8971 LookupResult result;
8972 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008973 if (result.IsProperty()) {
8974 return GetProperty(receiver, &result, name, attributes);
8975 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01008976 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00008977}
8978
8979
John Reck59135872010-11-02 12:39:01 -07008980MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008981 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00008982 String* name,
8983 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01008984 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008985 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01008986 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008987 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008988 Handle<JSObject> holder_handle(this);
8989 Handle<String> name_handle(name);
8990
8991 if (!interceptor->getter()->IsUndefined()) {
8992 v8::NamedPropertyGetter getter =
8993 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008994 LOG(isolate,
8995 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8996 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008997 v8::AccessorInfo info(args.end());
8998 v8::Handle<v8::Value> result;
8999 {
9000 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009001 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009002 result = getter(v8::Utils::ToLocal(name_handle), info);
9003 }
Steve Block44f0eee2011-05-26 01:26:41 +01009004 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009005 if (!result.IsEmpty()) {
9006 *attributes = NONE;
9007 return *v8::Utils::OpenHandle(*result);
9008 }
9009 }
9010
John Reck59135872010-11-02 12:39:01 -07009011 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00009012 *receiver_handle,
9013 *name_handle,
9014 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01009015 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009016 return result;
9017}
9018
9019
9020bool JSObject::HasRealNamedProperty(String* key) {
9021 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009022 if (IsAccessCheckNeeded()) {
9023 Heap* heap = GetHeap();
9024 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9025 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9026 return false;
9027 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009028 }
9029
9030 LookupResult result;
9031 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009032 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00009033}
9034
9035
9036bool JSObject::HasRealElementProperty(uint32_t index) {
9037 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009038 if (IsAccessCheckNeeded()) {
9039 Heap* heap = GetHeap();
9040 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9041 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9042 return false;
9043 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009044 }
9045
9046 // Handle [] on String objects.
9047 if (this->IsStringObjectWithCharacterAt(index)) return true;
9048
9049 switch (GetElementsKind()) {
9050 case FAST_ELEMENTS: {
9051 uint32_t length = IsJSArray() ?
9052 static_cast<uint32_t>(
9053 Smi::cast(JSArray::cast(this)->length())->value()) :
9054 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9055 return (index < length) &&
9056 !FixedArray::cast(elements())->get(index)->IsTheHole();
9057 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009058 case FAST_DOUBLE_ELEMENTS: {
9059 uint32_t length = IsJSArray() ?
9060 static_cast<uint32_t>(
9061 Smi::cast(JSArray::cast(this)->length())->value()) :
9062 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9063 return (index < length) &&
9064 !FixedDoubleArray::cast(elements())->is_the_hole(index);
9065 break;
9066 }
Steve Block44f0eee2011-05-26 01:26:41 +01009067 case EXTERNAL_PIXEL_ELEMENTS: {
9068 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009069 return index < static_cast<uint32_t>(pixels->length());
9070 }
Steve Block3ce2e202009-11-05 08:53:23 +00009071 case EXTERNAL_BYTE_ELEMENTS:
9072 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9073 case EXTERNAL_SHORT_ELEMENTS:
9074 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9075 case EXTERNAL_INT_ELEMENTS:
9076 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009077 case EXTERNAL_FLOAT_ELEMENTS:
9078 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009079 ExternalArray* array = ExternalArray::cast(elements());
9080 return index < static_cast<uint32_t>(array->length());
9081 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009082 case DICTIONARY_ELEMENTS: {
9083 return element_dictionary()->FindEntry(index)
9084 != NumberDictionary::kNotFound;
9085 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009086 case NON_STRICT_ARGUMENTS_ELEMENTS:
9087 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00009088 break;
9089 }
9090 // All possibilities have been handled above already.
9091 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009092 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009093}
9094
9095
9096bool JSObject::HasRealNamedCallbackProperty(String* key) {
9097 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009098 if (IsAccessCheckNeeded()) {
9099 Heap* heap = GetHeap();
9100 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9101 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9102 return false;
9103 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009104 }
9105
9106 LookupResult result;
9107 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009108 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00009109}
9110
9111
9112int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
9113 if (HasFastProperties()) {
9114 DescriptorArray* descs = map()->instance_descriptors();
9115 int result = 0;
9116 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009117 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009118 if (details.IsProperty() && (details.attributes() & filter) == 0) {
9119 result++;
9120 }
9121 }
9122 return result;
9123 } else {
9124 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9125 }
9126}
9127
9128
9129int JSObject::NumberOfEnumProperties() {
9130 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
9131}
9132
9133
9134void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
9135 Object* temp = get(i);
9136 set(i, get(j));
9137 set(j, temp);
9138 if (this != numbers) {
9139 temp = numbers->get(i);
9140 numbers->set(i, numbers->get(j));
9141 numbers->set(j, temp);
9142 }
9143}
9144
9145
9146static void InsertionSortPairs(FixedArray* content,
9147 FixedArray* numbers,
9148 int len) {
9149 for (int i = 1; i < len; i++) {
9150 int j = i;
9151 while (j > 0 &&
9152 (NumberToUint32(numbers->get(j - 1)) >
9153 NumberToUint32(numbers->get(j)))) {
9154 content->SwapPairs(numbers, j - 1, j);
9155 j--;
9156 }
9157 }
9158}
9159
9160
9161void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
9162 // In-place heap sort.
9163 ASSERT(content->length() == numbers->length());
9164
9165 // Bottom-up max-heap construction.
9166 for (int i = 1; i < len; ++i) {
9167 int child_index = i;
9168 while (child_index > 0) {
9169 int parent_index = ((child_index + 1) >> 1) - 1;
9170 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9171 uint32_t child_value = NumberToUint32(numbers->get(child_index));
9172 if (parent_value < child_value) {
9173 content->SwapPairs(numbers, parent_index, child_index);
9174 } else {
9175 break;
9176 }
9177 child_index = parent_index;
9178 }
9179 }
9180
9181 // Extract elements and create sorted array.
9182 for (int i = len - 1; i > 0; --i) {
9183 // Put max element at the back of the array.
9184 content->SwapPairs(numbers, 0, i);
9185 // Sift down the new top element.
9186 int parent_index = 0;
9187 while (true) {
9188 int child_index = ((parent_index + 1) << 1) - 1;
9189 if (child_index >= i) break;
9190 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
9191 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
9192 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9193 if (child_index + 1 >= i || child1_value > child2_value) {
9194 if (parent_value > child1_value) break;
9195 content->SwapPairs(numbers, parent_index, child_index);
9196 parent_index = child_index;
9197 } else {
9198 if (parent_value > child2_value) break;
9199 content->SwapPairs(numbers, parent_index, child_index + 1);
9200 parent_index = child_index + 1;
9201 }
9202 }
9203 }
9204}
9205
9206
9207// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9208void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9209 ASSERT(this->length() == numbers->length());
9210 // For small arrays, simply use insertion sort.
9211 if (len <= 10) {
9212 InsertionSortPairs(this, numbers, len);
9213 return;
9214 }
9215 // Check the range of indices.
9216 uint32_t min_index = NumberToUint32(numbers->get(0));
9217 uint32_t max_index = min_index;
9218 uint32_t i;
9219 for (i = 1; i < len; i++) {
9220 if (NumberToUint32(numbers->get(i)) < min_index) {
9221 min_index = NumberToUint32(numbers->get(i));
9222 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9223 max_index = NumberToUint32(numbers->get(i));
9224 }
9225 }
9226 if (max_index - min_index + 1 == len) {
9227 // Indices form a contiguous range, unless there are duplicates.
9228 // Do an in-place linear time sort assuming distinct numbers, but
9229 // avoid hanging in case they are not.
9230 for (i = 0; i < len; i++) {
9231 uint32_t p;
9232 uint32_t j = 0;
9233 // While the current element at i is not at its correct position p,
9234 // swap the elements at these two positions.
9235 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
9236 j++ < len) {
9237 SwapPairs(numbers, i, p);
9238 }
9239 }
9240 } else {
9241 HeapSortPairs(this, numbers, len);
9242 return;
9243 }
9244}
9245
9246
9247// Fill in the names of local properties into the supplied storage. The main
9248// purpose of this function is to provide reflection information for the object
9249// mirrors.
9250void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
9251 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
9252 if (HasFastProperties()) {
9253 DescriptorArray* descs = map()->instance_descriptors();
9254 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9255 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
9256 }
9257 ASSERT(storage->length() >= index);
9258 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009259 property_dictionary()->CopyKeysTo(storage,
9260 index,
9261 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009262 }
9263}
9264
9265
9266int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9267 return GetLocalElementKeys(NULL, filter);
9268}
9269
9270
9271int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00009272 // Fast case for objects with no elements.
9273 if (!IsJSValue() && HasFastElements()) {
9274 uint32_t length = IsJSArray() ?
9275 static_cast<uint32_t>(
9276 Smi::cast(JSArray::cast(this)->length())->value()) :
9277 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9278 if (length == 0) return 0;
9279 }
9280 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00009281 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9282}
9283
9284
9285int JSObject::GetLocalElementKeys(FixedArray* storage,
9286 PropertyAttributes filter) {
9287 int counter = 0;
9288 switch (GetElementsKind()) {
9289 case FAST_ELEMENTS: {
9290 int length = IsJSArray() ?
9291 Smi::cast(JSArray::cast(this)->length())->value() :
9292 FixedArray::cast(elements())->length();
9293 for (int i = 0; i < length; i++) {
9294 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9295 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009296 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009297 }
9298 counter++;
9299 }
9300 }
9301 ASSERT(!storage || storage->length() >= counter);
9302 break;
9303 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009304 case FAST_DOUBLE_ELEMENTS: {
9305 int length = IsJSArray() ?
9306 Smi::cast(JSArray::cast(this)->length())->value() :
9307 FixedDoubleArray::cast(elements())->length();
9308 for (int i = 0; i < length; i++) {
9309 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
9310 if (storage != NULL) {
9311 storage->set(counter, Smi::FromInt(i));
9312 }
9313 counter++;
9314 }
9315 }
9316 ASSERT(!storage || storage->length() >= counter);
9317 break;
9318 }
Steve Block44f0eee2011-05-26 01:26:41 +01009319 case EXTERNAL_PIXEL_ELEMENTS: {
9320 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00009321 while (counter < length) {
9322 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009323 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00009324 }
9325 counter++;
9326 }
9327 ASSERT(!storage || storage->length() >= counter);
9328 break;
9329 }
Steve Block3ce2e202009-11-05 08:53:23 +00009330 case EXTERNAL_BYTE_ELEMENTS:
9331 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9332 case EXTERNAL_SHORT_ELEMENTS:
9333 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9334 case EXTERNAL_INT_ELEMENTS:
9335 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009336 case EXTERNAL_FLOAT_ELEMENTS:
9337 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009338 int length = ExternalArray::cast(elements())->length();
9339 while (counter < length) {
9340 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009341 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00009342 }
9343 counter++;
9344 }
9345 ASSERT(!storage || storage->length() >= counter);
9346 break;
9347 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009348 case DICTIONARY_ELEMENTS: {
9349 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009350 element_dictionary()->CopyKeysTo(storage,
9351 filter,
9352 NumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009353 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009354 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +00009355 break;
9356 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009357 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9358 FixedArray* parameter_map = FixedArray::cast(elements());
9359 int mapped_length = parameter_map->length() - 2;
9360 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9361 if (arguments->IsDictionary()) {
9362 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
9363 // will insert in storage starting at index 0.
9364 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
9365 if (storage != NULL) {
9366 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
9367 }
9368 counter += dictionary->NumberOfElementsFilterAttributes(filter);
9369 for (int i = 0; i < mapped_length; ++i) {
9370 if (!parameter_map->get(i + 2)->IsTheHole()) {
9371 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9372 ++counter;
9373 }
9374 }
9375 if (storage != NULL) storage->SortPairs(storage, counter);
9376
9377 } else {
9378 int backing_length = arguments->length();
9379 int i = 0;
9380 for (; i < mapped_length; ++i) {
9381 if (!parameter_map->get(i + 2)->IsTheHole()) {
9382 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9383 ++counter;
9384 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
9385 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9386 ++counter;
9387 }
9388 }
9389 for (; i < backing_length; ++i) {
9390 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9391 ++counter;
9392 }
9393 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009394 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009395 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009396 }
9397
9398 if (this->IsJSValue()) {
9399 Object* val = JSValue::cast(this)->value();
9400 if (val->IsString()) {
9401 String* str = String::cast(val);
9402 if (storage) {
9403 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009404 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009405 }
9406 }
9407 counter += str->length();
9408 }
9409 }
9410 ASSERT(!storage || storage->length() == counter);
9411 return counter;
9412}
9413
9414
9415int JSObject::GetEnumElementKeys(FixedArray* storage) {
9416 return GetLocalElementKeys(storage,
9417 static_cast<PropertyAttributes>(DONT_ENUM));
9418}
9419
9420
Steve Blocka7e24c12009-10-30 11:49:00 +00009421// StringKey simply carries a string object as key.
9422class StringKey : public HashTableKey {
9423 public:
9424 explicit StringKey(String* string) :
9425 string_(string),
9426 hash_(HashForObject(string)) { }
9427
9428 bool IsMatch(Object* string) {
9429 // We know that all entries in a hash table had their hash keys created.
9430 // Use that knowledge to have fast failure.
9431 if (hash_ != HashForObject(string)) {
9432 return false;
9433 }
9434 return string_->Equals(String::cast(string));
9435 }
9436
9437 uint32_t Hash() { return hash_; }
9438
9439 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
9440
9441 Object* AsObject() { return string_; }
9442
9443 String* string_;
9444 uint32_t hash_;
9445};
9446
9447
9448// StringSharedKeys are used as keys in the eval cache.
9449class StringSharedKey : public HashTableKey {
9450 public:
Steve Block1e0659c2011-05-24 12:43:12 +01009451 StringSharedKey(String* source,
9452 SharedFunctionInfo* shared,
9453 StrictModeFlag strict_mode)
9454 : source_(source),
9455 shared_(shared),
9456 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009457
9458 bool IsMatch(Object* other) {
9459 if (!other->IsFixedArray()) return false;
9460 FixedArray* pair = FixedArray::cast(other);
9461 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9462 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01009463 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9464 Smi::cast(pair->get(2))->value());
9465 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009466 String* source = String::cast(pair->get(1));
9467 return source->Equals(source_);
9468 }
9469
9470 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01009471 SharedFunctionInfo* shared,
9472 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009473 uint32_t hash = source->Hash();
9474 if (shared->HasSourceCode()) {
9475 // Instead of using the SharedFunctionInfo pointer in the hash
9476 // code computation, we use a combination of the hash of the
9477 // script source code and the start and end positions. We do
9478 // this to ensure that the cache entries can survive garbage
9479 // collection.
9480 Script* script = Script::cast(shared->script());
9481 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01009482 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00009483 hash += shared->start_position();
9484 }
9485 return hash;
9486 }
9487
9488 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01009489 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009490 }
9491
9492 uint32_t HashForObject(Object* obj) {
9493 FixedArray* pair = FixedArray::cast(obj);
9494 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9495 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01009496 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9497 Smi::cast(pair->get(2))->value());
9498 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009499 }
9500
John Reck59135872010-11-02 12:39:01 -07009501 MUST_USE_RESULT MaybeObject* AsObject() {
9502 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009503 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07009504 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9505 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009506 FixedArray* pair = FixedArray::cast(obj);
9507 pair->set(0, shared_);
9508 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01009509 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00009510 return pair;
9511 }
9512
9513 private:
9514 String* source_;
9515 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01009516 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009517};
9518
9519
9520// RegExpKey carries the source and flags of a regular expression as key.
9521class RegExpKey : public HashTableKey {
9522 public:
9523 RegExpKey(String* string, JSRegExp::Flags flags)
9524 : string_(string),
9525 flags_(Smi::FromInt(flags.value())) { }
9526
Steve Block3ce2e202009-11-05 08:53:23 +00009527 // Rather than storing the key in the hash table, a pointer to the
9528 // stored value is stored where the key should be. IsMatch then
9529 // compares the search key to the found object, rather than comparing
9530 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00009531 bool IsMatch(Object* obj) {
9532 FixedArray* val = FixedArray::cast(obj);
9533 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9534 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9535 }
9536
9537 uint32_t Hash() { return RegExpHash(string_, flags_); }
9538
9539 Object* AsObject() {
9540 // Plain hash maps, which is where regexp keys are used, don't
9541 // use this function.
9542 UNREACHABLE();
9543 return NULL;
9544 }
9545
9546 uint32_t HashForObject(Object* obj) {
9547 FixedArray* val = FixedArray::cast(obj);
9548 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9549 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9550 }
9551
9552 static uint32_t RegExpHash(String* string, Smi* flags) {
9553 return string->Hash() + flags->value();
9554 }
9555
9556 String* string_;
9557 Smi* flags_;
9558};
9559
9560// Utf8SymbolKey carries a vector of chars as key.
9561class Utf8SymbolKey : public HashTableKey {
9562 public:
9563 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00009564 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009565
9566 bool IsMatch(Object* string) {
9567 return String::cast(string)->IsEqualTo(string_);
9568 }
9569
9570 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00009571 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009572 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9573 static_cast<unsigned>(string_.length()));
9574 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00009575 hash_field_ = String::ComputeHashField(&buffer, chars_);
9576 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009577 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9578 return result;
9579 }
9580
9581 uint32_t HashForObject(Object* other) {
9582 return String::cast(other)->Hash();
9583 }
9584
John Reck59135872010-11-02 12:39:01 -07009585 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00009586 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009587 return Isolate::Current()->heap()->AllocateSymbol(
9588 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009589 }
9590
9591 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00009592 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009593 int chars_; // Caches the number of characters when computing the hash code.
9594};
9595
9596
Steve Block9fac8402011-05-12 15:51:54 +01009597template <typename Char>
9598class SequentialSymbolKey : public HashTableKey {
9599 public:
9600 explicit SequentialSymbolKey(Vector<const Char> string)
9601 : string_(string), hash_field_(0) { }
9602
9603 uint32_t Hash() {
9604 StringHasher hasher(string_.length());
9605
9606 // Very long strings have a trivial hash that doesn't inspect the
9607 // string contents.
9608 if (hasher.has_trivial_hash()) {
9609 hash_field_ = hasher.GetHashField();
9610 } else {
9611 int i = 0;
9612 // Do the iterative array index computation as long as there is a
9613 // chance this is an array index.
9614 while (i < string_.length() && hasher.is_array_index()) {
9615 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9616 i++;
9617 }
9618
9619 // Process the remaining characters without updating the array
9620 // index.
9621 while (i < string_.length()) {
9622 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9623 i++;
9624 }
9625 hash_field_ = hasher.GetHashField();
9626 }
9627
9628 uint32_t result = hash_field_ >> String::kHashShift;
9629 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9630 return result;
9631 }
9632
9633
9634 uint32_t HashForObject(Object* other) {
9635 return String::cast(other)->Hash();
9636 }
9637
9638 Vector<const Char> string_;
9639 uint32_t hash_field_;
9640};
9641
9642
9643
9644class AsciiSymbolKey : public SequentialSymbolKey<char> {
9645 public:
9646 explicit AsciiSymbolKey(Vector<const char> str)
9647 : SequentialSymbolKey<char>(str) { }
9648
9649 bool IsMatch(Object* string) {
9650 return String::cast(string)->IsAsciiEqualTo(string_);
9651 }
9652
9653 MaybeObject* AsObject() {
9654 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009655 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009656 }
9657};
9658
9659
Ben Murdoch257744e2011-11-30 15:57:28 +00009660class SubStringAsciiSymbolKey : public HashTableKey {
9661 public:
9662 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9663 int from,
9664 int length)
9665 : string_(string), from_(from), length_(length) { }
9666
9667 uint32_t Hash() {
9668 ASSERT(length_ >= 0);
9669 ASSERT(from_ + length_ <= string_->length());
9670 StringHasher hasher(length_);
9671
9672 // Very long strings have a trivial hash that doesn't inspect the
9673 // string contents.
9674 if (hasher.has_trivial_hash()) {
9675 hash_field_ = hasher.GetHashField();
9676 } else {
9677 int i = 0;
9678 // Do the iterative array index computation as long as there is a
9679 // chance this is an array index.
9680 while (i < length_ && hasher.is_array_index()) {
9681 hasher.AddCharacter(static_cast<uc32>(
9682 string_->SeqAsciiStringGet(i + from_)));
9683 i++;
9684 }
9685
9686 // Process the remaining characters without updating the array
9687 // index.
9688 while (i < length_) {
9689 hasher.AddCharacterNoIndex(static_cast<uc32>(
9690 string_->SeqAsciiStringGet(i + from_)));
9691 i++;
9692 }
9693 hash_field_ = hasher.GetHashField();
9694 }
9695
9696 uint32_t result = hash_field_ >> String::kHashShift;
9697 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9698 return result;
9699 }
9700
9701
9702 uint32_t HashForObject(Object* other) {
9703 return String::cast(other)->Hash();
9704 }
9705
9706 bool IsMatch(Object* string) {
9707 Vector<const char> chars(string_->GetChars() + from_, length_);
9708 return String::cast(string)->IsAsciiEqualTo(chars);
9709 }
9710
9711 MaybeObject* AsObject() {
9712 if (hash_field_ == 0) Hash();
9713 Vector<const char> chars(string_->GetChars() + from_, length_);
9714 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
9715 }
9716
9717 private:
9718 Handle<SeqAsciiString> string_;
9719 int from_;
9720 int length_;
9721 uint32_t hash_field_;
9722};
9723
9724
Steve Block9fac8402011-05-12 15:51:54 +01009725class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
9726 public:
9727 explicit TwoByteSymbolKey(Vector<const uc16> str)
9728 : SequentialSymbolKey<uc16>(str) { }
9729
9730 bool IsMatch(Object* string) {
9731 return String::cast(string)->IsTwoByteEqualTo(string_);
9732 }
9733
9734 MaybeObject* AsObject() {
9735 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009736 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009737 }
9738};
9739
9740
Steve Blocka7e24c12009-10-30 11:49:00 +00009741// SymbolKey carries a string/symbol object as key.
9742class SymbolKey : public HashTableKey {
9743 public:
Steve Block44f0eee2011-05-26 01:26:41 +01009744 explicit SymbolKey(String* string)
9745 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009746
9747 bool IsMatch(Object* string) {
9748 return String::cast(string)->Equals(string_);
9749 }
9750
9751 uint32_t Hash() { return string_->Hash(); }
9752
9753 uint32_t HashForObject(Object* other) {
9754 return String::cast(other)->Hash();
9755 }
9756
John Reck59135872010-11-02 12:39:01 -07009757 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01009758 // Attempt to flatten the string, so that symbols will most often
9759 // be flat strings.
9760 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01009761 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009762 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01009763 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009764 if (map != NULL) {
9765 string_->set_map(map);
9766 ASSERT(string_->IsSymbol());
9767 return string_;
9768 }
9769 // Otherwise allocate a new symbol.
9770 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01009771 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00009772 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00009773 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00009774 }
9775
9776 static uint32_t StringHash(Object* obj) {
9777 return String::cast(obj)->Hash();
9778 }
9779
9780 String* string_;
9781};
9782
9783
9784template<typename Shape, typename Key>
9785void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
9786 IteratePointers(v, 0, kElementsStartOffset);
9787}
9788
9789
9790template<typename Shape, typename Key>
9791void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
9792 IteratePointers(v,
9793 kElementsStartOffset,
9794 kHeaderSize + length() * kPointerSize);
9795}
9796
9797
9798template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009799MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9800 PretenureFlag pretenure) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009801 int capacity = ComputeCapacity(at_least_space_for);
9802 if (capacity > HashTable::kMaxCapacity) {
Leon Clarkee46be812010-01-19 14:06:41 +00009803 return Failure::OutOfMemoryException();
9804 }
9805
John Reck59135872010-11-02 12:39:01 -07009806 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009807 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9808 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07009809 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009810 }
John Reck59135872010-11-02 12:39:01 -07009811 HashTable::cast(obj)->SetNumberOfElements(0);
9812 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9813 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009814 return obj;
9815}
9816
9817
Leon Clarkee46be812010-01-19 14:06:41 +00009818// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009819int StringDictionary::FindEntry(String* key) {
9820 if (!key->IsSymbol()) {
9821 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9822 }
9823
9824 // Optimized for symbol key. Knowledge of the key type allows:
9825 // 1. Move the check if the key is a symbol out of the loop.
9826 // 2. Avoid comparing hash codes in symbol to symbol comparision.
9827 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9828 // In case of positive result the dictionary key may be replaced by
9829 // the symbol with minimal performance penalty. It gives a chance to
9830 // perform further lookups in code stubs (and significant performance boost
9831 // a certain style of code).
9832
9833 // EnsureCapacity will guarantee the hash table is never full.
9834 uint32_t capacity = Capacity();
9835 uint32_t entry = FirstProbe(key->Hash(), capacity);
9836 uint32_t count = 1;
9837
9838 while (true) {
9839 int index = EntryToIndex(entry);
9840 Object* element = get(index);
9841 if (element->IsUndefined()) break; // Empty entry.
9842 if (key == element) return entry;
9843 if (!element->IsSymbol() &&
9844 !element->IsNull() &&
9845 String::cast(element)->Equals(key)) {
9846 // Replace a non-symbol key by the equivalent symbol for faster further
9847 // lookups.
9848 set(index, key);
9849 return entry;
9850 }
9851 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9852 entry = NextProbe(entry, count++, capacity);
9853 }
9854 return kNotFound;
9855}
9856
9857
Steve Blocka7e24c12009-10-30 11:49:00 +00009858template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009859MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
9860 ASSERT(NumberOfElements() < new_table->Capacity());
9861
9862 AssertNoAllocation no_gc;
9863 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
9864
9865 // Copy prefix to new array.
9866 for (int i = kPrefixStartIndex;
9867 i < kPrefixStartIndex + Shape::kPrefixSize;
9868 i++) {
9869 new_table->set(i, get(i), mode);
9870 }
9871
9872 // Rehash the elements.
9873 int capacity = Capacity();
9874 for (int i = 0; i < capacity; i++) {
9875 uint32_t from_index = EntryToIndex(i);
9876 Object* k = get(from_index);
9877 if (IsKey(k)) {
9878 uint32_t hash = Shape::HashForObject(key, k);
9879 uint32_t insertion_index =
9880 EntryToIndex(new_table->FindInsertionEntry(hash));
9881 for (int j = 0; j < Shape::kEntrySize; j++) {
9882 new_table->set(insertion_index + j, get(from_index + j), mode);
9883 }
9884 }
9885 }
9886 new_table->SetNumberOfElements(NumberOfElements());
9887 new_table->SetNumberOfDeletedElements(0);
9888 return new_table;
9889}
9890
9891
9892template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009893MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009894 int capacity = Capacity();
9895 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00009896 int nod = NumberOfDeletedElements();
9897 // Return if:
9898 // 50% is still free after adding n elements and
9899 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01009900 if (nod <= (capacity - nof) >> 1) {
9901 int needed_free = nof >> 1;
9902 if (nof + needed_free <= capacity) return this;
9903 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009904
Steve Block6ded16b2010-05-10 14:33:55 +01009905 const int kMinCapacityForPretenure = 256;
9906 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +01009907 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07009908 Object* obj;
9909 { MaybeObject* maybe_obj =
9910 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9911 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9912 }
Leon Clarke4515c472010-02-03 11:58:03 +00009913
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009914 return Rehash(HashTable::cast(obj), key);
9915}
Steve Blocka7e24c12009-10-30 11:49:00 +00009916
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009917
9918template<typename Shape, typename Key>
9919MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
9920 int capacity = Capacity();
9921 int nof = NumberOfElements();
9922
9923 // Shrink to fit the number of elements if only a quarter of the
9924 // capacity is filled with elements.
9925 if (nof > (capacity >> 2)) return this;
9926 // Allocate a new dictionary with room for at least the current
9927 // number of elements. The allocation method will make sure that
9928 // there is extra room in the dictionary for additions. Don't go
9929 // lower than room for 16 elements.
9930 int at_least_room_for = nof;
9931 if (at_least_room_for < 16) return this;
9932
9933 const int kMinCapacityForPretenure = 256;
9934 bool pretenure =
9935 (at_least_room_for > kMinCapacityForPretenure) &&
9936 !GetHeap()->InNewSpace(this);
9937 Object* obj;
9938 { MaybeObject* maybe_obj =
9939 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
9940 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009941 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009942
9943 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +00009944}
9945
9946
9947template<typename Shape, typename Key>
9948uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
9949 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00009950 uint32_t entry = FirstProbe(hash, capacity);
9951 uint32_t count = 1;
9952 // EnsureCapacity will guarantee the hash table is never full.
9953 while (true) {
9954 Object* element = KeyAt(entry);
9955 if (element->IsUndefined() || element->IsNull()) break;
9956 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009957 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009958 return entry;
9959}
9960
9961// Force instantiation of template instances class.
9962// Please note this list is compiler dependent.
9963
9964template class HashTable<SymbolTableShape, HashTableKey*>;
9965
9966template class HashTable<CompilationCacheShape, HashTableKey*>;
9967
9968template class HashTable<MapCacheShape, HashTableKey*>;
9969
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009970template class HashTable<ObjectHashTableShape, JSObject*>;
9971
Steve Blocka7e24c12009-10-30 11:49:00 +00009972template class Dictionary<StringDictionaryShape, String*>;
9973
9974template class Dictionary<NumberDictionaryShape, uint32_t>;
9975
John Reck59135872010-11-02 12:39:01 -07009976template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00009977 int);
9978
John Reck59135872010-11-02 12:39:01 -07009979template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00009980 int);
9981
John Reck59135872010-11-02 12:39:01 -07009982template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +00009983 uint32_t, Object*);
9984
9985template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9986 Object*);
9987
9988template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9989 Object*);
9990
9991template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009992 FixedArray*,
9993 PropertyAttributes,
9994 Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009995
9996template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9997 int, JSObject::DeleteMode);
9998
9999template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
10000 int, JSObject::DeleteMode);
10001
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010002template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
10003 String*);
10004
10005template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
10006 uint32_t);
10007
Steve Blocka7e24c12009-10-30 11:49:00 +000010008template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010009 FixedArray*,
10010 int,
10011 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010012
10013template int
10014Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
10015 PropertyAttributes);
10016
John Reck59135872010-11-02 12:39:01 -070010017template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010018 String*, Object*, PropertyDetails);
10019
John Reck59135872010-11-02 12:39:01 -070010020template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000010021Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
10022
10023template int
10024Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
10025 PropertyAttributes);
10026
John Reck59135872010-11-02 12:39:01 -070010027template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010028 uint32_t, Object*, PropertyDetails);
10029
John Reck59135872010-11-02 12:39:01 -070010030template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
10031 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010032
John Reck59135872010-11-02 12:39:01 -070010033template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10034 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000010035
John Reck59135872010-11-02 12:39:01 -070010036template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010037 uint32_t, Object*, PropertyDetails, uint32_t);
10038
John Reck59135872010-11-02 12:39:01 -070010039template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010040 String*, Object*, PropertyDetails, uint32_t);
10041
10042template
10043int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
10044
10045template
10046int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
10047
Leon Clarkee46be812010-01-19 14:06:41 +000010048template
10049int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
10050
10051
Steve Blocka7e24c12009-10-30 11:49:00 +000010052// Collates undefined and unexisting elements below limit from position
10053// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070010054MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010055 ASSERT(HasDictionaryElements());
10056 // Must stay in dictionary mode, either because of requires_slow_elements,
10057 // or because we are not going to sort (and therefore compact) all of the
10058 // elements.
10059 NumberDictionary* dict = element_dictionary();
10060 HeapNumber* result_double = NULL;
10061 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10062 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070010063 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010064 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010065 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10066 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010067 result_double = HeapNumber::cast(new_double);
10068 }
10069
John Reck59135872010-11-02 12:39:01 -070010070 Object* obj;
10071 { MaybeObject* maybe_obj =
10072 NumberDictionary::Allocate(dict->NumberOfElements());
10073 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10074 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010075 NumberDictionary* new_dict = NumberDictionary::cast(obj);
10076
10077 AssertNoAllocation no_alloc;
10078
10079 uint32_t pos = 0;
10080 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010010081 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000010082 for (int i = 0; i < capacity; i++) {
10083 Object* k = dict->KeyAt(i);
10084 if (dict->IsKey(k)) {
10085 ASSERT(k->IsNumber());
10086 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10087 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10088 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10089 Object* value = dict->ValueAt(i);
10090 PropertyDetails details = dict->DetailsAt(i);
10091 if (details.type() == CALLBACKS) {
10092 // Bail out and do the sorting of undefineds and array holes in JS.
10093 return Smi::FromInt(-1);
10094 }
10095 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070010096 // In the following we assert that adding the entry to the new dictionary
10097 // does not cause GC. This is the case because we made sure to allocate
10098 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000010099 if (key < limit) {
10100 if (value->IsUndefined()) {
10101 undefs++;
10102 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010103 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10104 // Adding an entry with the key beyond smi-range requires
10105 // allocation. Bailout.
10106 return Smi::FromInt(-1);
10107 }
John Reck59135872010-11-02 12:39:01 -070010108 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010109 pos++;
10110 }
10111 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010112 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10113 // Adding an entry with the key beyond smi-range requires
10114 // allocation. Bailout.
10115 return Smi::FromInt(-1);
10116 }
John Reck59135872010-11-02 12:39:01 -070010117 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010118 }
10119 }
10120 }
10121
10122 uint32_t result = pos;
10123 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010124 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010125 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010010126 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10127 // Adding an entry with the key beyond smi-range requires
10128 // allocation. Bailout.
10129 return Smi::FromInt(-1);
10130 }
Steve Block44f0eee2011-05-26 01:26:41 +010010131 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070010132 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010133 pos++;
10134 undefs--;
10135 }
10136
10137 set_elements(new_dict);
10138
10139 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10140 return Smi::FromInt(static_cast<int>(result));
10141 }
10142
10143 ASSERT_NE(NULL, result_double);
10144 result_double->set_value(static_cast<double>(result));
10145 return result_double;
10146}
10147
10148
10149// Collects all defined (non-hole) and non-undefined (array) elements at
10150// the start of the elements array.
10151// If the object is in dictionary mode, it is converted to fast elements
10152// mode.
John Reck59135872010-11-02 12:39:01 -070010153MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010154 Heap* heap = GetHeap();
10155
Steve Blocka7e24c12009-10-30 11:49:00 +000010156 if (HasDictionaryElements()) {
10157 // Convert to fast elements containing only the existing properties.
10158 // Ordering is irrelevant, since we are going to sort anyway.
10159 NumberDictionary* dict = element_dictionary();
10160 if (IsJSArray() || dict->requires_slow_elements() ||
10161 dict->max_number_key() >= limit) {
10162 return PrepareSlowElementsForSort(limit);
10163 }
10164 // Convert to fast elements.
10165
John Reck59135872010-11-02 12:39:01 -070010166 Object* obj;
10167 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
10168 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10169 }
Steve Block8defd9f2010-07-08 12:39:36 +010010170 Map* new_map = Map::cast(obj);
10171
Steve Block44f0eee2011-05-26 01:26:41 +010010172 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070010173 Object* new_array;
10174 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010175 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070010176 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
10177 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010178 FixedArray* fast_elements = FixedArray::cast(new_array);
10179 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010010180
10181 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000010182 set_elements(fast_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010183 } else if (HasExternalArrayElements()) {
10184 // External arrays cannot have holes or undefined elements.
10185 return Smi::FromInt(ExternalArray::cast(elements())->length());
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010186 } else if (!HasFastDoubleElements()) {
John Reck59135872010-11-02 12:39:01 -070010187 Object* obj;
10188 { MaybeObject* maybe_obj = EnsureWritableFastElements();
10189 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10190 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010191 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010192 ASSERT(HasFastElements() || HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000010193
10194 // Collect holes at the end, undefined before that and the rest at the
10195 // start, and return the number of non-hole, non-undefined values.
10196
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010197 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
10198 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010199 if (limit > elements_length) {
10200 limit = elements_length ;
10201 }
10202 if (limit == 0) {
10203 return Smi::FromInt(0);
10204 }
10205
10206 HeapNumber* result_double = NULL;
10207 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10208 // Pessimistically allocate space for return value before
10209 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070010210 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010010211 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010212 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10213 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010214 result_double = HeapNumber::cast(new_double);
10215 }
10216
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010217 uint32_t result = 0;
10218 if (elements_base->map() == heap->fixed_double_array_map()) {
10219 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
10220 // Split elements into defined and the_hole, in that order.
10221 unsigned int holes = limit;
10222 // Assume most arrays contain no holes and undefined values, so minimize the
10223 // number of stores of non-undefined, non-the-hole values.
10224 for (unsigned int i = 0; i < holes; i++) {
10225 if (elements->is_the_hole(i)) {
10226 holes--;
10227 } else {
10228 continue;
10229 }
10230 // Position i needs to be filled.
10231 while (holes > i) {
10232 if (elements->is_the_hole(holes)) {
10233 holes--;
10234 } else {
10235 elements->set(i, elements->get_scalar(holes));
10236 break;
10237 }
10238 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010239 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010240 result = holes;
10241 while (holes < limit) {
10242 elements->set_the_hole(holes);
10243 holes++;
10244 }
10245 } else {
10246 FixedArray* elements = FixedArray::cast(elements_base);
10247 AssertNoAllocation no_alloc;
10248
10249 // Split elements into defined, undefined and the_hole, in that order. Only
10250 // count locations for undefined and the hole, and fill them afterwards.
10251 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
10252 unsigned int undefs = limit;
10253 unsigned int holes = limit;
10254 // Assume most arrays contain no holes and undefined values, so minimize the
10255 // number of stores of non-undefined, non-the-hole values.
10256 for (unsigned int i = 0; i < undefs; i++) {
10257 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000010258 if (current->IsTheHole()) {
10259 holes--;
10260 undefs--;
10261 } else if (current->IsUndefined()) {
10262 undefs--;
10263 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010264 continue;
10265 }
10266 // Position i needs to be filled.
10267 while (undefs > i) {
10268 current = elements->get(undefs);
10269 if (current->IsTheHole()) {
10270 holes--;
10271 undefs--;
10272 } else if (current->IsUndefined()) {
10273 undefs--;
10274 } else {
10275 elements->set(i, current, write_barrier);
10276 break;
10277 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010278 }
10279 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010280 result = undefs;
10281 while (undefs < holes) {
10282 elements->set_undefined(undefs);
10283 undefs++;
10284 }
10285 while (holes < limit) {
10286 elements->set_the_hole(holes);
10287 holes++;
10288 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010289 }
10290
10291 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10292 return Smi::FromInt(static_cast<int>(result));
10293 }
10294 ASSERT_NE(NULL, result_double);
10295 result_double->set_value(static_cast<double>(result));
10296 return result_double;
10297}
10298
10299
Steve Block44f0eee2011-05-26 01:26:41 +010010300Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010301 uint8_t clamped_value = 0;
10302 if (index < static_cast<uint32_t>(length())) {
10303 if (value->IsSmi()) {
10304 int int_value = Smi::cast(value)->value();
10305 if (int_value < 0) {
10306 clamped_value = 0;
10307 } else if (int_value > 255) {
10308 clamped_value = 255;
10309 } else {
10310 clamped_value = static_cast<uint8_t>(int_value);
10311 }
10312 } else if (value->IsHeapNumber()) {
10313 double double_value = HeapNumber::cast(value)->value();
10314 if (!(double_value > 0)) {
10315 // NaN and less than zero clamp to zero.
10316 clamped_value = 0;
10317 } else if (double_value > 255) {
10318 // Greater than 255 clamp to 255.
10319 clamped_value = 255;
10320 } else {
10321 // Other doubles are rounded to the nearest integer.
10322 clamped_value = static_cast<uint8_t>(double_value + 0.5);
10323 }
10324 } else {
10325 // Clamp undefined to zero (default). All other types have been
10326 // converted to a number type further up in the call chain.
10327 ASSERT(value->IsUndefined());
10328 }
10329 set(index, clamped_value);
10330 }
10331 return Smi::FromInt(clamped_value);
10332}
10333
10334
Steve Block3ce2e202009-11-05 08:53:23 +000010335template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010010336static MaybeObject* ExternalArrayIntSetter(Heap* heap,
10337 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070010338 uint32_t index,
10339 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010340 ValueType cast_value = 0;
10341 if (index < static_cast<uint32_t>(receiver->length())) {
10342 if (value->IsSmi()) {
10343 int int_value = Smi::cast(value)->value();
10344 cast_value = static_cast<ValueType>(int_value);
10345 } else if (value->IsHeapNumber()) {
10346 double double_value = HeapNumber::cast(value)->value();
10347 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10348 } else {
10349 // Clamp undefined to zero (default). All other types have been
10350 // converted to a number type further up in the call chain.
10351 ASSERT(value->IsUndefined());
10352 }
10353 receiver->set(index, cast_value);
10354 }
Steve Block44f0eee2011-05-26 01:26:41 +010010355 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010356}
10357
10358
John Reck59135872010-11-02 12:39:01 -070010359MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010360 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010361 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010362}
10363
10364
John Reck59135872010-11-02 12:39:01 -070010365MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10366 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010367 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010368 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010369}
10370
10371
John Reck59135872010-11-02 12:39:01 -070010372MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10373 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010374 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010375 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010376}
10377
10378
John Reck59135872010-11-02 12:39:01 -070010379MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10380 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010381 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010382 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010383}
10384
10385
John Reck59135872010-11-02 12:39:01 -070010386MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010387 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010388 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010389}
10390
10391
John Reck59135872010-11-02 12:39:01 -070010392MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010393 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010394 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010395 if (index < static_cast<uint32_t>(length())) {
10396 if (value->IsSmi()) {
10397 int int_value = Smi::cast(value)->value();
10398 cast_value = static_cast<uint32_t>(int_value);
10399 } else if (value->IsHeapNumber()) {
10400 double double_value = HeapNumber::cast(value)->value();
10401 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10402 } else {
10403 // Clamp undefined to zero (default). All other types have been
10404 // converted to a number type further up in the call chain.
10405 ASSERT(value->IsUndefined());
10406 }
10407 set(index, cast_value);
10408 }
Steve Block44f0eee2011-05-26 01:26:41 +010010409 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010410}
10411
10412
John Reck59135872010-11-02 12:39:01 -070010413MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010414 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010415 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010416 if (index < static_cast<uint32_t>(length())) {
10417 if (value->IsSmi()) {
10418 int int_value = Smi::cast(value)->value();
10419 cast_value = static_cast<float>(int_value);
10420 } else if (value->IsHeapNumber()) {
10421 double double_value = HeapNumber::cast(value)->value();
10422 cast_value = static_cast<float>(double_value);
10423 } else {
10424 // Clamp undefined to zero (default). All other types have been
10425 // converted to a number type further up in the call chain.
10426 ASSERT(value->IsUndefined());
10427 }
10428 set(index, cast_value);
10429 }
Steve Block44f0eee2011-05-26 01:26:41 +010010430 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010431}
10432
10433
Ben Murdoch257744e2011-11-30 15:57:28 +000010434MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
10435 double double_value = 0;
10436 Heap* heap = GetHeap();
10437 if (index < static_cast<uint32_t>(length())) {
10438 if (value->IsSmi()) {
10439 int int_value = Smi::cast(value)->value();
10440 double_value = static_cast<double>(int_value);
10441 } else if (value->IsHeapNumber()) {
10442 double_value = HeapNumber::cast(value)->value();
10443 } else {
10444 // Clamp undefined to zero (default). All other types have been
10445 // converted to a number type further up in the call chain.
10446 ASSERT(value->IsUndefined());
10447 }
10448 set(index, double_value);
10449 }
10450 return heap->AllocateHeapNumber(double_value);
10451}
10452
10453
Ben Murdochb0fe1622011-05-05 13:52:32 +010010454JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010455 ASSERT(!HasFastProperties());
10456 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010457 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010458}
10459
10460
John Reck59135872010-11-02 12:39:01 -070010461MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010462 ASSERT(!HasFastProperties());
10463 int entry = property_dictionary()->FindEntry(name);
10464 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010465 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070010466 Object* cell;
10467 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010010468 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070010469 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10470 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010471 PropertyDetails details(NONE, NORMAL);
10472 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070010473 Object* dictionary;
10474 { MaybeObject* maybe_dictionary =
10475 property_dictionary()->Add(name, cell, details);
10476 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10477 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010478 set_properties(StringDictionary::cast(dictionary));
10479 return cell;
10480 } else {
10481 Object* value = property_dictionary()->ValueAt(entry);
10482 ASSERT(value->IsJSGlobalPropertyCell());
10483 return value;
10484 }
10485}
10486
10487
John Reck59135872010-11-02 12:39:01 -070010488MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010489 SymbolKey key(string);
10490 return LookupKey(&key, s);
10491}
10492
10493
Steve Blockd0582a62009-12-15 09:54:21 +000010494// This class is used for looking up two character strings in the symbol table.
10495// If we don't have a hit we don't want to waste much time so we unroll the
10496// string hash calculation loop here for speed. Doesn't work if the two
10497// characters form a decimal integer, since such strings have a different hash
10498// algorithm.
10499class TwoCharHashTableKey : public HashTableKey {
10500 public:
10501 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
10502 : c1_(c1), c2_(c2) {
10503 // Char 1.
10504 uint32_t hash = c1 + (c1 << 10);
10505 hash ^= hash >> 6;
10506 // Char 2.
10507 hash += c2;
10508 hash += hash << 10;
10509 hash ^= hash >> 6;
10510 // GetHash.
10511 hash += hash << 3;
10512 hash ^= hash >> 11;
10513 hash += hash << 15;
10514 if (hash == 0) hash = 27;
10515#ifdef DEBUG
10516 StringHasher hasher(2);
10517 hasher.AddCharacter(c1);
10518 hasher.AddCharacter(c2);
10519 // If this assert fails then we failed to reproduce the two-character
10520 // version of the string hashing algorithm above. One reason could be
10521 // that we were passed two digits as characters, since the hash
10522 // algorithm is different in that case.
10523 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10524#endif
10525 hash_ = hash;
10526 }
10527
10528 bool IsMatch(Object* o) {
10529 if (!o->IsString()) return false;
10530 String* other = String::cast(o);
10531 if (other->length() != 2) return false;
10532 if (other->Get(0) != c1_) return false;
10533 return other->Get(1) == c2_;
10534 }
10535
10536 uint32_t Hash() { return hash_; }
10537 uint32_t HashForObject(Object* key) {
10538 if (!key->IsString()) return 0;
10539 return String::cast(key)->Hash();
10540 }
10541
10542 Object* AsObject() {
10543 // The TwoCharHashTableKey is only used for looking in the symbol
10544 // table, not for adding to it.
10545 UNREACHABLE();
10546 return NULL;
10547 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010548
Steve Blockd0582a62009-12-15 09:54:21 +000010549 private:
10550 uint32_t c1_;
10551 uint32_t c2_;
10552 uint32_t hash_;
10553};
10554
10555
Steve Blocka7e24c12009-10-30 11:49:00 +000010556bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10557 SymbolKey key(string);
10558 int entry = FindEntry(&key);
10559 if (entry == kNotFound) {
10560 return false;
10561 } else {
10562 String* result = String::cast(KeyAt(entry));
10563 ASSERT(StringShape(result).IsSymbol());
10564 *symbol = result;
10565 return true;
10566 }
10567}
10568
10569
Steve Blockd0582a62009-12-15 09:54:21 +000010570bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10571 uint32_t c2,
10572 String** symbol) {
10573 TwoCharHashTableKey key(c1, c2);
10574 int entry = FindEntry(&key);
10575 if (entry == kNotFound) {
10576 return false;
10577 } else {
10578 String* result = String::cast(KeyAt(entry));
10579 ASSERT(StringShape(result).IsSymbol());
10580 *symbol = result;
10581 return true;
10582 }
10583}
10584
10585
John Reck59135872010-11-02 12:39:01 -070010586MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010587 Utf8SymbolKey key(str);
10588 return LookupKey(&key, s);
10589}
10590
10591
Steve Block9fac8402011-05-12 15:51:54 +010010592MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10593 Object** s) {
10594 AsciiSymbolKey key(str);
10595 return LookupKey(&key, s);
10596}
10597
10598
Ben Murdoch257744e2011-11-30 15:57:28 +000010599MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10600 int from,
10601 int length,
10602 Object** s) {
10603 SubStringAsciiSymbolKey key(str, from, length);
10604 return LookupKey(&key, s);
10605}
10606
10607
Steve Block9fac8402011-05-12 15:51:54 +010010608MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10609 Object** s) {
10610 TwoByteSymbolKey key(str);
10611 return LookupKey(&key, s);
10612}
10613
John Reck59135872010-11-02 12:39:01 -070010614MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010615 int entry = FindEntry(key);
10616
10617 // Symbol already in table.
10618 if (entry != kNotFound) {
10619 *s = KeyAt(entry);
10620 return this;
10621 }
10622
10623 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -070010624 Object* obj;
10625 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10626 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10627 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010628
10629 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070010630 Object* symbol;
10631 { MaybeObject* maybe_symbol = key->AsObject();
10632 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10633 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010634
10635 // If the symbol table grew as part of EnsureCapacity, obj is not
10636 // the current symbol table and therefore we cannot use
10637 // SymbolTable::cast here.
10638 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10639
10640 // Add the new symbol and return it along with the symbol table.
10641 entry = table->FindInsertionEntry(key->Hash());
10642 table->set(EntryToIndex(entry), symbol);
10643 table->ElementAdded();
10644 *s = symbol;
10645 return table;
10646}
10647
10648
10649Object* CompilationCacheTable::Lookup(String* src) {
10650 StringKey key(src);
10651 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010652 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010653 return get(EntryToIndex(entry) + 1);
10654}
10655
10656
Steve Block1e0659c2011-05-24 12:43:12 +010010657Object* CompilationCacheTable::LookupEval(String* src,
10658 Context* context,
10659 StrictModeFlag strict_mode) {
10660 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010661 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010010662 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010663 return get(EntryToIndex(entry) + 1);
10664}
10665
10666
10667Object* CompilationCacheTable::LookupRegExp(String* src,
10668 JSRegExp::Flags flags) {
10669 RegExpKey key(src, flags);
10670 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010671 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010672 return get(EntryToIndex(entry) + 1);
10673}
10674
10675
John Reck59135872010-11-02 12:39:01 -070010676MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010677 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070010678 Object* obj;
10679 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10680 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10681 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010682
10683 CompilationCacheTable* cache =
10684 reinterpret_cast<CompilationCacheTable*>(obj);
10685 int entry = cache->FindInsertionEntry(key.Hash());
10686 cache->set(EntryToIndex(entry), src);
10687 cache->set(EntryToIndex(entry) + 1, value);
10688 cache->ElementAdded();
10689 return cache;
10690}
10691
10692
John Reck59135872010-11-02 12:39:01 -070010693MaybeObject* CompilationCacheTable::PutEval(String* src,
10694 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +010010695 SharedFunctionInfo* value) {
10696 StringSharedKey key(src,
10697 context->closure()->shared(),
10698 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070010699 Object* obj;
10700 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10701 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10702 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010703
10704 CompilationCacheTable* cache =
10705 reinterpret_cast<CompilationCacheTable*>(obj);
10706 int entry = cache->FindInsertionEntry(key.Hash());
10707
John Reck59135872010-11-02 12:39:01 -070010708 Object* k;
10709 { MaybeObject* maybe_k = key.AsObject();
10710 if (!maybe_k->ToObject(&k)) return maybe_k;
10711 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010712
10713 cache->set(EntryToIndex(entry), k);
10714 cache->set(EntryToIndex(entry) + 1, value);
10715 cache->ElementAdded();
10716 return cache;
10717}
10718
10719
John Reck59135872010-11-02 12:39:01 -070010720MaybeObject* CompilationCacheTable::PutRegExp(String* src,
10721 JSRegExp::Flags flags,
10722 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010723 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070010724 Object* obj;
10725 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10726 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10727 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010728
10729 CompilationCacheTable* cache =
10730 reinterpret_cast<CompilationCacheTable*>(obj);
10731 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000010732 // We store the value in the key slot, and compare the search key
10733 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000010734 cache->set(EntryToIndex(entry), value);
10735 cache->set(EntryToIndex(entry) + 1, value);
10736 cache->ElementAdded();
10737 return cache;
10738}
10739
10740
Ben Murdochb0fe1622011-05-05 13:52:32 +010010741void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +010010742 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010743 for (int entry = 0, size = Capacity(); entry < size; entry++) {
10744 int entry_index = EntryToIndex(entry);
10745 int value_index = entry_index + 1;
10746 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +010010747 fast_set(this, entry_index, null_value);
10748 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010749 ElementRemoved();
10750 }
10751 }
10752 return;
10753}
10754
10755
Steve Blocka7e24c12009-10-30 11:49:00 +000010756// SymbolsKey used for HashTable where key is array of symbols.
10757class SymbolsKey : public HashTableKey {
10758 public:
10759 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
10760
10761 bool IsMatch(Object* symbols) {
10762 FixedArray* o = FixedArray::cast(symbols);
10763 int len = symbols_->length();
10764 if (o->length() != len) return false;
10765 for (int i = 0; i < len; i++) {
10766 if (o->get(i) != symbols_->get(i)) return false;
10767 }
10768 return true;
10769 }
10770
10771 uint32_t Hash() { return HashForObject(symbols_); }
10772
10773 uint32_t HashForObject(Object* obj) {
10774 FixedArray* symbols = FixedArray::cast(obj);
10775 int len = symbols->length();
10776 uint32_t hash = 0;
10777 for (int i = 0; i < len; i++) {
10778 hash ^= String::cast(symbols->get(i))->Hash();
10779 }
10780 return hash;
10781 }
10782
10783 Object* AsObject() { return symbols_; }
10784
10785 private:
10786 FixedArray* symbols_;
10787};
10788
10789
10790Object* MapCache::Lookup(FixedArray* array) {
10791 SymbolsKey key(array);
10792 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010793 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010794 return get(EntryToIndex(entry) + 1);
10795}
10796
10797
John Reck59135872010-11-02 12:39:01 -070010798MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010799 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070010800 Object* obj;
10801 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10802 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10803 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010804
10805 MapCache* cache = reinterpret_cast<MapCache*>(obj);
10806 int entry = cache->FindInsertionEntry(key.Hash());
10807 cache->set(EntryToIndex(entry), array);
10808 cache->set(EntryToIndex(entry) + 1, value);
10809 cache->ElementAdded();
10810 return cache;
10811}
10812
10813
10814template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010815MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
10816 Object* obj;
10817 { MaybeObject* maybe_obj =
10818 HashTable<Shape, Key>::Allocate(at_least_space_for);
10819 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010820 }
John Reck59135872010-11-02 12:39:01 -070010821 // Initialize the next enumeration index.
10822 Dictionary<Shape, Key>::cast(obj)->
10823 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000010824 return obj;
10825}
10826
10827
10828template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010829MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010010830 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010831 int length = HashTable<Shape, Key>::NumberOfElements();
10832
10833 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070010834 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010010835 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070010836 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10837 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010838 FixedArray* iteration_order = FixedArray::cast(obj);
10839 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000010840 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010841 }
10842
10843 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010010844 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070010845 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10846 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010847 FixedArray* enumeration_order = FixedArray::cast(obj);
10848
10849 // Fill the enumeration order array with property details.
10850 int capacity = HashTable<Shape, Key>::Capacity();
10851 int pos = 0;
10852 for (int i = 0; i < capacity; i++) {
10853 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000010854 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010855 }
10856 }
10857
10858 // Sort the arrays wrt. enumeration order.
10859 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
10860
10861 // Overwrite the enumeration_order with the enumeration indices.
10862 for (int i = 0; i < length; i++) {
10863 int index = Smi::cast(iteration_order->get(i))->value();
10864 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000010865 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000010866 }
10867
10868 // Update the dictionary with new indices.
10869 capacity = HashTable<Shape, Key>::Capacity();
10870 pos = 0;
10871 for (int i = 0; i < capacity; i++) {
10872 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
10873 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10874 PropertyDetails details = DetailsAt(i);
10875 PropertyDetails new_details =
10876 PropertyDetails(details.attributes(), details.type(), enum_index);
10877 DetailsAtPut(i, new_details);
10878 }
10879 }
10880
10881 // Set the next enumeration index.
10882 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10883 return this;
10884}
10885
10886template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010887MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010888 // Check whether there are enough enumeration indices to add n elements.
10889 if (Shape::kIsEnumerable &&
10890 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10891 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070010892 Object* result;
10893 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10894 if (!maybe_result->ToObject(&result)) return maybe_result;
10895 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010896 }
10897 return HashTable<Shape, Key>::EnsureCapacity(n, key);
10898}
10899
10900
10901void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
10902 // Do nothing if the interval [from, to) is empty.
10903 if (from >= to) return;
10904
Steve Block44f0eee2011-05-26 01:26:41 +010010905 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010906 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010907 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010908 int capacity = Capacity();
10909 for (int i = 0; i < capacity; i++) {
10910 Object* key = KeyAt(i);
10911 if (key->IsNumber()) {
10912 uint32_t number = static_cast<uint32_t>(key->Number());
10913 if (from <= number && number < to) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010914 SetEntry(i, sentinel, sentinel);
Steve Blocka7e24c12009-10-30 11:49:00 +000010915 removed_entries++;
10916 }
10917 }
10918 }
10919
10920 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +000010921 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +000010922}
10923
10924
10925template<typename Shape, typename Key>
10926Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010927 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010010928 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010929 PropertyDetails details = DetailsAt(entry);
10930 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010931 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010010932 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010933 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010934 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010935 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010010936 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010937}
10938
10939
10940template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010941MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
10942 return HashTable<Shape, Key>::Shrink(key);
10943}
10944
10945
10946template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010947MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010948 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010949
10950 // If the entry is present set the value;
10951 if (entry != Dictionary<Shape, Key>::kNotFound) {
10952 ValueAtPut(entry, value);
10953 return this;
10954 }
10955
10956 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010957 Object* obj;
10958 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10959 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10960 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010961
John Reck59135872010-11-02 12:39:01 -070010962 Object* k;
10963 { MaybeObject* maybe_k = Shape::AsObject(key);
10964 if (!maybe_k->ToObject(&k)) return maybe_k;
10965 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010966 PropertyDetails details = PropertyDetails(NONE, NORMAL);
10967 return Dictionary<Shape, Key>::cast(obj)->
10968 AddEntry(key, value, details, Shape::Hash(key));
10969}
10970
10971
10972template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010973MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10974 Object* value,
10975 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010976 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010977 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000010978 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010979 Object* obj;
10980 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10981 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10982 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010983 return Dictionary<Shape, Key>::cast(obj)->
10984 AddEntry(key, value, details, Shape::Hash(key));
10985}
10986
10987
10988// Add a key, value pair to the dictionary.
10989template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010990MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
10991 Object* value,
10992 PropertyDetails details,
10993 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010994 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070010995 Object* k;
10996 { MaybeObject* maybe_k = Shape::AsObject(key);
10997 if (!maybe_k->ToObject(&k)) return maybe_k;
10998 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010999
11000 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
11001 // Insert element at empty or deleted entry
11002 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
11003 // Assign an enumeration index to the property and update
11004 // SetNextEnumerationIndex.
11005 int index = NextEnumerationIndex();
11006 details = PropertyDetails(details.attributes(), details.type(), index);
11007 SetNextEnumerationIndex(index + 1);
11008 }
11009 SetEntry(entry, k, value, details);
11010 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
11011 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
11012 HashTable<Shape, Key>::ElementAdded();
11013 return this;
11014}
11015
11016
11017void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
11018 // If the dictionary requires slow elements an element has already
11019 // been added at a high index.
11020 if (requires_slow_elements()) return;
11021 // Check if this index is high enough that we should require slow
11022 // elements.
11023 if (key > kRequiresSlowElementsLimit) {
11024 set_requires_slow_elements();
11025 return;
11026 }
11027 // Update max key value.
11028 Object* max_index_object = get(kMaxNumberKeyIndex);
11029 if (!max_index_object->IsSmi() || max_number_key() < key) {
11030 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000011031 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000011032 }
11033}
11034
11035
John Reck59135872010-11-02 12:39:01 -070011036MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
11037 Object* value,
11038 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011039 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011040 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000011041 return Add(key, value, details);
11042}
11043
11044
John Reck59135872010-11-02 12:39:01 -070011045MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011046 UpdateMaxNumberKey(key);
11047 return AtPut(key, value);
11048}
11049
11050
John Reck59135872010-11-02 12:39:01 -070011051MaybeObject* NumberDictionary::Set(uint32_t key,
11052 Object* value,
11053 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011054 int entry = FindEntry(key);
11055 if (entry == kNotFound) return AddNumberEntry(key, value, details);
11056 // Preserve enumeration index.
11057 details = PropertyDetails(details.attributes(),
11058 details.type(),
11059 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -070011060 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
11061 Object* object_key;
11062 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010011063 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011064 return this;
11065}
11066
11067
11068
11069template<typename Shape, typename Key>
11070int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11071 PropertyAttributes filter) {
11072 int capacity = HashTable<Shape, Key>::Capacity();
11073 int result = 0;
11074 for (int i = 0; i < capacity; i++) {
11075 Object* k = HashTable<Shape, Key>::KeyAt(i);
11076 if (HashTable<Shape, Key>::IsKey(k)) {
11077 PropertyDetails details = DetailsAt(i);
11078 if (details.IsDeleted()) continue;
11079 PropertyAttributes attr = details.attributes();
11080 if ((attr & filter) == 0) result++;
11081 }
11082 }
11083 return result;
11084}
11085
11086
11087template<typename Shape, typename Key>
11088int Dictionary<Shape, Key>::NumberOfEnumElements() {
11089 return NumberOfElementsFilterAttributes(
11090 static_cast<PropertyAttributes>(DONT_ENUM));
11091}
11092
11093
11094template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011095void Dictionary<Shape, Key>::CopyKeysTo(
11096 FixedArray* storage,
11097 PropertyAttributes filter,
11098 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011099 ASSERT(storage->length() >= NumberOfEnumElements());
11100 int capacity = HashTable<Shape, Key>::Capacity();
11101 int index = 0;
11102 for (int i = 0; i < capacity; i++) {
11103 Object* k = HashTable<Shape, Key>::KeyAt(i);
11104 if (HashTable<Shape, Key>::IsKey(k)) {
11105 PropertyDetails details = DetailsAt(i);
11106 if (details.IsDeleted()) continue;
11107 PropertyAttributes attr = details.attributes();
11108 if ((attr & filter) == 0) storage->set(index++, k);
11109 }
11110 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011111 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11112 storage->SortPairs(storage, index);
11113 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011114 ASSERT(storage->length() >= index);
11115}
11116
11117
11118void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11119 FixedArray* sort_array) {
11120 ASSERT(storage->length() >= NumberOfEnumElements());
11121 int capacity = Capacity();
11122 int index = 0;
11123 for (int i = 0; i < capacity; i++) {
11124 Object* k = KeyAt(i);
11125 if (IsKey(k)) {
11126 PropertyDetails details = DetailsAt(i);
11127 if (details.IsDeleted() || details.IsDontEnum()) continue;
11128 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000011129 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011130 index++;
11131 }
11132 }
11133 storage->SortPairs(sort_array, sort_array->length());
11134 ASSERT(storage->length() >= index);
11135}
11136
11137
11138template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010011139void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000011140 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011141 int index,
11142 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011143 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11144 static_cast<PropertyAttributes>(NONE)));
11145 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011146 for (int i = 0; i < capacity; i++) {
11147 Object* k = HashTable<Shape, Key>::KeyAt(i);
11148 if (HashTable<Shape, Key>::IsKey(k)) {
11149 PropertyDetails details = DetailsAt(i);
11150 if (details.IsDeleted()) continue;
11151 storage->set(index++, k);
11152 }
11153 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011154 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11155 storage->SortPairs(storage, index);
11156 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011157 ASSERT(storage->length() >= index);
11158}
11159
11160
11161// Backwards lookup (slow).
11162template<typename Shape, typename Key>
11163Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11164 int capacity = HashTable<Shape, Key>::Capacity();
11165 for (int i = 0; i < capacity; i++) {
11166 Object* k = HashTable<Shape, Key>::KeyAt(i);
11167 if (Dictionary<Shape, Key>::IsKey(k)) {
11168 Object* e = ValueAt(i);
11169 if (e->IsJSGlobalPropertyCell()) {
11170 e = JSGlobalPropertyCell::cast(e)->value();
11171 }
11172 if (e == value) return k;
11173 }
11174 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010011175 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011176 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011177}
11178
11179
John Reck59135872010-11-02 12:39:01 -070011180MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000011181 JSObject* obj, int unused_property_fields) {
11182 // Make sure we preserve dictionary representation if there are too many
11183 // descriptors.
11184 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
11185
11186 // Figure out if it is necessary to generate new enumeration indices.
11187 int max_enumeration_index =
11188 NextEnumerationIndex() +
11189 (DescriptorArray::kMaxNumberOfDescriptors -
11190 NumberOfElements());
11191 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070011192 Object* result;
11193 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11194 if (!maybe_result->ToObject(&result)) return maybe_result;
11195 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011196 }
11197
11198 int instance_descriptor_length = 0;
11199 int number_of_fields = 0;
11200
Ben Murdoch8b112d22011-06-08 16:22:53 +010011201 Heap* heap = GetHeap();
11202
Steve Blocka7e24c12009-10-30 11:49:00 +000011203 // Compute the length of the instance descriptor.
11204 int capacity = Capacity();
11205 for (int i = 0; i < capacity; i++) {
11206 Object* k = KeyAt(i);
11207 if (IsKey(k)) {
11208 Object* value = ValueAt(i);
11209 PropertyType type = DetailsAt(i).type();
11210 ASSERT(type != FIELD);
11211 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000011212 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010011213 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000011214 number_of_fields += 1;
11215 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011216 }
11217 }
11218
11219 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011220 Object* descriptors_unchecked;
11221 { MaybeObject* maybe_descriptors_unchecked =
11222 DescriptorArray::Allocate(instance_descriptor_length);
11223 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
11224 return maybe_descriptors_unchecked;
11225 }
11226 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011227 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
11228
11229 int inobject_props = obj->map()->inobject_properties();
11230 int number_of_allocated_fields =
11231 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010011232 if (number_of_allocated_fields < 0) {
11233 // There is enough inobject space for all fields (including unused).
11234 number_of_allocated_fields = 0;
11235 unused_property_fields = inobject_props - number_of_fields;
11236 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011237
11238 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070011239 Object* fields;
11240 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010011241 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070011242 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
11243 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011244
11245 // Fill in the instance descriptor and the fields.
11246 int next_descriptor = 0;
11247 int current_offset = 0;
11248 for (int i = 0; i < capacity; i++) {
11249 Object* k = KeyAt(i);
11250 if (IsKey(k)) {
11251 Object* value = ValueAt(i);
11252 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011253 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010011254 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070011255 if (!maybe_key->ToObject(&key)) return maybe_key;
11256 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011257 PropertyDetails details = DetailsAt(i);
11258 PropertyType type = details.type();
11259
Steve Block44f0eee2011-05-26 01:26:41 +010011260 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011261 ConstantFunctionDescriptor d(String::cast(key),
11262 JSFunction::cast(value),
11263 details.attributes(),
11264 details.index());
11265 descriptors->Set(next_descriptor++, &d);
11266 } else if (type == NORMAL) {
11267 if (current_offset < inobject_props) {
11268 obj->InObjectPropertyAtPut(current_offset,
11269 value,
11270 UPDATE_WRITE_BARRIER);
11271 } else {
11272 int offset = current_offset - inobject_props;
11273 FixedArray::cast(fields)->set(offset, value);
11274 }
11275 FieldDescriptor d(String::cast(key),
11276 current_offset++,
11277 details.attributes(),
11278 details.index());
11279 descriptors->Set(next_descriptor++, &d);
11280 } else if (type == CALLBACKS) {
11281 CallbacksDescriptor d(String::cast(key),
11282 value,
11283 details.attributes(),
11284 details.index());
11285 descriptors->Set(next_descriptor++, &d);
11286 } else {
11287 UNREACHABLE();
11288 }
11289 }
11290 }
11291 ASSERT(current_offset == number_of_fields);
11292
11293 descriptors->Sort();
11294 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070011295 Object* new_map;
11296 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
11297 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
11298 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011299
11300 // Transform the object.
11301 obj->set_map(Map::cast(new_map));
11302 obj->map()->set_instance_descriptors(descriptors);
11303 obj->map()->set_unused_property_fields(unused_property_fields);
11304
11305 obj->set_properties(FixedArray::cast(fields));
11306 ASSERT(obj->IsJSObject());
11307
11308 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
11309 // Check that it really works.
11310 ASSERT(obj->HasFastProperties());
11311
11312 return obj;
11313}
11314
11315
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011316Object* ObjectHashTable::Lookup(JSObject* key) {
11317 // If the object does not have an identity hash, it was never used as a key.
11318 MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
11319 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
11320 int entry = FindEntry(key);
11321 if (entry == kNotFound) return GetHeap()->undefined_value();
11322 return get(EntryToIndex(entry) + 1);
11323}
11324
11325
11326MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
11327 // Make sure the key object has an identity hash code.
11328 int hash;
11329 { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
11330 if (maybe_hash->IsFailure()) return maybe_hash;
11331 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
11332 }
11333 int entry = FindEntry(key);
11334
11335 // Check whether to perform removal operation.
11336 if (value->IsUndefined()) {
11337 if (entry == kNotFound) return this;
11338 RemoveEntry(entry);
11339 return Shrink(key);
11340 }
11341
11342 // Key is already in table, just overwrite value.
11343 if (entry != kNotFound) {
11344 set(EntryToIndex(entry) + 1, value);
11345 return this;
11346 }
11347
11348 // Check whether the hash table should be extended.
11349 Object* obj;
11350 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11351 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11352 }
11353 ObjectHashTable* table = ObjectHashTable::cast(obj);
11354 table->AddEntry(table->FindInsertionEntry(hash), key, value);
11355 return table;
11356}
11357
11358
11359void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
11360 set(EntryToIndex(entry), key);
11361 set(EntryToIndex(entry) + 1, value);
11362 ElementAdded();
11363}
11364
11365
11366void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
11367 set_null(heap, EntryToIndex(entry));
11368 set_null(heap, EntryToIndex(entry) + 1);
11369 ElementRemoved();
11370}
11371
11372
Steve Blocka7e24c12009-10-30 11:49:00 +000011373#ifdef ENABLE_DEBUGGER_SUPPORT
11374// Check if there is a break point at this code position.
11375bool DebugInfo::HasBreakPoint(int code_position) {
11376 // Get the break point info object for this code position.
11377 Object* break_point_info = GetBreakPointInfo(code_position);
11378
11379 // If there is no break point info object or no break points in the break
11380 // point info object there is no break point at this code position.
11381 if (break_point_info->IsUndefined()) return false;
11382 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
11383}
11384
11385
11386// Get the break point info object for this code position.
11387Object* DebugInfo::GetBreakPointInfo(int code_position) {
11388 // Find the index of the break point info object for this code position.
11389 int index = GetBreakPointInfoIndex(code_position);
11390
11391 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011392 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011393 return BreakPointInfo::cast(break_points()->get(index));
11394}
11395
11396
11397// Clear a break point at the specified code position.
11398void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
11399 int code_position,
11400 Handle<Object> break_point_object) {
11401 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11402 if (break_point_info->IsUndefined()) return;
11403 BreakPointInfo::ClearBreakPoint(
11404 Handle<BreakPointInfo>::cast(break_point_info),
11405 break_point_object);
11406}
11407
11408
11409void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
11410 int code_position,
11411 int source_position,
11412 int statement_position,
11413 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011414 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011415 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11416 if (!break_point_info->IsUndefined()) {
11417 BreakPointInfo::SetBreakPoint(
11418 Handle<BreakPointInfo>::cast(break_point_info),
11419 break_point_object);
11420 return;
11421 }
11422
11423 // Adding a new break point for a code position which did not have any
11424 // break points before. Try to find a free slot.
11425 int index = kNoBreakPointInfo;
11426 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11427 if (debug_info->break_points()->get(i)->IsUndefined()) {
11428 index = i;
11429 break;
11430 }
11431 }
11432 if (index == kNoBreakPointInfo) {
11433 // No free slot - extend break point info array.
11434 Handle<FixedArray> old_break_points =
11435 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011436 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010011437 isolate->factory()->NewFixedArray(
11438 old_break_points->length() +
11439 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011440
11441 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000011442 for (int i = 0; i < old_break_points->length(); i++) {
11443 new_break_points->set(i, old_break_points->get(i));
11444 }
11445 index = old_break_points->length();
11446 }
11447 ASSERT(index != kNoBreakPointInfo);
11448
11449 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011450 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11451 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000011452 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11453 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11454 new_break_point_info->
11455 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010011456 new_break_point_info->set_break_point_objects(
11457 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011458 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11459 debug_info->break_points()->set(index, *new_break_point_info);
11460}
11461
11462
11463// Get the break point objects for a code position.
11464Object* DebugInfo::GetBreakPointObjects(int code_position) {
11465 Object* break_point_info = GetBreakPointInfo(code_position);
11466 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011467 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011468 }
11469 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11470}
11471
11472
11473// Get the total number of break points.
11474int DebugInfo::GetBreakPointCount() {
11475 if (break_points()->IsUndefined()) return 0;
11476 int count = 0;
11477 for (int i = 0; i < break_points()->length(); i++) {
11478 if (!break_points()->get(i)->IsUndefined()) {
11479 BreakPointInfo* break_point_info =
11480 BreakPointInfo::cast(break_points()->get(i));
11481 count += break_point_info->GetBreakPointCount();
11482 }
11483 }
11484 return count;
11485}
11486
11487
11488Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11489 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011490 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011491 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011492 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11493 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11494 Handle<BreakPointInfo> break_point_info =
11495 Handle<BreakPointInfo>(BreakPointInfo::cast(
11496 debug_info->break_points()->get(i)));
11497 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11498 break_point_object)) {
11499 return *break_point_info;
11500 }
11501 }
11502 }
Steve Block44f0eee2011-05-26 01:26:41 +010011503 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011504}
11505
11506
11507// Find the index of the break point info object for the specified code
11508// position.
11509int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11510 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11511 for (int i = 0; i < break_points()->length(); i++) {
11512 if (!break_points()->get(i)->IsUndefined()) {
11513 BreakPointInfo* break_point_info =
11514 BreakPointInfo::cast(break_points()->get(i));
11515 if (break_point_info->code_position()->value() == code_position) {
11516 return i;
11517 }
11518 }
11519 }
11520 return kNoBreakPointInfo;
11521}
11522
11523
11524// Remove the specified break point object.
11525void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11526 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011527 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011528 // If there are no break points just ignore.
11529 if (break_point_info->break_point_objects()->IsUndefined()) return;
11530 // If there is a single break point clear it if it is the same.
11531 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11532 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011533 break_point_info->set_break_point_objects(
11534 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011535 }
11536 return;
11537 }
11538 // If there are multiple break points shrink the array
11539 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11540 Handle<FixedArray> old_array =
11541 Handle<FixedArray>(
11542 FixedArray::cast(break_point_info->break_point_objects()));
11543 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011544 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011545 int found_count = 0;
11546 for (int i = 0; i < old_array->length(); i++) {
11547 if (old_array->get(i) == *break_point_object) {
11548 ASSERT(found_count == 0);
11549 found_count++;
11550 } else {
11551 new_array->set(i - found_count, old_array->get(i));
11552 }
11553 }
11554 // If the break point was found in the list change it.
11555 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11556}
11557
11558
11559// Add the specified break point object.
11560void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11561 Handle<Object> break_point_object) {
11562 // If there was no break point objects before just set it.
11563 if (break_point_info->break_point_objects()->IsUndefined()) {
11564 break_point_info->set_break_point_objects(*break_point_object);
11565 return;
11566 }
11567 // If the break point object is the same as before just ignore.
11568 if (break_point_info->break_point_objects() == *break_point_object) return;
11569 // If there was one break point object before replace with array.
11570 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011571 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000011572 array->set(0, break_point_info->break_point_objects());
11573 array->set(1, *break_point_object);
11574 break_point_info->set_break_point_objects(*array);
11575 return;
11576 }
11577 // If there was more than one break point before extend array.
11578 Handle<FixedArray> old_array =
11579 Handle<FixedArray>(
11580 FixedArray::cast(break_point_info->break_point_objects()));
11581 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011582 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011583 for (int i = 0; i < old_array->length(); i++) {
11584 // If the break point was there before just ignore.
11585 if (old_array->get(i) == *break_point_object) return;
11586 new_array->set(i, old_array->get(i));
11587 }
11588 // Add the new break point.
11589 new_array->set(old_array->length(), *break_point_object);
11590 break_point_info->set_break_point_objects(*new_array);
11591}
11592
11593
11594bool BreakPointInfo::HasBreakPointObject(
11595 Handle<BreakPointInfo> break_point_info,
11596 Handle<Object> break_point_object) {
11597 // No break point.
11598 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011599 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000011600 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11601 return break_point_info->break_point_objects() == *break_point_object;
11602 }
11603 // Multiple break points.
11604 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11605 for (int i = 0; i < array->length(); i++) {
11606 if (array->get(i) == *break_point_object) {
11607 return true;
11608 }
11609 }
11610 return false;
11611}
11612
11613
11614// Get the number of break points.
11615int BreakPointInfo::GetBreakPointCount() {
11616 // No break point.
11617 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011618 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000011619 if (!break_point_objects()->IsFixedArray()) return 1;
11620 // Multiple break points.
11621 return FixedArray::cast(break_point_objects())->length();
11622}
11623#endif
11624
11625
11626} } // namespace v8::internal