blob: b407c016c90bbec2fbe9ddff175240fb720b82e7 [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "execution.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010037#include "full-codegen.h"
38#include "hydrogen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "objects-inl.h"
Iain Merrick75681382010-08-19 15:07:18 +010040#include "objects-visiting.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000041#include "macro-assembler.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010042#include "safepoint-table.h"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -080043#include "scanner-base.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "string-stream.h"
Steve Blockd0582a62009-12-15 09:54:21 +000045#include "utils.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010046#include "vm-state-inl.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000047
48#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +010049#include "disasm.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000050#include "disassembler.h"
51#endif
52
Steve Blocka7e24c12009-10-30 11:49:00 +000053namespace v8 {
54namespace internal {
55
56// Getters and setters are stored in a fixed array property. These are
57// constants for their indices.
58const int kGetterIndex = 0;
59const int kSetterIndex = 1;
60
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);
143 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000144 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100145 if (heap_object->IsString()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100146 holder = global_context->string_function()->instance_prototype();
147 } else if (heap_object->IsHeapNumber()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100148 holder = global_context->number_function()->instance_prototype();
149 } else if (heap_object->IsBoolean()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100150 holder = global_context->boolean_function()->instance_prototype();
Ben Murdoch257744e2011-11-30 15:57:28 +0000151 } else if (heap_object->IsJSProxy()) {
152 return result->HandlerResult();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100153 }
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);
193 HandleScope scope;
194 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();
233 HandleScope scope;
234 Handle<Object> receiver(receiver_raw);
235 Handle<Object> name(name_raw);
236 Handle<Object> handler(handler_raw);
237
238 // Extract trap function.
239 LookupResult lookup;
240 Handle<Object> trap(v8::internal::GetProperty(handler, "get", &lookup));
241 if (!lookup.IsFound()) {
242 // 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 {
492 return dictionary->DeleteProperty(entry, mode);
493 }
494 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100495 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000496}
497
498
499bool JSObject::IsDirty() {
500 Object* cons_obj = map()->constructor();
501 if (!cons_obj->IsJSFunction())
502 return true;
503 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100504 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000505 return true;
506 // If the object is fully fast case and has the same map it was
507 // created with then no changes can have been made to it.
508 return map() != fun->initial_map()
509 || !HasFastElements()
510 || !HasFastProperties();
511}
512
513
John Reck59135872010-11-02 12:39:01 -0700514MaybeObject* Object::GetProperty(Object* receiver,
515 LookupResult* result,
516 String* name,
517 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000518 // Make sure that the top context does not change when doing
519 // callbacks or interceptor calls.
520 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100521 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000522
523 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000524 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000525 // objects more than once in case of interceptors, because the
526 // holder will always be the interceptor holder and the search may
527 // only continue with a current object just after the interceptor
528 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000529 // Proxy handlers do not use the proxy's prototype, so we can skip this.
530 if (!result->IsHandler()) {
531 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
532 ASSERT(this != this->GetPrototype());
533 for (Object* current = this; true; current = current->GetPrototype()) {
534 if (current->IsAccessCheckNeeded()) {
535 // Check if we're allowed to read from the current object. Note
536 // that even though we may not actually end up loading the named
537 // property from the current object, we still check that we have
538 // access to it.
539 JSObject* checked = JSObject::cast(current);
540 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
541 return checked->GetPropertyWithFailedAccessCheck(receiver,
542 result,
543 name,
544 attributes);
545 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000546 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000547 // Stop traversing the chain once we reach the last object in the
548 // chain; either the holder of the result or null in case of an
549 // absent property.
550 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000551 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 }
553
554 if (!result->IsProperty()) {
555 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100556 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000557 }
558 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000559 Object* value;
560 JSObject* holder = result->holder();
561 switch (result->type()) {
562 case NORMAL:
563 value = holder->GetNormalizedProperty(result);
564 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100565 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 case FIELD:
567 value = holder->FastPropertyAt(result->GetFieldIndex());
568 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100569 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 case CONSTANT_FUNCTION:
571 return result->GetConstantFunction();
572 case CALLBACKS:
573 return GetPropertyWithCallback(receiver,
574 result->GetCallbackObject(),
575 name,
576 holder);
Ben Murdoch257744e2011-11-30 15:57:28 +0000577 case HANDLER: {
578 JSProxy* proxy = JSProxy::cast(this);
579 return GetPropertyWithHandler(receiver, name, proxy->handler());
580 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000581 case INTERCEPTOR: {
582 JSObject* recvr = JSObject::cast(receiver);
583 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
584 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000585 case MAP_TRANSITION:
586 case EXTERNAL_ARRAY_TRANSITION:
587 case CONSTANT_TRANSITION:
588 case NULL_DESCRIPTOR:
589 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000591 UNREACHABLE();
592 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000593}
594
595
John Reck59135872010-11-02 12:39:01 -0700596MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100597 Object* holder = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100598 if (IsSmi()) {
599 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100600 holder = global_context->number_function()->instance_prototype();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100601 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100602 HeapObject* heap_object = HeapObject::cast(this);
603
604 if (heap_object->IsJSObject()) {
605 return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
606 }
607 Heap* heap = heap_object->GetHeap();
608 Isolate* isolate = heap->isolate();
609
610 Context* global_context = isolate->context()->global_context();
611 if (heap_object->IsString()) {
612 holder = global_context->string_function()->instance_prototype();
613 } else if (heap_object->IsHeapNumber()) {
614 holder = global_context->number_function()->instance_prototype();
615 } else if (heap_object->IsBoolean()) {
616 holder = global_context->boolean_function()->instance_prototype();
Ben Murdoch257744e2011-11-30 15:57:28 +0000617 } else if (heap_object->IsJSProxy()) {
618 return heap->undefined_value(); // For now...
Ben Murdoch8b112d22011-06-08 16:22:53 +0100619 } else {
620 // Undefined and null have no indexed properties.
621 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
622 return heap->undefined_value();
623 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100624 }
625
626 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000627}
628
629
630Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100631 if (IsSmi()) {
632 Heap* heap = Isolate::Current()->heap();
633 Context* context = heap->isolate()->context()->global_context();
634 return context->number_function()->instance_prototype();
635 }
636
637 HeapObject* heap_object = HeapObject::cast(this);
638
Ben Murdoch257744e2011-11-30 15:57:28 +0000639 // The object is either a number, a string, a boolean,
640 // a real JS object, or a Harmony proxy.
641 if (heap_object->IsJSObject() || heap_object->IsJSProxy()) {
642 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100643 }
644 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100645 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000646
Ben Murdoch8b112d22011-06-08 16:22:53 +0100647 if (heap_object->IsHeapNumber()) {
648 return context->number_function()->instance_prototype();
649 }
650 if (heap_object->IsString()) {
651 return context->string_function()->instance_prototype();
652 }
653 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000654 return context->boolean_function()->instance_prototype();
655 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100656 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000657 }
658}
659
660
Ben Murdochb0fe1622011-05-05 13:52:32 +0100661void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 HeapStringAllocator allocator;
663 StringStream accumulator(&allocator);
664 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100665 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000666}
667
668
669void Object::ShortPrint(StringStream* accumulator) {
670 if (IsSmi()) {
671 Smi::cast(this)->SmiPrint(accumulator);
672 } else if (IsFailure()) {
673 Failure::cast(this)->FailurePrint(accumulator);
674 } else {
675 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
676 }
677}
678
679
Ben Murdochb0fe1622011-05-05 13:52:32 +0100680void Smi::SmiPrint(FILE* out) {
681 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000682}
683
684
685void Smi::SmiPrint(StringStream* accumulator) {
686 accumulator->Add("%d", value());
687}
688
689
690void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000691 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000692}
693
694
Ben Murdochb0fe1622011-05-05 13:52:32 +0100695void Failure::FailurePrint(FILE* out) {
696 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000697}
698
699
Steve Blocka7e24c12009-10-30 11:49:00 +0000700// Should a word be prefixed by 'a' or 'an' in order to read naturally in
701// English? Returns false for non-ASCII or words that don't start with
702// a capital letter. The a/an rule follows pronunciation in English.
703// We don't use the BBC's overcorrect "an historic occasion" though if
704// you speak a dialect you may well say "an 'istoric occasion".
705static bool AnWord(String* str) {
706 if (str->length() == 0) return false; // A nothing.
707 int c0 = str->Get(0);
708 int c1 = str->length() > 1 ? str->Get(1) : 0;
709 if (c0 == 'U') {
710 if (c1 > 'Z') {
711 return true; // An Umpire, but a UTF8String, a U.
712 }
713 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
714 return true; // An Ape, an ABCBook.
715 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
716 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
717 c0 == 'S' || c0 == 'X')) {
718 return true; // An MP3File, an M.
719 }
720 return false;
721}
722
723
John Reck59135872010-11-02 12:39:01 -0700724MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000725#ifdef DEBUG
726 // Do not attempt to flatten in debug mode when allocation is not
727 // allowed. This is to avoid an assertion failure when allocating.
728 // Flattening strings is the only case where we always allow
729 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100730 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000731#endif
732
Steve Block44f0eee2011-05-26 01:26:41 +0100733 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000735 case kConsStringTag: {
736 ConsString* cs = ConsString::cast(this);
737 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100738 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000739 }
740 // There's little point in putting the flat string in new space if the
741 // cons string is in old space. It can never get GCed until there is
742 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100743 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000744 int len = length();
745 Object* object;
746 String* result;
747 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100748 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700749 if (!maybe_object->ToObject(&object)) return maybe_object;
750 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 result = String::cast(object);
752 String* first = cs->first();
753 int first_length = first->length();
754 char* dest = SeqAsciiString::cast(result)->GetChars();
755 WriteToFlat(first, dest, 0, first_length);
756 String* second = cs->second();
757 WriteToFlat(second,
758 dest + first_length,
759 0,
760 len - first_length);
761 } else {
John Reck59135872010-11-02 12:39:01 -0700762 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100763 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700764 if (!maybe_object->ToObject(&object)) return maybe_object;
765 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 result = String::cast(object);
767 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
768 String* first = cs->first();
769 int first_length = first->length();
770 WriteToFlat(first, dest, 0, first_length);
771 String* second = cs->second();
772 WriteToFlat(second,
773 dest + first_length,
774 0,
775 len - first_length);
776 }
777 cs->set_first(result);
Steve Block44f0eee2011-05-26 01:26:41 +0100778 cs->set_second(heap->empty_string());
Leon Clarkef7060e22010-06-03 12:02:55 +0100779 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000780 }
781 default:
782 return this;
783 }
784}
785
786
787bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100788 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100789 // prohibited by the API.
790 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000791#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000792 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000793 // Assert that the resource and the string are equivalent.
794 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100795 ScopedVector<uc16> smart_chars(this->length());
796 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
797 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000798 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100799 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000800 }
801#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100802 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000803 int size = this->Size(); // Byte size of the original string.
804 if (size < ExternalString::kSize) {
805 // The string is too small to fit an external String in its place. This can
806 // only happen for zero length strings.
807 return false;
808 }
809 ASSERT(size >= ExternalString::kSize);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100810 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 bool is_symbol = this->IsSymbol();
812 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000813 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000814
815 // Morph the object to an external string by adjusting the map and
816 // reinitializing the fields.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100817 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100818 heap->external_string_with_ascii_data_map() :
819 heap->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000820 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
821 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000822 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 self->set_resource(resource);
824 // Additionally make the object into an external symbol if the original string
825 // was a symbol to start with.
826 if (is_symbol) {
827 self->Hash(); // Force regeneration of the hash value.
828 // Now morph this external string into a external symbol.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100829 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100830 heap->external_symbol_with_ascii_data_map() :
831 heap->external_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000832 }
833
834 // Fill the remainder of the string with dead wood.
835 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100836 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 return true;
838}
839
840
841bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
842#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000843 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 // Assert that the resource and the string are equivalent.
845 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100846 ScopedVector<char> smart_chars(this->length());
847 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
848 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000849 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100850 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000851 }
852#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100853 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000854 int size = this->Size(); // Byte size of the original string.
855 if (size < ExternalString::kSize) {
856 // The string is too small to fit an external String in its place. This can
857 // only happen for zero length strings.
858 return false;
859 }
860 ASSERT(size >= ExternalString::kSize);
861 bool is_symbol = this->IsSymbol();
862 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000863 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000864
865 // Morph the object to an external string by adjusting the map and
866 // reinitializing the fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100867 this->set_map(heap->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000868 ExternalAsciiString* self = ExternalAsciiString::cast(this);
869 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000870 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000871 self->set_resource(resource);
872 // Additionally make the object into an external symbol if the original string
873 // was a symbol to start with.
874 if (is_symbol) {
875 self->Hash(); // Force regeneration of the hash value.
876 // Now morph this external string into a external symbol.
Steve Block44f0eee2011-05-26 01:26:41 +0100877 this->set_map(heap->external_ascii_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000878 }
879
880 // Fill the remainder of the string with dead wood.
881 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100882 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000883 return true;
884}
885
886
887void String::StringShortPrint(StringStream* accumulator) {
888 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +0000889 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 accumulator->Add("<Very long string[%u]>", len);
891 return;
892 }
893
894 if (!LooksValid()) {
895 accumulator->Add("<Invalid String>");
896 return;
897 }
898
899 StringInputBuffer buf(this);
900
901 bool truncated = false;
902 if (len > kMaxShortPrintLength) {
903 len = kMaxShortPrintLength;
904 truncated = true;
905 }
906 bool ascii = true;
907 for (int i = 0; i < len; i++) {
908 int c = buf.GetNext();
909
910 if (c < 32 || c >= 127) {
911 ascii = false;
912 }
913 }
914 buf.Reset(this);
915 if (ascii) {
916 accumulator->Add("<String[%u]: ", length());
917 for (int i = 0; i < len; i++) {
918 accumulator->Put(buf.GetNext());
919 }
920 accumulator->Put('>');
921 } else {
922 // Backslash indicates that the string contains control
923 // characters and that backslashes are therefore escaped.
924 accumulator->Add("<String[%u]\\: ", length());
925 for (int i = 0; i < len; i++) {
926 int c = buf.GetNext();
927 if (c == '\n') {
928 accumulator->Add("\\n");
929 } else if (c == '\r') {
930 accumulator->Add("\\r");
931 } else if (c == '\\') {
932 accumulator->Add("\\\\");
933 } else if (c < 32 || c > 126) {
934 accumulator->Add("\\x%02x", c);
935 } else {
936 accumulator->Put(c);
937 }
938 }
939 if (truncated) {
940 accumulator->Put('.');
941 accumulator->Put('.');
942 accumulator->Put('.');
943 }
944 accumulator->Put('>');
945 }
946 return;
947}
948
949
950void JSObject::JSObjectShortPrint(StringStream* accumulator) {
951 switch (map()->instance_type()) {
952 case JS_ARRAY_TYPE: {
953 double length = JSArray::cast(this)->length()->Number();
954 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
955 break;
956 }
957 case JS_REGEXP_TYPE: {
958 accumulator->Add("<JS RegExp>");
959 break;
960 }
961 case JS_FUNCTION_TYPE: {
962 Object* fun_name = JSFunction::cast(this)->shared()->name();
963 bool printed = false;
964 if (fun_name->IsString()) {
965 String* str = String::cast(fun_name);
966 if (str->length() > 0) {
967 accumulator->Add("<JS Function ");
968 accumulator->Put(str);
969 accumulator->Put('>');
970 printed = true;
971 }
972 }
973 if (!printed) {
974 accumulator->Add("<JS Function>");
975 }
976 break;
977 }
978 // All other JSObjects are rather similar to each other (JSObject,
979 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
980 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100981 Map* map_of_this = map();
982 Heap* heap = map_of_this->heap();
983 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +0000984 bool printed = false;
985 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100986 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000987 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
988 } else {
989 bool global_object = IsJSGlobalProxy();
990 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100991 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
993 } else {
994 Object* constructor_name =
995 JSFunction::cast(constructor)->shared()->name();
996 if (constructor_name->IsString()) {
997 String* str = String::cast(constructor_name);
998 if (str->length() > 0) {
999 bool vowel = AnWord(str);
1000 accumulator->Add("<%sa%s ",
1001 global_object ? "Global Object: " : "",
1002 vowel ? "n" : "");
1003 accumulator->Put(str);
1004 accumulator->Put('>');
1005 printed = true;
1006 }
1007 }
1008 }
1009 }
1010 if (!printed) {
1011 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1012 }
1013 }
1014 if (IsJSValue()) {
1015 accumulator->Add(" value = ");
1016 JSValue::cast(this)->value()->ShortPrint(accumulator);
1017 }
1018 accumulator->Put('>');
1019 break;
1020 }
1021 }
1022}
1023
1024
1025void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001026 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1027 Heap* heap = GetHeap();
1028 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001029 accumulator->Add("!!!INVALID POINTER!!!");
1030 return;
1031 }
Steve Block44f0eee2011-05-26 01:26:41 +01001032 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001033 accumulator->Add("!!!INVALID MAP!!!");
1034 return;
1035 }
1036
1037 accumulator->Add("%p ", this);
1038
1039 if (IsString()) {
1040 String::cast(this)->StringShortPrint(accumulator);
1041 return;
1042 }
1043 if (IsJSObject()) {
1044 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1045 return;
1046 }
1047 switch (map()->instance_type()) {
1048 case MAP_TYPE:
1049 accumulator->Add("<Map>");
1050 break;
1051 case FIXED_ARRAY_TYPE:
1052 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1053 break;
1054 case BYTE_ARRAY_TYPE:
1055 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1056 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001057 case EXTERNAL_PIXEL_ARRAY_TYPE:
1058 accumulator->Add("<ExternalPixelArray[%u]>",
1059 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001060 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001061 case EXTERNAL_BYTE_ARRAY_TYPE:
1062 accumulator->Add("<ExternalByteArray[%u]>",
1063 ExternalByteArray::cast(this)->length());
1064 break;
1065 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1066 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1067 ExternalUnsignedByteArray::cast(this)->length());
1068 break;
1069 case EXTERNAL_SHORT_ARRAY_TYPE:
1070 accumulator->Add("<ExternalShortArray[%u]>",
1071 ExternalShortArray::cast(this)->length());
1072 break;
1073 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1074 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1075 ExternalUnsignedShortArray::cast(this)->length());
1076 break;
1077 case EXTERNAL_INT_ARRAY_TYPE:
1078 accumulator->Add("<ExternalIntArray[%u]>",
1079 ExternalIntArray::cast(this)->length());
1080 break;
1081 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1082 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1083 ExternalUnsignedIntArray::cast(this)->length());
1084 break;
1085 case EXTERNAL_FLOAT_ARRAY_TYPE:
1086 accumulator->Add("<ExternalFloatArray[%u]>",
1087 ExternalFloatArray::cast(this)->length());
1088 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001089 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1090 accumulator->Add("<ExternalDoubleArray[%u]>",
1091 ExternalDoubleArray::cast(this)->length());
1092 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001093 case SHARED_FUNCTION_INFO_TYPE:
1094 accumulator->Add("<SharedFunctionInfo>");
1095 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001096 case JS_MESSAGE_OBJECT_TYPE:
1097 accumulator->Add("<JSMessageObject>");
1098 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001099#define MAKE_STRUCT_CASE(NAME, Name, name) \
1100 case NAME##_TYPE: \
1101 accumulator->Put('<'); \
1102 accumulator->Add(#Name); \
1103 accumulator->Put('>'); \
1104 break;
1105 STRUCT_LIST(MAKE_STRUCT_CASE)
1106#undef MAKE_STRUCT_CASE
1107 case CODE_TYPE:
1108 accumulator->Add("<Code>");
1109 break;
1110 case ODDBALL_TYPE: {
1111 if (IsUndefined())
1112 accumulator->Add("<undefined>");
1113 else if (IsTheHole())
1114 accumulator->Add("<the hole>");
1115 else if (IsNull())
1116 accumulator->Add("<null>");
1117 else if (IsTrue())
1118 accumulator->Add("<true>");
1119 else if (IsFalse())
1120 accumulator->Add("<false>");
1121 else
1122 accumulator->Add("<Odd Oddball>");
1123 break;
1124 }
1125 case HEAP_NUMBER_TYPE:
1126 accumulator->Add("<Number: ");
1127 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1128 accumulator->Put('>');
1129 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001130 case FOREIGN_TYPE:
1131 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001132 break;
1133 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1134 accumulator->Add("Cell for ");
1135 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1136 break;
1137 default:
1138 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1139 break;
1140 }
1141}
1142
1143
Steve Blocka7e24c12009-10-30 11:49:00 +00001144void HeapObject::Iterate(ObjectVisitor* v) {
1145 // Handle header
1146 IteratePointer(v, kMapOffset);
1147 // Handle object body
1148 Map* m = map();
1149 IterateBody(m->instance_type(), SizeFromMap(m), v);
1150}
1151
1152
1153void HeapObject::IterateBody(InstanceType type, int object_size,
1154 ObjectVisitor* v) {
1155 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1156 // During GC, the map pointer field is encoded.
1157 if (type < FIRST_NONSTRING_TYPE) {
1158 switch (type & kStringRepresentationMask) {
1159 case kSeqStringTag:
1160 break;
1161 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001162 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001163 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001164 case kExternalStringTag:
1165 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1166 reinterpret_cast<ExternalAsciiString*>(this)->
1167 ExternalAsciiStringIterateBody(v);
1168 } else {
1169 reinterpret_cast<ExternalTwoByteString*>(this)->
1170 ExternalTwoByteStringIterateBody(v);
1171 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001172 break;
1173 }
1174 return;
1175 }
1176
1177 switch (type) {
1178 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001179 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001180 break;
1181 case JS_OBJECT_TYPE:
1182 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1183 case JS_VALUE_TYPE:
1184 case JS_ARRAY_TYPE:
1185 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 case JS_GLOBAL_PROXY_TYPE:
1187 case JS_GLOBAL_OBJECT_TYPE:
1188 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001189 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001190 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001191 break;
Steve Block791712a2010-08-27 10:21:07 +01001192 case JS_FUNCTION_TYPE:
1193 reinterpret_cast<JSFunction*>(this)
1194 ->JSFunctionIterateBody(object_size, v);
1195 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001196 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001197 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001198 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001199 case JS_PROXY_TYPE:
1200 JSProxy::BodyDescriptor::IterateBody(this, v);
1201 break;
1202 case FOREIGN_TYPE:
1203 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001204 break;
1205 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001206 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 break;
1208 case CODE_TYPE:
1209 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1210 break;
1211 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001212 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001213 break;
1214 case HEAP_NUMBER_TYPE:
1215 case FILLER_TYPE:
1216 case BYTE_ARRAY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001217 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001218 case EXTERNAL_BYTE_ARRAY_TYPE:
1219 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1220 case EXTERNAL_SHORT_ARRAY_TYPE:
1221 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1222 case EXTERNAL_INT_ARRAY_TYPE:
1223 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1224 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001225 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001226 break;
Iain Merrick75681382010-08-19 15:07:18 +01001227 case SHARED_FUNCTION_INFO_TYPE:
1228 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001229 break;
Iain Merrick75681382010-08-19 15:07:18 +01001230
Steve Blocka7e24c12009-10-30 11:49:00 +00001231#define MAKE_STRUCT_CASE(NAME, Name, name) \
1232 case NAME##_TYPE:
1233 STRUCT_LIST(MAKE_STRUCT_CASE)
1234#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001235 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001236 break;
1237 default:
1238 PrintF("Unknown type: %d\n", type);
1239 UNREACHABLE();
1240 }
1241}
1242
1243
Steve Blocka7e24c12009-10-30 11:49:00 +00001244Object* HeapNumber::HeapNumberToBoolean() {
1245 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001246#if __BYTE_ORDER == __LITTLE_ENDIAN
1247 union IeeeDoubleLittleEndianArchType u;
1248#elif __BYTE_ORDER == __BIG_ENDIAN
1249 union IeeeDoubleBigEndianArchType u;
1250#endif
1251 u.d = value();
1252 if (u.bits.exp == 2047) {
1253 // Detect NaN for IEEE double precision floating point.
1254 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001255 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 }
Iain Merrick75681382010-08-19 15:07:18 +01001257 if (u.bits.exp == 0) {
1258 // Detect +0, and -0 for IEEE double precision floating point.
1259 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001260 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001261 }
Steve Block44f0eee2011-05-26 01:26:41 +01001262 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001263}
1264
1265
Ben Murdochb0fe1622011-05-05 13:52:32 +01001266void HeapNumber::HeapNumberPrint(FILE* out) {
1267 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001268}
1269
1270
1271void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1272 // The Windows version of vsnprintf can allocate when printing a %g string
1273 // into a buffer that may not be big enough. We don't want random memory
1274 // allocation when producing post-crash stack traces, so we print into a
1275 // buffer that is plenty big enough for any floating point number, then
1276 // print that using vsnprintf (which may truncate but never allocate if
1277 // there is no more space in the buffer).
1278 EmbeddedVector<char, 100> buffer;
1279 OS::SNPrintF(buffer, "%.16g", Number());
1280 accumulator->Add("%s", buffer.start());
1281}
1282
1283
1284String* JSObject::class_name() {
1285 if (IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001286 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001287 }
1288 if (map()->constructor()->IsJSFunction()) {
1289 JSFunction* constructor = JSFunction::cast(map()->constructor());
1290 return String::cast(constructor->shared()->instance_class_name());
1291 }
1292 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001293 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001294}
1295
1296
1297String* JSObject::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001298 if (map()->constructor()->IsJSFunction()) {
1299 JSFunction* constructor = JSFunction::cast(map()->constructor());
1300 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001301 if (name->length() > 0) return name;
1302 String* inferred_name = constructor->shared()->inferred_name();
1303 if (inferred_name->length() > 0) return inferred_name;
1304 Object* proto = GetPrototype();
1305 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001306 }
1307 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001308 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001309}
1310
1311
John Reck59135872010-11-02 12:39:01 -07001312MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1313 String* name,
1314 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 int index = new_map->PropertyIndexFor(name);
1316 if (map()->unused_property_fields() == 0) {
1317 ASSERT(map()->unused_property_fields() == 0);
1318 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001319 Object* values;
1320 { MaybeObject* maybe_values =
1321 properties()->CopySize(properties()->length() + new_unused + 1);
1322 if (!maybe_values->ToObject(&values)) return maybe_values;
1323 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001324 set_properties(FixedArray::cast(values));
1325 }
1326 set_map(new_map);
1327 return FastPropertyAtPut(index, value);
1328}
1329
1330
Ben Murdoch8b112d22011-06-08 16:22:53 +01001331static bool IsIdentifier(UnicodeCache* cache,
1332 unibrow::CharacterStream* buffer) {
1333 // Checks whether the buffer contains an identifier (no escape).
1334 if (!buffer->has_more()) return false;
1335 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1336 return false;
1337 }
1338 while (buffer->has_more()) {
1339 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1340 return false;
1341 }
1342 }
1343 return true;
1344}
1345
1346
John Reck59135872010-11-02 12:39:01 -07001347MaybeObject* JSObject::AddFastProperty(String* name,
1348 Object* value,
1349 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001350 ASSERT(!IsJSGlobalProxy());
1351
Steve Blocka7e24c12009-10-30 11:49:00 +00001352 // Normalize the object if the name is an actual string (not the
1353 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001354 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001355 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001356 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001357 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001358 Object* obj;
1359 { MaybeObject* maybe_obj =
1360 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1361 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1362 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 return AddSlowProperty(name, value, attributes);
1364 }
1365
1366 DescriptorArray* old_descriptors = map()->instance_descriptors();
1367 // Compute the new index for new field.
1368 int index = map()->NextFreePropertyIndex();
1369
1370 // Allocate new instance descriptors with (name, index) added
1371 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001372 Object* new_descriptors;
1373 { MaybeObject* maybe_new_descriptors =
1374 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1375 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1376 return maybe_new_descriptors;
1377 }
1378 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001379
Steve Block44f0eee2011-05-26 01:26:41 +01001380 // Only allow map transition if the object isn't the global object and there
1381 // is not a transition for the name, or there's a transition for the name but
1382 // it's unrelated to properties.
1383 int descriptor_index = old_descriptors->Search(name);
1384
1385 // External array transitions are stored in the descriptor for property "",
1386 // which is not a identifier and should have forced a switch to slow
1387 // properties above.
1388 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1389 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1390 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1391 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001392 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001393 can_insert_transition &&
1394 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001395
1396 ASSERT(index < map()->inobject_properties() ||
1397 (index - map()->inobject_properties()) < properties()->length() ||
1398 map()->unused_property_fields() == 0);
1399 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001400 Object* r;
1401 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1402 if (!maybe_r->ToObject(&r)) return maybe_r;
1403 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 Map* new_map = Map::cast(r);
1405 if (allow_map_transition) {
1406 // Allocate new instance descriptors for the old map with map transition.
1407 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001408 Object* r;
1409 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1410 if (!maybe_r->ToObject(&r)) return maybe_r;
1411 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001412 old_descriptors = DescriptorArray::cast(r);
1413 }
1414
1415 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001416 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001417 Object* obj;
1418 { MaybeObject* maybe_obj =
1419 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1420 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1421 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 return AddSlowProperty(name, value, attributes);
1423 }
1424 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001425 Object* values;
1426 { MaybeObject* maybe_values =
1427 properties()->CopySize(properties()->length() + kFieldsAdded);
1428 if (!maybe_values->ToObject(&values)) return maybe_values;
1429 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001430 set_properties(FixedArray::cast(values));
1431 new_map->set_unused_property_fields(kFieldsAdded - 1);
1432 } else {
1433 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1434 }
1435 // We have now allocated all the necessary objects.
1436 // All the changes can be applied at once, so they are atomic.
1437 map()->set_instance_descriptors(old_descriptors);
1438 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1439 set_map(new_map);
1440 return FastPropertyAtPut(index, value);
1441}
1442
1443
John Reck59135872010-11-02 12:39:01 -07001444MaybeObject* JSObject::AddConstantFunctionProperty(
1445 String* name,
1446 JSFunction* function,
1447 PropertyAttributes attributes) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001448 ASSERT(!GetHeap()->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001449
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 // Allocate new instance descriptors with (name, function) added
1451 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001452 Object* new_descriptors;
1453 { MaybeObject* maybe_new_descriptors =
1454 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1455 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1456 return maybe_new_descriptors;
1457 }
1458 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001459
1460 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001461 Object* new_map;
1462 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1463 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1464 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001465
1466 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1467 Map::cast(new_map)->set_instance_descriptors(descriptors);
1468 Map* old_map = map();
1469 set_map(Map::cast(new_map));
1470
1471 // If the old map is the global object map (from new Object()),
1472 // then transitions are not added to it, so we are done.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001473 Heap* heap = old_map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001474 if (old_map == heap->isolate()->context()->global_context()->
1475 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001476 return function;
1477 }
1478
1479 // Do not add CONSTANT_TRANSITIONS to global objects
1480 if (IsGlobalObject()) {
1481 return function;
1482 }
1483
1484 // Add a CONSTANT_TRANSITION descriptor to the old map,
1485 // so future assignments to this property on other objects
1486 // of the same type will create a normal field, not a constant function.
1487 // Don't do this for special properties, with non-trival attributes.
1488 if (attributes != NONE) {
1489 return function;
1490 }
Iain Merrick75681382010-08-19 15:07:18 +01001491 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001492 { MaybeObject* maybe_new_descriptors =
1493 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1494 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1495 // We have accomplished the main goal, so return success.
1496 return function;
1497 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 }
1499 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1500
1501 return function;
1502}
1503
1504
1505// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001506MaybeObject* JSObject::AddSlowProperty(String* name,
1507 Object* value,
1508 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 ASSERT(!HasFastProperties());
1510 StringDictionary* dict = property_dictionary();
1511 Object* store_value = value;
1512 if (IsGlobalObject()) {
1513 // In case name is an orphaned property reuse the cell.
1514 int entry = dict->FindEntry(name);
1515 if (entry != StringDictionary::kNotFound) {
1516 store_value = dict->ValueAt(entry);
1517 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1518 // Assign an enumeration index to the property and update
1519 // SetNextEnumerationIndex.
1520 int index = dict->NextEnumerationIndex();
1521 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1522 dict->SetNextEnumerationIndex(index + 1);
1523 dict->SetEntry(entry, name, store_value, details);
1524 return value;
1525 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001526 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001527 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001528 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001529 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1530 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001531 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1532 }
1533 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001534 Object* result;
1535 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1536 if (!maybe_result->ToObject(&result)) return maybe_result;
1537 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001538 if (dict != result) set_properties(StringDictionary::cast(result));
1539 return value;
1540}
1541
1542
John Reck59135872010-11-02 12:39:01 -07001543MaybeObject* JSObject::AddProperty(String* name,
1544 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001545 PropertyAttributes attributes,
1546 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001547 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001548 Map* map_of_this = map();
1549 Heap* heap = map_of_this->heap();
1550 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001551 if (strict_mode == kNonStrictMode) {
1552 return heap->undefined_value();
1553 } else {
1554 Handle<Object> args[1] = {Handle<String>(name)};
1555 return heap->isolate()->Throw(
1556 *FACTORY->NewTypeError("object_not_extensible",
1557 HandleVector(args, 1)));
1558 }
Steve Block8defd9f2010-07-08 12:39:36 +01001559 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001560 if (HasFastProperties()) {
1561 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001562 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001563 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001564 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001565 return AddConstantFunctionProperty(name,
1566 JSFunction::cast(value),
1567 attributes);
1568 } else {
1569 return AddFastProperty(name, value, attributes);
1570 }
1571 } else {
1572 // Normalize the object to prevent very large instance descriptors.
1573 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001574 Object* obj;
1575 { MaybeObject* maybe_obj =
1576 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1577 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1578 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001579 }
1580 }
1581 return AddSlowProperty(name, value, attributes);
1582}
1583
1584
John Reck59135872010-11-02 12:39:01 -07001585MaybeObject* JSObject::SetPropertyPostInterceptor(
1586 String* name,
1587 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001588 PropertyAttributes attributes,
1589 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001590 // Check local property, ignore interceptor.
1591 LookupResult result;
1592 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001593 if (result.IsFound()) {
1594 // An existing property, a map transition or a null descriptor was
1595 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001596 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001597 }
1598 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001599 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001600}
1601
1602
John Reck59135872010-11-02 12:39:01 -07001603MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1604 Object* value,
1605 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001606 StringDictionary* dictionary = property_dictionary();
1607 int old_index = dictionary->FindEntry(name);
1608 int new_enumeration_index = 0; // 0 means "Use the next available index."
1609 if (old_index != -1) {
1610 // All calls to ReplaceSlowProperty have had all transitions removed.
1611 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1612 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1613 }
1614
1615 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1616 return SetNormalizedProperty(name, value, new_details);
1617}
1618
Steve Blockd0582a62009-12-15 09:54:21 +00001619
John Reck59135872010-11-02 12:39:01 -07001620MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001621 String* name,
1622 Object* new_value,
1623 PropertyAttributes attributes) {
1624 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001625 Object* result;
1626 { MaybeObject* maybe_result =
1627 ConvertDescriptorToField(name, new_value, attributes);
1628 if (!maybe_result->ToObject(&result)) return maybe_result;
1629 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001630 // If we get to this point we have succeeded - do not return failure
1631 // after this point. Later stuff is optional.
1632 if (!HasFastProperties()) {
1633 return result;
1634 }
1635 // Do not add transitions to the map of "new Object()".
Ben Murdoch8b112d22011-06-08 16:22:53 +01001636 if (map() == old_map->heap()->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001637 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001638 return result;
1639 }
1640
1641 MapTransitionDescriptor transition(name,
1642 map(),
1643 attributes);
John Reck59135872010-11-02 12:39:01 -07001644 Object* new_descriptors;
1645 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1646 CopyInsert(&transition, KEEP_TRANSITIONS);
1647 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1648 return result; // Yes, return _result_.
1649 }
1650 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001651 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1652 return result;
1653}
1654
1655
John Reck59135872010-11-02 12:39:01 -07001656MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1657 Object* new_value,
1658 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001659 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001660 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001661 Object* obj;
1662 { MaybeObject* maybe_obj =
1663 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1664 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1665 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001666 return ReplaceSlowProperty(name, new_value, attributes);
1667 }
1668
1669 int index = map()->NextFreePropertyIndex();
1670 FieldDescriptor new_field(name, index, attributes);
1671 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001672 Object* descriptors_unchecked;
1673 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1674 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1675 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1676 return maybe_descriptors_unchecked;
1677 }
1678 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001679 DescriptorArray* new_descriptors =
1680 DescriptorArray::cast(descriptors_unchecked);
1681
1682 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001683 Object* new_map_unchecked;
1684 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1685 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1686 return maybe_new_map_unchecked;
1687 }
1688 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001689 Map* new_map = Map::cast(new_map_unchecked);
1690 new_map->set_instance_descriptors(new_descriptors);
1691
1692 // Make new properties array if necessary.
1693 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1694 int new_unused_property_fields = map()->unused_property_fields() - 1;
1695 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001696 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001697 Object* new_properties_object;
1698 { MaybeObject* maybe_new_properties_object =
1699 properties()->CopySize(properties()->length() + kFieldsAdded);
1700 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1701 return maybe_new_properties_object;
1702 }
1703 }
1704 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001705 }
1706
1707 // Update pointers to commit changes.
1708 // Object points to the new map.
1709 new_map->set_unused_property_fields(new_unused_property_fields);
1710 set_map(new_map);
1711 if (new_properties) {
1712 set_properties(FixedArray::cast(new_properties));
1713 }
1714 return FastPropertyAtPut(index, new_value);
1715}
1716
1717
1718
John Reck59135872010-11-02 12:39:01 -07001719MaybeObject* JSObject::SetPropertyWithInterceptor(
1720 String* name,
1721 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001722 PropertyAttributes attributes,
1723 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001724 Isolate* isolate = GetIsolate();
1725 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001726 Handle<JSObject> this_handle(this);
1727 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001728 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1730 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001731 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1732 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001733 v8::AccessorInfo info(args.end());
1734 v8::NamedPropertySetter setter =
1735 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1736 v8::Handle<v8::Value> result;
1737 {
1738 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001739 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001740 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001741 isolate->heap()->undefined_value() :
1742 value,
1743 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001744 result = setter(v8::Utils::ToLocal(name_handle),
1745 v8::Utils::ToLocal(value_unhole),
1746 info);
1747 }
Steve Block44f0eee2011-05-26 01:26:41 +01001748 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001749 if (!result.IsEmpty()) return *value_handle;
1750 }
John Reck59135872010-11-02 12:39:01 -07001751 MaybeObject* raw_result =
1752 this_handle->SetPropertyPostInterceptor(*name_handle,
1753 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001754 attributes,
1755 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001756 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001757 return raw_result;
1758}
1759
1760
John Reck59135872010-11-02 12:39:01 -07001761MaybeObject* JSObject::SetProperty(String* name,
1762 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001763 PropertyAttributes attributes,
1764 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001765 LookupResult result;
1766 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001767 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001768}
1769
1770
John Reck59135872010-11-02 12:39:01 -07001771MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1772 String* name,
1773 Object* value,
1774 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01001775 Isolate* isolate = GetIsolate();
1776 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001777
1778 // We should never get here to initialize a const with the hole
1779 // value since a const declaration would conflict with the setter.
1780 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001781 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001782
1783 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00001784 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00001785 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00001786 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001787 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00001788 reinterpret_cast<AccessorDescriptor*>(
1789 Foreign::cast(structure)->address());
John Reck59135872010-11-02 12:39:01 -07001790 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001791 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001792 if (obj->IsFailure()) return obj;
1793 return *value_handle;
1794 }
1795
1796 if (structure->IsAccessorInfo()) {
1797 // api style callbacks
1798 AccessorInfo* data = AccessorInfo::cast(structure);
1799 Object* call_obj = data->setter();
1800 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1801 if (call_fun == NULL) return value;
1802 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001803 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1804 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001805 v8::AccessorInfo info(args.end());
1806 {
1807 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001808 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001809 call_fun(v8::Utils::ToLocal(key),
1810 v8::Utils::ToLocal(value_handle),
1811 info);
1812 }
Steve Block44f0eee2011-05-26 01:26:41 +01001813 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001814 return *value_handle;
1815 }
1816
1817 if (structure->IsFixedArray()) {
1818 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1819 if (setter->IsJSFunction()) {
1820 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1821 } else {
1822 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001823 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001824 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01001825 return isolate->Throw(
1826 *isolate->factory()->NewTypeError("no_setter_in_callback",
1827 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001828 }
1829 }
1830
1831 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01001832 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001833}
1834
1835
John Reck59135872010-11-02 12:39:01 -07001836MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1837 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01001838 Isolate* isolate = GetIsolate();
1839 Handle<Object> value_handle(value, isolate);
1840 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1841 Handle<JSObject> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001842#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01001843 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00001844 // Handle stepping into a setter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01001845 if (debug->StepInActive()) {
1846 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001847 }
1848#endif
1849 bool has_pending_exception;
1850 Object** argv[] = { value_handle.location() };
1851 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1852 // Check for pending exception and return the result.
1853 if (has_pending_exception) return Failure::Exception();
1854 return *value_handle;
1855}
1856
1857
1858void JSObject::LookupCallbackSetterInPrototypes(String* name,
1859 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001860 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001861 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001862 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001863 pt = pt->GetPrototype()) {
1864 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001865 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01001866 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
1867 // Found non-callback or read-only callback, stop looking.
1868 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 }
1870 }
1871 result->NotFound();
1872}
1873
1874
Steve Block1e0659c2011-05-24 12:43:12 +01001875MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(uint32_t index,
1876 Object* value,
1877 bool* found) {
Steve Block44f0eee2011-05-26 01:26:41 +01001878 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001879 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001880 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001881 pt = pt->GetPrototype()) {
1882 if (!JSObject::cast(pt)->HasDictionaryElements()) {
1883 continue;
1884 }
1885 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1886 int entry = dictionary->FindEntry(index);
1887 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001888 PropertyDetails details = dictionary->DetailsAt(entry);
1889 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001890 *found = true;
1891 return SetElementWithCallback(
1892 dictionary->ValueAt(entry), index, value, JSObject::cast(pt));
Steve Blocka7e24c12009-10-30 11:49:00 +00001893 }
1894 }
1895 }
Steve Block1e0659c2011-05-24 12:43:12 +01001896 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001897 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001898}
1899
1900
1901void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1902 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001903 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 if (number != DescriptorArray::kNotFound) {
1905 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1906 } else {
1907 result->NotFound();
1908 }
1909}
1910
1911
Ben Murdochb0fe1622011-05-05 13:52:32 +01001912void Map::LookupInDescriptors(JSObject* holder,
1913 String* name,
1914 LookupResult* result) {
1915 DescriptorArray* descriptors = instance_descriptors();
Steve Block44f0eee2011-05-26 01:26:41 +01001916 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1917 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001918 if (number == DescriptorLookupCache::kAbsent) {
1919 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001920 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001921 }
1922 if (number != DescriptorArray::kNotFound) {
1923 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1924 } else {
1925 result->NotFound();
1926 }
1927}
1928
1929
Steve Block44f0eee2011-05-26 01:26:41 +01001930MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
1931 bool safe_to_add_transition) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001932 Heap* current_heap = heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001933 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001934 String* external_array_sentinel_name = current_heap->empty_symbol();
Steve Block44f0eee2011-05-26 01:26:41 +01001935
1936 if (safe_to_add_transition) {
1937 // It's only safe to manipulate the descriptor array if it would be
1938 // safe to add a transition.
1939
1940 ASSERT(!is_shared()); // no transitions can be added to shared maps.
1941 // Check if the external array transition already exists.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001942 DescriptorLookupCache* cache =
1943 current_heap->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01001944 int index = cache->Lookup(descriptors, external_array_sentinel_name);
1945 if (index == DescriptorLookupCache::kAbsent) {
1946 index = descriptors->Search(external_array_sentinel_name);
1947 cache->Update(descriptors,
1948 external_array_sentinel_name,
1949 index);
1950 }
1951
1952 // If the transition already exists, check the type. If there is a match,
1953 // return it.
1954 if (index != DescriptorArray::kNotFound) {
1955 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
1956 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
1957 details.array_type() == array_type) {
1958 return descriptors->GetValue(index);
1959 } else {
1960 safe_to_add_transition = false;
1961 }
1962 }
1963 }
1964
1965 // No transition to an existing external array map. Make a new one.
1966 Object* obj;
1967 { MaybeObject* maybe_map = CopyDropTransitions();
1968 if (!maybe_map->ToObject(&obj)) return maybe_map;
1969 }
1970 Map* new_map = Map::cast(obj);
1971
1972 new_map->set_has_fast_elements(false);
1973 new_map->set_has_external_array_elements(true);
1974 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
1975
1976 // Only remember the map transition if the object's map is NOT equal to the
1977 // global object_function's map and there is not an already existing
1978 // non-matching external array transition.
1979 bool allow_map_transition =
1980 safe_to_add_transition &&
1981 (GetIsolate()->context()->global_context()->object_function()->map() !=
1982 map());
1983 if (allow_map_transition) {
1984 // Allocate new instance descriptors for the old map with map transition.
1985 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
1986 Map::cast(new_map),
1987 array_type);
1988 Object* new_descriptors;
1989 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
1990 &desc,
1991 KEEP_TRANSITIONS);
1992 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1993 return maybe_new_descriptors;
1994 }
1995 descriptors = DescriptorArray::cast(new_descriptors);
1996 set_instance_descriptors(descriptors);
1997 }
1998
1999 return new_map;
2000}
2001
2002
Steve Blocka7e24c12009-10-30 11:49:00 +00002003void JSObject::LocalLookupRealNamedProperty(String* name,
2004 LookupResult* result) {
2005 if (IsJSGlobalProxy()) {
2006 Object* proto = GetPrototype();
2007 if (proto->IsNull()) return result->NotFound();
2008 ASSERT(proto->IsJSGlobalObject());
2009 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2010 }
2011
2012 if (HasFastProperties()) {
2013 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002014 if (result->IsFound()) {
2015 // A property, a map transition or a null descriptor was found.
2016 // We return all of these result types because
2017 // LocalLookupRealNamedProperty is used when setting properties
2018 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002019 ASSERT(result->holder() == this && result->type() != NORMAL);
2020 // Disallow caching for uninitialized constants. These can only
2021 // occur as fields.
2022 if (result->IsReadOnly() && result->type() == FIELD &&
2023 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2024 result->DisallowCaching();
2025 }
2026 return;
2027 }
2028 } else {
2029 int entry = property_dictionary()->FindEntry(name);
2030 if (entry != StringDictionary::kNotFound) {
2031 Object* value = property_dictionary()->ValueAt(entry);
2032 if (IsGlobalObject()) {
2033 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2034 if (d.IsDeleted()) {
2035 result->NotFound();
2036 return;
2037 }
2038 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002039 }
2040 // Make sure to disallow caching for uninitialized constants
2041 // found in the dictionary-mode objects.
2042 if (value->IsTheHole()) result->DisallowCaching();
2043 result->DictionaryResult(this, entry);
2044 return;
2045 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002046 }
2047 result->NotFound();
2048}
2049
2050
2051void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2052 LocalLookupRealNamedProperty(name, result);
2053 if (result->IsProperty()) return;
2054
2055 LookupRealNamedPropertyInPrototypes(name, result);
2056}
2057
2058
2059void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2060 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002061 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002062 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002063 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002064 pt = JSObject::cast(pt)->GetPrototype()) {
2065 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002066 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002067 }
2068 result->NotFound();
2069}
2070
2071
2072// We only need to deal with CALLBACKS and INTERCEPTORS
John Reck59135872010-11-02 12:39:01 -07002073MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(LookupResult* result,
2074 String* name,
Ben Murdoch086aeea2011-05-13 15:57:08 +01002075 Object* value,
2076 bool check_prototype) {
2077 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002078 LookupCallbackSetterInPrototypes(name, result);
2079 }
2080
2081 if (result->IsProperty()) {
2082 if (!result->IsReadOnly()) {
2083 switch (result->type()) {
2084 case CALLBACKS: {
2085 Object* obj = result->GetCallbackObject();
2086 if (obj->IsAccessorInfo()) {
2087 AccessorInfo* info = AccessorInfo::cast(obj);
2088 if (info->all_can_write()) {
2089 return SetPropertyWithCallback(result->GetCallbackObject(),
2090 name,
2091 value,
2092 result->holder());
2093 }
2094 }
2095 break;
2096 }
2097 case INTERCEPTOR: {
2098 // Try lookup real named properties. Note that only property can be
2099 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2100 LookupResult r;
2101 LookupRealNamedProperty(name, &r);
2102 if (r.IsProperty()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002103 return SetPropertyWithFailedAccessCheck(&r, name, value,
2104 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00002105 }
2106 break;
2107 }
2108 default: {
2109 break;
2110 }
2111 }
2112 }
2113 }
2114
Iain Merrick75681382010-08-19 15:07:18 +01002115 HandleScope scope;
2116 Handle<Object> value_handle(value);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002117 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01002118 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002119 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002120}
2121
2122
John Reck59135872010-11-02 12:39:01 -07002123MaybeObject* JSObject::SetProperty(LookupResult* result,
2124 String* name,
2125 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002126 PropertyAttributes attributes,
2127 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002128 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002129 // Make sure that the top context does not change when doing callbacks or
2130 // interceptor calls.
2131 AssertNoContextChange ncc;
2132
Steve Blockd0582a62009-12-15 09:54:21 +00002133 // Optimization for 2-byte strings often used as keys in a decompression
2134 // dictionary. We make these short keys into symbols to avoid constantly
2135 // reallocating them.
2136 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002137 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002138 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002139 if (maybe_symbol_version->ToObject(&symbol_version)) {
2140 name = String::cast(symbol_version);
2141 }
2142 }
Steve Blockd0582a62009-12-15 09:54:21 +00002143 }
2144
Steve Blocka7e24c12009-10-30 11:49:00 +00002145 // Check access rights if needed.
2146 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002147 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002148 return SetPropertyWithFailedAccessCheck(result, name, value, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00002149 }
2150
2151 if (IsJSGlobalProxy()) {
2152 Object* proto = GetPrototype();
2153 if (proto->IsNull()) return value;
2154 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002155 return JSObject::cast(proto)->SetProperty(
2156 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002157 }
2158
2159 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2160 // We could not find a local property so let's check whether there is an
2161 // accessor that wants to handle the property.
2162 LookupResult accessor_result;
2163 LookupCallbackSetterInPrototypes(name, &accessor_result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002164 if (accessor_result.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002165 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2166 name,
2167 value,
2168 accessor_result.holder());
2169 }
2170 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002171 if (!result->IsFound()) {
2172 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002173 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002174 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002175 if (result->IsReadOnly() && result->IsProperty()) {
2176 if (strict_mode == kStrictMode) {
2177 HandleScope scope;
2178 Handle<String> key(name);
2179 Handle<Object> holder(this);
2180 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002181 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2182 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002183 } else {
2184 return value;
2185 }
2186 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002187 // This is a real property that is not read-only, or it is a
2188 // transition or null descriptor and there are no setters in the prototypes.
2189 switch (result->type()) {
2190 case NORMAL:
2191 return SetNormalizedProperty(result, value);
2192 case FIELD:
2193 return FastPropertyAtPut(result->GetFieldIndex(), value);
2194 case MAP_TRANSITION:
2195 if (attributes == result->GetAttributes()) {
2196 // Only use map transition if the attributes match.
2197 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2198 name,
2199 value);
2200 }
2201 return ConvertDescriptorToField(name, value, attributes);
2202 case CONSTANT_FUNCTION:
2203 // Only replace the function if necessary.
2204 if (value == result->GetConstantFunction()) return value;
2205 // Preserve the attributes of this existing property.
2206 attributes = result->GetAttributes();
2207 return ConvertDescriptorToField(name, value, attributes);
2208 case CALLBACKS:
2209 return SetPropertyWithCallback(result->GetCallbackObject(),
2210 name,
2211 value,
2212 result->holder());
2213 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002214 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002215 case CONSTANT_TRANSITION: {
2216 // If the same constant function is being added we can simply
2217 // transition to the target map.
2218 Map* target_map = result->GetTransitionMap();
2219 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2220 int number = target_descriptors->SearchWithCache(name);
2221 ASSERT(number != DescriptorArray::kNotFound);
2222 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2223 JSFunction* function =
2224 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002225 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002226 if (value == function) {
2227 set_map(target_map);
2228 return value;
2229 }
2230 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2231 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002232 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002233 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002234 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002235 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002236 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2237 default:
2238 UNREACHABLE();
2239 }
2240 UNREACHABLE();
2241 return value;
2242}
2243
2244
2245// Set a real local property, even if it is READ_ONLY. If the property is not
2246// present, add it with attributes NONE. This code is an exact clone of
2247// SetProperty, with the check for IsReadOnly and the check for a
2248// callback setter removed. The two lines looking up the LookupResult
2249// result are also added. If one of the functions is changed, the other
2250// should be.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002251MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002252 String* name,
2253 Object* value,
2254 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002255
Steve Blocka7e24c12009-10-30 11:49:00 +00002256 // Make sure that the top context does not change when doing callbacks or
2257 // interceptor calls.
2258 AssertNoContextChange ncc;
Andrei Popescu402d9372010-02-26 13:31:12 +00002259 LookupResult result;
2260 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002261 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002262 if (IsAccessCheckNeeded()) {
2263 Heap* heap = GetHeap();
2264 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
2265 return SetPropertyWithFailedAccessCheck(&result, name, value, false);
2266 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002267 }
2268
2269 if (IsJSGlobalProxy()) {
2270 Object* proto = GetPrototype();
2271 if (proto->IsNull()) return value;
2272 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002273 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002274 name,
2275 value,
2276 attributes);
2277 }
2278
2279 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002280 if (!result.IsFound()) {
2281 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002282 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002283 }
Steve Block6ded16b2010-05-10 14:33:55 +01002284
Andrei Popescu402d9372010-02-26 13:31:12 +00002285 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2286
Steve Blocka7e24c12009-10-30 11:49:00 +00002287 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002288 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002289 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002290 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002291 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002292 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002293 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002294 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002295 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002296 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002297 name,
2298 value);
2299 }
2300 return ConvertDescriptorToField(name, value, attributes);
2301 case CONSTANT_FUNCTION:
2302 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002303 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002304 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002305 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002306 return ConvertDescriptorToField(name, value, attributes);
2307 case CALLBACKS:
2308 case INTERCEPTOR:
2309 // Override callback in clone
2310 return ConvertDescriptorToField(name, value, attributes);
2311 case CONSTANT_TRANSITION:
2312 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2313 // if the value is a function.
2314 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2315 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002316 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002317 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2318 default:
2319 UNREACHABLE();
2320 }
2321 UNREACHABLE();
2322 return value;
2323}
2324
2325
2326PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2327 JSObject* receiver,
2328 String* name,
2329 bool continue_search) {
2330 // Check local property, ignore interceptor.
2331 LookupResult result;
2332 LocalLookupRealNamedProperty(name, &result);
2333 if (result.IsProperty()) return result.GetAttributes();
2334
2335 if (continue_search) {
2336 // Continue searching via the prototype chain.
2337 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002338 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002339 return JSObject::cast(pt)->
2340 GetPropertyAttributeWithReceiver(receiver, name);
2341 }
2342 }
2343 return ABSENT;
2344}
2345
2346
2347PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2348 JSObject* receiver,
2349 String* name,
2350 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002351 Isolate* isolate = GetIsolate();
2352
Steve Blocka7e24c12009-10-30 11:49:00 +00002353 // Make sure that the top context does not change when doing
2354 // callbacks or interceptor calls.
2355 AssertNoContextChange ncc;
2356
Steve Block44f0eee2011-05-26 01:26:41 +01002357 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002358 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2359 Handle<JSObject> receiver_handle(receiver);
2360 Handle<JSObject> holder_handle(this);
2361 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002362 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002363 v8::AccessorInfo info(args.end());
2364 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002365 v8::NamedPropertyQuery query =
2366 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002367 LOG(isolate,
2368 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002369 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002370 {
2371 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002372 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002373 result = query(v8::Utils::ToLocal(name_handle), info);
2374 }
2375 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002376 ASSERT(result->IsInt32());
2377 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002378 }
2379 } else if (!interceptor->getter()->IsUndefined()) {
2380 v8::NamedPropertyGetter getter =
2381 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002382 LOG(isolate,
2383 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002384 v8::Handle<v8::Value> result;
2385 {
2386 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002387 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002388 result = getter(v8::Utils::ToLocal(name_handle), info);
2389 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002390 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002391 }
2392 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2393 *name_handle,
2394 continue_search);
2395}
2396
2397
2398PropertyAttributes JSObject::GetPropertyAttributeWithReceiver(
2399 JSObject* receiver,
2400 String* key) {
2401 uint32_t index = 0;
2402 if (key->AsArrayIndex(&index)) {
2403 if (HasElementWithReceiver(receiver, index)) return NONE;
2404 return ABSENT;
2405 }
2406 // Named property.
2407 LookupResult result;
2408 Lookup(key, &result);
2409 return GetPropertyAttribute(receiver, &result, key, true);
2410}
2411
2412
2413PropertyAttributes JSObject::GetPropertyAttribute(JSObject* receiver,
2414 LookupResult* result,
2415 String* name,
2416 bool continue_search) {
2417 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002418 if (IsAccessCheckNeeded()) {
2419 Heap* heap = GetHeap();
2420 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
2421 return GetPropertyAttributeWithFailedAccessCheck(receiver,
2422 result,
2423 name,
2424 continue_search);
2425 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002426 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002427 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002428 switch (result->type()) {
2429 case NORMAL: // fall through
2430 case FIELD:
2431 case CONSTANT_FUNCTION:
2432 case CALLBACKS:
2433 return result->GetAttributes();
2434 case INTERCEPTOR:
2435 return result->holder()->
2436 GetPropertyAttributeWithInterceptor(receiver, name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002437 default:
2438 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002439 }
2440 }
2441 return ABSENT;
2442}
2443
2444
2445PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) {
2446 // Check whether the name is an array index.
2447 uint32_t index = 0;
2448 if (name->AsArrayIndex(&index)) {
2449 if (HasLocalElement(index)) return NONE;
2450 return ABSENT;
2451 }
2452 // Named property.
2453 LookupResult result;
2454 LocalLookup(name, &result);
2455 return GetPropertyAttribute(this, &result, name, false);
2456}
2457
2458
John Reck59135872010-11-02 12:39:01 -07002459MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2460 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002461 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002462 Map* fast = obj->map();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002463 int index = Hash(fast) % kEntries;
2464 Object* result = get(index);
2465 if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002466#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002467 if (FLAG_enable_slow_asserts) {
2468 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002469 Object* fresh;
2470 { MaybeObject* maybe_fresh =
2471 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2472 if (maybe_fresh->ToObject(&fresh)) {
2473 ASSERT(memcmp(Map::cast(fresh)->address(),
2474 Map::cast(result)->address(),
2475 Map::kSize) == 0);
2476 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002477 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002478 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002479#endif
2480 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002481 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002482
John Reck59135872010-11-02 12:39:01 -07002483 { MaybeObject* maybe_result =
2484 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2485 if (!maybe_result->ToObject(&result)) return maybe_result;
2486 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002487 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002488 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002489
2490 return result;
2491}
2492
2493
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002494void NormalizedMapCache::Clear() {
2495 int entries = length();
2496 for (int i = 0; i != entries; i++) {
2497 set_undefined(i);
2498 }
2499}
2500
2501
2502int NormalizedMapCache::Hash(Map* fast) {
2503 // For performance reasons we only hash the 3 most variable fields of a map:
2504 // constructor, prototype and bit_field2.
2505
2506 // Shift away the tag.
2507 int hash = (static_cast<uint32_t>(
2508 reinterpret_cast<uintptr_t>(fast->constructor())) >> 2);
2509
2510 // XOR-ing the prototype and constructor directly yields too many zero bits
2511 // when the two pointers are close (which is fairly common).
2512 // To avoid this we shift the prototype 4 bits relatively to the constructor.
2513 hash ^= (static_cast<uint32_t>(
2514 reinterpret_cast<uintptr_t>(fast->prototype())) << 2);
2515
2516 return hash ^ (hash >> 16) ^ fast->bit_field2();
2517}
2518
2519
2520bool NormalizedMapCache::CheckHit(Map* slow,
2521 Map* fast,
2522 PropertyNormalizationMode mode) {
2523#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002524 slow->SharedMapVerify();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002525#endif
2526 return
2527 slow->constructor() == fast->constructor() &&
2528 slow->prototype() == fast->prototype() &&
2529 slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
2530 0 :
2531 fast->inobject_properties()) &&
2532 slow->instance_type() == fast->instance_type() &&
2533 slow->bit_field() == fast->bit_field() &&
Ben Murdoch257744e2011-11-30 15:57:28 +00002534 slow->bit_field2() == fast->bit_field2() &&
2535 (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002536}
2537
2538
John Reck59135872010-11-02 12:39:01 -07002539MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002540 if (map()->is_shared()) {
2541 // Fast case maps are never marked as shared.
2542 ASSERT(!HasFastProperties());
2543 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002544 Object* obj;
2545 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2546 UNIQUE_NORMALIZED_MAP);
2547 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2548 }
Steve Block44f0eee2011-05-26 01:26:41 +01002549 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002550
2551 set_map(Map::cast(obj));
2552 }
2553 return map()->UpdateCodeCache(name, code);
2554}
2555
2556
John Reck59135872010-11-02 12:39:01 -07002557MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2558 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002559 if (!HasFastProperties()) return this;
2560
2561 // The global object is always normalized.
2562 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002563 // JSGlobalProxy must never be normalized
2564 ASSERT(!IsJSGlobalProxy());
2565
Ben Murdoch8b112d22011-06-08 16:22:53 +01002566 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01002567
Steve Blocka7e24c12009-10-30 11:49:00 +00002568 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002569 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00002570 if (expected_additional_properties > 0) {
2571 property_count += expected_additional_properties;
2572 } else {
2573 property_count += 2; // Make space for two more properties.
2574 }
John Reck59135872010-11-02 12:39:01 -07002575 Object* obj;
2576 { MaybeObject* maybe_obj =
2577 StringDictionary::Allocate(property_count);
2578 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2579 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002580 StringDictionary* dictionary = StringDictionary::cast(obj);
2581
Ben Murdoch8b112d22011-06-08 16:22:53 +01002582 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002583 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002584 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00002585 switch (details.type()) {
2586 case CONSTANT_FUNCTION: {
2587 PropertyDetails d =
2588 PropertyDetails(details.attributes(), NORMAL, details.index());
2589 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07002590 Object* result;
2591 { MaybeObject* maybe_result =
2592 dictionary->Add(descs->GetKey(i), value, d);
2593 if (!maybe_result->ToObject(&result)) return maybe_result;
2594 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002595 dictionary = StringDictionary::cast(result);
2596 break;
2597 }
2598 case FIELD: {
2599 PropertyDetails d =
2600 PropertyDetails(details.attributes(), NORMAL, details.index());
2601 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07002602 Object* result;
2603 { MaybeObject* maybe_result =
2604 dictionary->Add(descs->GetKey(i), value, d);
2605 if (!maybe_result->ToObject(&result)) return maybe_result;
2606 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002607 dictionary = StringDictionary::cast(result);
2608 break;
2609 }
2610 case CALLBACKS: {
2611 PropertyDetails d =
2612 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2613 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07002614 Object* result;
2615 { MaybeObject* maybe_result =
2616 dictionary->Add(descs->GetKey(i), value, d);
2617 if (!maybe_result->ToObject(&result)) return maybe_result;
2618 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002619 dictionary = StringDictionary::cast(result);
2620 break;
2621 }
2622 case MAP_TRANSITION:
2623 case CONSTANT_TRANSITION:
2624 case NULL_DESCRIPTOR:
2625 case INTERCEPTOR:
Ben Murdoch257744e2011-11-30 15:57:28 +00002626 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002627 break;
2628 default:
2629 UNREACHABLE();
2630 }
2631 }
2632
Ben Murdoch8b112d22011-06-08 16:22:53 +01002633 Heap* current_heap = map_of_this->heap();
2634
Steve Blocka7e24c12009-10-30 11:49:00 +00002635 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002636 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002637 dictionary->SetNextEnumerationIndex(index);
2638
Ben Murdoch8b112d22011-06-08 16:22:53 +01002639 { MaybeObject* maybe_obj =
2640 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01002641 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07002642 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2643 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002644 Map* new_map = Map::cast(obj);
2645
Steve Blocka7e24c12009-10-30 11:49:00 +00002646 // We have now successfully allocated all the necessary objects.
2647 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002648
2649 // Resize the object in the heap if necessary.
2650 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002651 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002652 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002653 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2654 instance_size_delta);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002655
Steve Blocka7e24c12009-10-30 11:49:00 +00002656 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00002657 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002658
2659 set_properties(dictionary);
2660
Ben Murdoch8b112d22011-06-08 16:22:53 +01002661 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002662
2663#ifdef DEBUG
2664 if (FLAG_trace_normalization) {
2665 PrintF("Object properties have been normalized:\n");
2666 Print();
2667 }
2668#endif
2669 return this;
2670}
2671
2672
John Reck59135872010-11-02 12:39:01 -07002673MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002674 if (HasFastProperties()) return this;
2675 ASSERT(!IsGlobalObject());
2676 return property_dictionary()->
2677 TransformPropertiesToFastFor(this, unused_property_fields);
2678}
2679
2680
John Reck59135872010-11-02 12:39:01 -07002681MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002682 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00002683 if (HasDictionaryElements()) return this;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002684 Map* old_map = map();
2685 ASSERT(old_map->has_fast_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01002686
John Reck59135872010-11-02 12:39:01 -07002687 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01002688 { MaybeObject* maybe_obj = old_map->GetSlowElementsMap();
John Reck59135872010-11-02 12:39:01 -07002689 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2690 }
Steve Block8defd9f2010-07-08 12:39:36 +01002691 Map* new_map = Map::cast(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00002692
2693 // Get number of entries.
2694 FixedArray* array = FixedArray::cast(elements());
2695
2696 // Compute the effective length.
2697 int length = IsJSArray() ?
2698 Smi::cast(JSArray::cast(this)->length())->value() :
2699 array->length();
John Reck59135872010-11-02 12:39:01 -07002700 { MaybeObject* maybe_obj = NumberDictionary::Allocate(length);
2701 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2702 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002703 NumberDictionary* dictionary = NumberDictionary::cast(obj);
2704 // Copy entries.
2705 for (int i = 0; i < length; i++) {
2706 Object* value = array->get(i);
2707 if (!value->IsTheHole()) {
2708 PropertyDetails details = PropertyDetails(NONE, NORMAL);
John Reck59135872010-11-02 12:39:01 -07002709 Object* result;
2710 { MaybeObject* maybe_result =
2711 dictionary->AddNumberEntry(i, array->get(i), details);
2712 if (!maybe_result->ToObject(&result)) return maybe_result;
2713 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002714 dictionary = NumberDictionary::cast(result);
2715 }
2716 }
Steve Block8defd9f2010-07-08 12:39:36 +01002717 // Switch to using the dictionary as the backing storage for
2718 // elements. Set the new map first to satify the elements type
2719 // assert in set_elements().
2720 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00002721 set_elements(dictionary);
2722
Ben Murdoch8b112d22011-06-08 16:22:53 +01002723 new_map->heap()->isolate()->counters()->elements_to_dictionary()->
Steve Block44f0eee2011-05-26 01:26:41 +01002724 Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002725
2726#ifdef DEBUG
2727 if (FLAG_trace_normalization) {
2728 PrintF("Object elements have been normalized:\n");
2729 Print();
2730 }
2731#endif
2732
2733 return this;
2734}
2735
2736
John Reck59135872010-11-02 12:39:01 -07002737MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
2738 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002739 // Check local property, ignore interceptor.
2740 LookupResult result;
2741 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002742 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002743
2744 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002745 Object* obj;
2746 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2747 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2748 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002749
2750 return DeleteNormalizedProperty(name, mode);
2751}
2752
2753
John Reck59135872010-11-02 12:39:01 -07002754MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01002755 Isolate* isolate = GetIsolate();
2756 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002757 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2758 Handle<String> name_handle(name);
2759 Handle<JSObject> this_handle(this);
2760 if (!interceptor->deleter()->IsUndefined()) {
2761 v8::NamedPropertyDeleter deleter =
2762 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01002763 LOG(isolate,
2764 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2765 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002766 v8::AccessorInfo info(args.end());
2767 v8::Handle<v8::Boolean> result;
2768 {
2769 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002770 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002771 result = deleter(v8::Utils::ToLocal(name_handle), info);
2772 }
Steve Block44f0eee2011-05-26 01:26:41 +01002773 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002774 if (!result.IsEmpty()) {
2775 ASSERT(result->IsBoolean());
2776 return *v8::Utils::OpenHandle(*result);
2777 }
2778 }
John Reck59135872010-11-02 12:39:01 -07002779 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00002780 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01002781 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002782 return raw_result;
2783}
2784
2785
John Reck59135872010-11-02 12:39:01 -07002786MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
2787 DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002788 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00002789 switch (GetElementsKind()) {
2790 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07002791 Object* obj;
2792 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2793 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2794 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002795 uint32_t length = IsJSArray() ?
2796 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2797 static_cast<uint32_t>(FixedArray::cast(elements())->length());
2798 if (index < length) {
2799 FixedArray::cast(elements())->set_the_hole(index);
2800 }
2801 break;
2802 }
2803 case DICTIONARY_ELEMENTS: {
2804 NumberDictionary* dictionary = element_dictionary();
2805 int entry = dictionary->FindEntry(index);
2806 if (entry != NumberDictionary::kNotFound) {
2807 return dictionary->DeleteProperty(entry, mode);
2808 }
2809 break;
2810 }
2811 default:
2812 UNREACHABLE();
2813 break;
2814 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01002815 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002816}
2817
2818
John Reck59135872010-11-02 12:39:01 -07002819MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01002820 Isolate* isolate = GetIsolate();
2821 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002822 // Make sure that the top context does not change when doing
2823 // callbacks or interceptor calls.
2824 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01002825 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002826 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01002827 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002828 v8::IndexedPropertyDeleter deleter =
2829 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
2830 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01002831 LOG(isolate,
2832 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
2833 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002834 v8::AccessorInfo info(args.end());
2835 v8::Handle<v8::Boolean> result;
2836 {
2837 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002838 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002839 result = deleter(index, info);
2840 }
Steve Block44f0eee2011-05-26 01:26:41 +01002841 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002842 if (!result.IsEmpty()) {
2843 ASSERT(result->IsBoolean());
2844 return *v8::Utils::OpenHandle(*result);
2845 }
John Reck59135872010-11-02 12:39:01 -07002846 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00002847 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01002848 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002849 return raw_result;
2850}
2851
2852
John Reck59135872010-11-02 12:39:01 -07002853MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002854 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002855 // Check access rights if needed.
2856 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002857 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
2858 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2859 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002860 }
2861
2862 if (IsJSGlobalProxy()) {
2863 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002864 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002865 ASSERT(proto->IsJSGlobalObject());
2866 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
2867 }
2868
2869 if (HasIndexedInterceptor()) {
2870 // Skip interceptor if forcing deletion.
2871 if (mode == FORCE_DELETION) {
2872 return DeleteElementPostInterceptor(index, mode);
2873 }
2874 return DeleteElementWithInterceptor(index);
2875 }
2876
2877 switch (GetElementsKind()) {
2878 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07002879 Object* obj;
2880 { MaybeObject* maybe_obj = EnsureWritableFastElements();
2881 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2882 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002883 uint32_t length = IsJSArray() ?
2884 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
2885 static_cast<uint32_t>(FixedArray::cast(elements())->length());
2886 if (index < length) {
2887 FixedArray::cast(elements())->set_the_hole(index);
2888 }
2889 break;
2890 }
Steve Block44f0eee2011-05-26 01:26:41 +01002891 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00002892 case EXTERNAL_BYTE_ELEMENTS:
2893 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
2894 case EXTERNAL_SHORT_ELEMENTS:
2895 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
2896 case EXTERNAL_INT_ELEMENTS:
2897 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
2898 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00002899 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00002900 // Pixel and external array elements cannot be deleted. Just
2901 // silently ignore here.
Steve Blocka7e24c12009-10-30 11:49:00 +00002902 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00002903 case DICTIONARY_ELEMENTS: {
2904 NumberDictionary* dictionary = element_dictionary();
2905 int entry = dictionary->FindEntry(index);
2906 if (entry != NumberDictionary::kNotFound) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002907 Object* result = dictionary->DeleteProperty(entry, mode);
Steve Block44f0eee2011-05-26 01:26:41 +01002908 if (mode == STRICT_DELETION && result ==
2909 isolate->heap()->false_value()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002910 // In strict mode, deleting a non-configurable property throws
2911 // exception. dictionary->DeleteProperty will return false_value()
2912 // if a non-configurable property is being deleted.
2913 HandleScope scope;
Ben Murdoch257744e2011-11-30 15:57:28 +00002914 Handle<Object> self(this);
Steve Block44f0eee2011-05-26 01:26:41 +01002915 Handle<Object> i = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch257744e2011-11-30 15:57:28 +00002916 Handle<Object> args[2] = { i, self };
Steve Block44f0eee2011-05-26 01:26:41 +01002917 return isolate->Throw(*isolate->factory()->NewTypeError(
2918 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002919 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002920 }
2921 break;
2922 }
2923 default:
2924 UNREACHABLE();
2925 break;
2926 }
Steve Block44f0eee2011-05-26 01:26:41 +01002927 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002928}
2929
2930
John Reck59135872010-11-02 12:39:01 -07002931MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002932 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00002933 // ECMA-262, 3rd, 8.6.2.5
2934 ASSERT(name->IsString());
2935
2936 // Check access rights if needed.
2937 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01002938 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
2939 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
2940 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002941 }
2942
2943 if (IsJSGlobalProxy()) {
2944 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002945 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002946 ASSERT(proto->IsJSGlobalObject());
2947 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
2948 }
2949
2950 uint32_t index = 0;
2951 if (name->AsArrayIndex(&index)) {
2952 return DeleteElement(index, mode);
2953 } else {
2954 LookupResult result;
2955 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01002956 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002957 // Ignore attributes if forcing a deletion.
2958 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002959 if (mode == STRICT_DELETION) {
2960 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01002961 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002962 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01002963 return isolate->Throw(*isolate->factory()->NewTypeError(
2964 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002965 }
Steve Block44f0eee2011-05-26 01:26:41 +01002966 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002967 }
2968 // Check for interceptor.
2969 if (result.type() == INTERCEPTOR) {
2970 // Skip interceptor if forcing a deletion.
2971 if (mode == FORCE_DELETION) {
2972 return DeletePropertyPostInterceptor(name, mode);
2973 }
2974 return DeletePropertyWithInterceptor(name);
2975 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002976 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002977 Object* obj;
2978 { MaybeObject* maybe_obj =
2979 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2980 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2981 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002982 // Make sure the properties are normalized before removing the entry.
2983 return DeleteNormalizedProperty(name, mode);
2984 }
2985}
2986
2987
2988// Check whether this object references another object.
2989bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002990 Map* map_of_this = map();
2991 Heap* heap = map_of_this->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002992 AssertNoAllocation no_alloc;
2993
2994 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01002995 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002996 return true;
2997 }
2998
2999 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003000 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003001 return true;
3002 }
3003
3004 // Check if the object is among the named properties.
3005 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003006 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003007 return true;
3008 }
3009
3010 // Check if the object is among the indexed properties.
3011 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003012 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003013 case EXTERNAL_BYTE_ELEMENTS:
3014 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3015 case EXTERNAL_SHORT_ELEMENTS:
3016 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3017 case EXTERNAL_INT_ELEMENTS:
3018 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3019 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003020 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003021 // Raw pixels and external arrays do not reference other
3022 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00003023 break;
3024 case FAST_ELEMENTS: {
3025 int length = IsJSArray() ?
3026 Smi::cast(JSArray::cast(this)->length())->value() :
3027 FixedArray::cast(elements())->length();
3028 for (int i = 0; i < length; i++) {
3029 Object* element = FixedArray::cast(elements())->get(i);
3030 if (!element->IsTheHole() && element == obj) {
3031 return true;
3032 }
3033 }
3034 break;
3035 }
3036 case DICTIONARY_ELEMENTS: {
3037 key = element_dictionary()->SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003038 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003039 return true;
3040 }
3041 break;
3042 }
3043 default:
3044 UNREACHABLE();
3045 break;
3046 }
3047
Steve Block6ded16b2010-05-10 14:33:55 +01003048 // For functions check the context.
3049 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003050 // Get the constructor function for arguments array.
3051 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01003052 heap->isolate()->context()->global_context()->
3053 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003054 JSFunction* arguments_function =
3055 JSFunction::cast(arguments_boilerplate->map()->constructor());
3056
3057 // Get the context and don't check if it is the global context.
3058 JSFunction* f = JSFunction::cast(this);
3059 Context* context = f->context();
3060 if (context->IsGlobalContext()) {
3061 return false;
3062 }
3063
3064 // Check the non-special context slots.
3065 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3066 // Only check JS objects.
3067 if (context->get(i)->IsJSObject()) {
3068 JSObject* ctxobj = JSObject::cast(context->get(i));
3069 // If it is an arguments array check the content.
3070 if (ctxobj->map()->constructor() == arguments_function) {
3071 if (ctxobj->ReferencesObject(obj)) {
3072 return true;
3073 }
3074 } else if (ctxobj == obj) {
3075 return true;
3076 }
3077 }
3078 }
3079
3080 // Check the context extension if any.
3081 if (context->has_extension()) {
3082 return context->extension()->ReferencesObject(obj);
3083 }
3084 }
3085
3086 // No references to object.
3087 return false;
3088}
3089
3090
John Reck59135872010-11-02 12:39:01 -07003091MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01003092 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003093 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003094 !isolate->MayNamedAccess(this,
3095 isolate->heap()->undefined_value(),
3096 v8::ACCESS_KEYS)) {
3097 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3098 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003099 }
3100
Steve Block1e0659c2011-05-24 12:43:12 +01003101 if (IsJSGlobalProxy()) {
3102 Object* proto = GetPrototype();
3103 if (proto->IsNull()) return this;
3104 ASSERT(proto->IsJSGlobalObject());
3105 return JSObject::cast(proto)->PreventExtensions();
3106 }
3107
Ben Murdoch257744e2011-11-30 15:57:28 +00003108 // It's not possible to seal objects with external array elements
3109 if (HasExternalArrayElements()) {
3110 HandleScope scope(isolate);
3111 Handle<Object> object(this);
3112 Handle<Object> error =
3113 isolate->factory()->NewTypeError(
3114 "cant_prevent_ext_external_array_elements",
3115 HandleVector(&object, 1));
3116 return isolate->Throw(*error);
3117 }
3118
Steve Block8defd9f2010-07-08 12:39:36 +01003119 // If there are fast elements we normalize.
3120 if (HasFastElements()) {
John Reck59135872010-11-02 12:39:01 -07003121 Object* ok;
3122 { MaybeObject* maybe_ok = NormalizeElements();
3123 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3124 }
Steve Block8defd9f2010-07-08 12:39:36 +01003125 }
3126 // Make sure that we never go back to fast case.
3127 element_dictionary()->set_requires_slow_elements();
3128
3129 // Do a map transition, other objects with this map may still
3130 // be extensible.
John Reck59135872010-11-02 12:39:01 -07003131 Object* new_map;
3132 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
3133 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3134 }
Steve Block8defd9f2010-07-08 12:39:36 +01003135 Map::cast(new_map)->set_is_extensible(false);
3136 set_map(Map::cast(new_map));
3137 ASSERT(!map()->is_extensible());
3138 return new_map;
3139}
3140
3141
Steve Blocka7e24c12009-10-30 11:49:00 +00003142// Tests for the fast common case for property enumeration:
Steve Blockd0582a62009-12-15 09:54:21 +00003143// - This object and all prototypes has an enum cache (which means that it has
3144// no interceptors and needs no access checks).
3145// - This object has no elements.
3146// - No prototype has enumerable properties/elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00003147bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003148 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003149 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003150 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003151 o = JSObject::cast(o)->GetPrototype()) {
3152 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003153 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003154 ASSERT(!curr->HasNamedInterceptor());
3155 ASSERT(!curr->HasIndexedInterceptor());
3156 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003157 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003158 if (curr != this) {
3159 FixedArray* curr_fixed_array =
3160 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003161 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003162 }
3163 }
3164 return true;
3165}
3166
3167
3168int Map::NumberOfDescribedProperties() {
3169 int result = 0;
3170 DescriptorArray* descs = instance_descriptors();
3171 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3172 if (descs->IsProperty(i)) result++;
3173 }
3174 return result;
3175}
3176
3177
3178int Map::PropertyIndexFor(String* name) {
3179 DescriptorArray* descs = instance_descriptors();
3180 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3181 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3182 return descs->GetFieldIndex(i);
3183 }
3184 }
3185 return -1;
3186}
3187
3188
3189int Map::NextFreePropertyIndex() {
3190 int max_index = -1;
3191 DescriptorArray* descs = instance_descriptors();
3192 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3193 if (descs->GetType(i) == FIELD) {
3194 int current_index = descs->GetFieldIndex(i);
3195 if (current_index > max_index) max_index = current_index;
3196 }
3197 }
3198 return max_index + 1;
3199}
3200
3201
3202AccessorDescriptor* Map::FindAccessor(String* name) {
3203 DescriptorArray* descs = instance_descriptors();
3204 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3205 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3206 return descs->GetCallbacks(i);
3207 }
3208 }
3209 return NULL;
3210}
3211
3212
3213void JSObject::LocalLookup(String* name, LookupResult* result) {
3214 ASSERT(name->IsString());
3215
Steve Block44f0eee2011-05-26 01:26:41 +01003216 Heap* heap = GetHeap();
3217
Steve Blocka7e24c12009-10-30 11:49:00 +00003218 if (IsJSGlobalProxy()) {
3219 Object* proto = GetPrototype();
3220 if (proto->IsNull()) return result->NotFound();
3221 ASSERT(proto->IsJSGlobalObject());
3222 return JSObject::cast(proto)->LocalLookup(name, result);
3223 }
3224
3225 // Do not use inline caching if the object is a non-global object
3226 // that requires access checks.
3227 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
3228 result->DisallowCaching();
3229 }
3230
3231 // Check __proto__ before interceptor.
Steve Block44f0eee2011-05-26 01:26:41 +01003232 if (name->Equals(heap->Proto_symbol()) &&
3233 !IsJSContextExtensionObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003234 result->ConstantResult(this);
3235 return;
3236 }
3237
3238 // Check for lookup interceptor except when bootstrapping.
Steve Block44f0eee2011-05-26 01:26:41 +01003239 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003240 result->InterceptorResult(this);
3241 return;
3242 }
3243
3244 LocalLookupRealNamedProperty(name, result);
3245}
3246
3247
3248void JSObject::Lookup(String* name, LookupResult* result) {
3249 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003250 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003251 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003252 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003253 current = JSObject::cast(current)->GetPrototype()) {
3254 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003255 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003256 }
3257 result->NotFound();
3258}
3259
3260
3261// Search object and it's prototype chain for callback properties.
3262void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003263 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003264 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003265 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003266 current = JSObject::cast(current)->GetPrototype()) {
3267 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003268 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003269 }
3270 result->NotFound();
3271}
3272
3273
John Reck59135872010-11-02 12:39:01 -07003274MaybeObject* JSObject::DefineGetterSetter(String* name,
3275 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003276 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003277 // Make sure that the top context does not change when doing callbacks or
3278 // interceptor calls.
3279 AssertNoContextChange ncc;
3280
Steve Blocka7e24c12009-10-30 11:49:00 +00003281 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01003282 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003283
Leon Clarkef7060e22010-06-03 12:02:55 +01003284 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003285 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003286 }
3287
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003288 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003289 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003290
3291 if (is_element) {
3292 switch (GetElementsKind()) {
3293 case FAST_ELEMENTS:
3294 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003295 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003296 case EXTERNAL_BYTE_ELEMENTS:
3297 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3298 case EXTERNAL_SHORT_ELEMENTS:
3299 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3300 case EXTERNAL_INT_ELEMENTS:
3301 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3302 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003303 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003304 // Ignore getters and setters on pixel and external array
3305 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003306 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003307 case DICTIONARY_ELEMENTS: {
3308 // Lookup the index.
3309 NumberDictionary* dictionary = element_dictionary();
3310 int entry = dictionary->FindEntry(index);
3311 if (entry != NumberDictionary::kNotFound) {
3312 Object* result = dictionary->ValueAt(entry);
3313 PropertyDetails details = dictionary->DetailsAt(entry);
Steve Block44f0eee2011-05-26 01:26:41 +01003314 if (details.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003315 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003316 if (result->IsFixedArray()) {
3317 return result;
3318 }
3319 // Otherwise allow to override it.
Steve Blocka7e24c12009-10-30 11:49:00 +00003320 }
3321 }
3322 break;
3323 }
3324 default:
3325 UNREACHABLE();
3326 break;
3327 }
3328 } else {
3329 // Lookup the name.
3330 LookupResult result;
3331 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003332 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003333 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003334 if (result.type() == CALLBACKS) {
3335 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01003336 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00003337 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003338 // Use set to update attributes.
3339 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003340 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003341 }
3342 }
3343 }
3344
3345 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07003346 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01003347 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07003348 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3349 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003350
3351 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003352 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003353 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003354 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003355 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003356}
3357
3358
3359bool JSObject::CanSetCallback(String* name) {
3360 ASSERT(!IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01003361 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003362
3363 // Check if there is an API defined callback object which prohibits
3364 // callback overwriting in this object or it's prototype chain.
3365 // This mechanism is needed for instance in a browser setting, where
3366 // certain accessors such as window.location should not be allowed
3367 // to be overwritten because allowing overwriting could potentially
3368 // cause security problems.
3369 LookupResult callback_result;
3370 LookupCallback(name, &callback_result);
3371 if (callback_result.IsProperty()) {
3372 Object* obj = callback_result.GetCallbackObject();
3373 if (obj->IsAccessorInfo() &&
3374 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3375 return false;
3376 }
3377 }
3378
3379 return true;
3380}
3381
3382
John Reck59135872010-11-02 12:39:01 -07003383MaybeObject* JSObject::SetElementCallback(uint32_t index,
3384 Object* structure,
3385 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003386 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3387
3388 // Normalize elements to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003389 Object* ok;
3390 { MaybeObject* maybe_ok = NormalizeElements();
3391 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3392 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003393
3394 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003395 Object* dict;
3396 { MaybeObject* maybe_dict =
3397 element_dictionary()->Set(index, structure, details);
3398 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
3399 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003400
3401 NumberDictionary* elements = NumberDictionary::cast(dict);
3402 elements->set_requires_slow_elements();
3403 // Set the potential new dictionary on the object.
3404 set_elements(elements);
Steve Blocka7e24c12009-10-30 11:49:00 +00003405
3406 return structure;
3407}
3408
3409
John Reck59135872010-11-02 12:39:01 -07003410MaybeObject* JSObject::SetPropertyCallback(String* name,
3411 Object* structure,
3412 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003413 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3414
3415 bool convert_back_to_fast = HasFastProperties() &&
3416 (map()->instance_descriptors()->number_of_descriptors()
3417 < DescriptorArray::kMaxNumberOfDescriptors);
3418
3419 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003420 Object* ok;
3421 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3422 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3423 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003424
3425 // For the global object allocate a new map to invalidate the global inline
3426 // caches which have a global property cell reference directly in the code.
3427 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07003428 Object* new_map;
3429 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3430 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3431 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003432 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003433 // When running crankshaft, changing the map is not enough. We
3434 // need to deoptimize all functions that rely on this global
3435 // object.
3436 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003437 }
3438
3439 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003440 Object* result;
3441 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3442 if (!maybe_result->ToObject(&result)) return maybe_result;
3443 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003444
3445 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07003446 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3447 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3448 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003449 }
3450 return result;
3451}
3452
John Reck59135872010-11-02 12:39:01 -07003453MaybeObject* JSObject::DefineAccessor(String* name,
3454 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01003455 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003456 PropertyAttributes attributes) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003457 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003458 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003459 // Check access rights if needed.
3460 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003461 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3462 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3463 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003464 }
3465
3466 if (IsJSGlobalProxy()) {
3467 Object* proto = GetPrototype();
3468 if (proto->IsNull()) return this;
3469 ASSERT(proto->IsJSGlobalObject());
3470 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3471 fun, attributes);
3472 }
3473
John Reck59135872010-11-02 12:39:01 -07003474 Object* array;
3475 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3476 if (!maybe_array->ToObject(&array)) return maybe_array;
3477 }
3478 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003479 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3480 return this;
3481}
3482
3483
John Reck59135872010-11-02 12:39:01 -07003484MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003485 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003486 String* name = String::cast(info->name());
3487 // Check access rights if needed.
3488 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003489 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3490 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3491 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003492 }
3493
3494 if (IsJSGlobalProxy()) {
3495 Object* proto = GetPrototype();
3496 if (proto->IsNull()) return this;
3497 ASSERT(proto->IsJSGlobalObject());
3498 return JSObject::cast(proto)->DefineAccessor(info);
3499 }
3500
3501 // Make sure that the top context does not change when doing callbacks or
3502 // interceptor calls.
3503 AssertNoContextChange ncc;
3504
3505 // Try to flatten before operating on the string.
3506 name->TryFlatten();
3507
3508 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003509 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003510 }
3511
3512 uint32_t index = 0;
3513 bool is_element = name->AsArrayIndex(&index);
3514
3515 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003516 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003517
3518 // Accessors overwrite previous callbacks (cf. with getters/setters).
3519 switch (GetElementsKind()) {
3520 case FAST_ELEMENTS:
3521 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003522 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003523 case EXTERNAL_BYTE_ELEMENTS:
3524 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3525 case EXTERNAL_SHORT_ELEMENTS:
3526 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3527 case EXTERNAL_INT_ELEMENTS:
3528 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3529 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003530 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003531 // Ignore getters and setters on pixel and external array
3532 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003533 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003534 case DICTIONARY_ELEMENTS:
3535 break;
3536 default:
3537 UNREACHABLE();
3538 break;
3539 }
3540
John Reck59135872010-11-02 12:39:01 -07003541 Object* ok;
3542 { MaybeObject* maybe_ok =
3543 SetElementCallback(index, info, info->property_attributes());
3544 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3545 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003546 } else {
3547 // Lookup the name.
3548 LookupResult result;
3549 LocalLookup(name, &result);
3550 // ES5 forbids turning a property into an accessor if it's not
3551 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3552 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003553 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003554 }
John Reck59135872010-11-02 12:39:01 -07003555 Object* ok;
3556 { MaybeObject* maybe_ok =
3557 SetPropertyCallback(name, info, info->property_attributes());
3558 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3559 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003560 }
3561
3562 return this;
3563}
3564
3565
Steve Blocka7e24c12009-10-30 11:49:00 +00003566Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003567 Heap* heap = GetHeap();
3568
Steve Blocka7e24c12009-10-30 11:49:00 +00003569 // Make sure that the top context does not change when doing callbacks or
3570 // interceptor calls.
3571 AssertNoContextChange ncc;
3572
3573 // Check access rights if needed.
3574 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003575 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3576 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3577 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003578 }
3579
3580 // Make the lookup and include prototypes.
3581 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003582 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003583 if (name->AsArrayIndex(&index)) {
3584 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003585 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003586 obj = JSObject::cast(obj)->GetPrototype()) {
3587 JSObject* js_object = JSObject::cast(obj);
3588 if (js_object->HasDictionaryElements()) {
3589 NumberDictionary* dictionary = js_object->element_dictionary();
3590 int entry = dictionary->FindEntry(index);
3591 if (entry != NumberDictionary::kNotFound) {
3592 Object* element = dictionary->ValueAt(entry);
3593 PropertyDetails details = dictionary->DetailsAt(entry);
3594 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003595 if (element->IsFixedArray()) {
3596 return FixedArray::cast(element)->get(accessor_index);
3597 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003598 }
3599 }
3600 }
3601 }
3602 } else {
3603 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003604 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003605 obj = JSObject::cast(obj)->GetPrototype()) {
3606 LookupResult result;
3607 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003608 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003609 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003610 if (result.type() == CALLBACKS) {
3611 Object* obj = result.GetCallbackObject();
3612 if (obj->IsFixedArray()) {
3613 return FixedArray::cast(obj)->get(accessor_index);
3614 }
3615 }
3616 }
3617 }
3618 }
Steve Block44f0eee2011-05-26 01:26:41 +01003619 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003620}
3621
3622
3623Object* JSObject::SlowReverseLookup(Object* value) {
3624 if (HasFastProperties()) {
3625 DescriptorArray* descs = map()->instance_descriptors();
3626 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3627 if (descs->GetType(i) == FIELD) {
3628 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3629 return descs->GetKey(i);
3630 }
3631 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3632 if (descs->GetConstantFunction(i) == value) {
3633 return descs->GetKey(i);
3634 }
3635 }
3636 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003637 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003638 } else {
3639 return property_dictionary()->SlowReverseLookup(value);
3640 }
3641}
3642
3643
John Reck59135872010-11-02 12:39:01 -07003644MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01003645 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07003646 Object* result;
3647 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003648 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07003649 if (!maybe_result->ToObject(&result)) return maybe_result;
3650 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003651 Map::cast(result)->set_prototype(prototype());
3652 Map::cast(result)->set_constructor(constructor());
3653 // Don't copy descriptors, so map transitions always remain a forest.
3654 // If we retained the same descriptors we would have two maps
3655 // pointing to the same transition which is bad because the garbage
3656 // collector relies on being able to reverse pointers from transitions
3657 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00003658 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00003659 // Please note instance_type and instance_size are set when allocated.
3660 Map::cast(result)->set_inobject_properties(inobject_properties());
3661 Map::cast(result)->set_unused_property_fields(unused_property_fields());
3662
3663 // If the map has pre-allocated properties always start out with a descriptor
3664 // array describing these properties.
3665 if (pre_allocated_property_fields() > 0) {
3666 ASSERT(constructor()->IsJSFunction());
3667 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07003668 Object* descriptors;
3669 { MaybeObject* maybe_descriptors =
3670 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
3671 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3672 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003673 Map::cast(result)->set_instance_descriptors(
3674 DescriptorArray::cast(descriptors));
3675 Map::cast(result)->set_pre_allocated_property_fields(
3676 pre_allocated_property_fields());
3677 }
3678 Map::cast(result)->set_bit_field(bit_field());
3679 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00003680 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003681 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01003682 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00003683 return result;
3684}
3685
3686
John Reck59135872010-11-02 12:39:01 -07003687MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
3688 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003689 int new_instance_size = instance_size();
3690 if (mode == CLEAR_INOBJECT_PROPERTIES) {
3691 new_instance_size -= inobject_properties() * kPointerSize;
3692 }
3693
John Reck59135872010-11-02 12:39:01 -07003694 Object* result;
3695 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003696 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07003697 if (!maybe_result->ToObject(&result)) return maybe_result;
3698 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003699
3700 if (mode != CLEAR_INOBJECT_PROPERTIES) {
3701 Map::cast(result)->set_inobject_properties(inobject_properties());
3702 }
3703
3704 Map::cast(result)->set_prototype(prototype());
3705 Map::cast(result)->set_constructor(constructor());
3706
3707 Map::cast(result)->set_bit_field(bit_field());
3708 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00003709 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003710
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003711 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
3712
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003713#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003714 if (Map::cast(result)->is_shared()) {
3715 Map::cast(result)->SharedMapVerify();
3716 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01003717#endif
3718
3719 return result;
3720}
3721
3722
John Reck59135872010-11-02 12:39:01 -07003723MaybeObject* Map::CopyDropTransitions() {
3724 Object* new_map;
3725 { MaybeObject* maybe_new_map = CopyDropDescriptors();
3726 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3727 }
3728 Object* descriptors;
3729 { MaybeObject* maybe_descriptors =
3730 instance_descriptors()->RemoveTransitions();
3731 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
3732 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003733 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01003734 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00003735}
3736
3737
John Reck59135872010-11-02 12:39:01 -07003738MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003739 // Allocate the code cache if not present.
3740 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07003741 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +01003742 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07003743 if (!maybe_result->ToObject(&result)) return maybe_result;
3744 }
Steve Block6ded16b2010-05-10 14:33:55 +01003745 set_code_cache(result);
3746 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003747
Steve Block6ded16b2010-05-10 14:33:55 +01003748 // Update the code cache.
3749 return CodeCache::cast(code_cache())->Update(name, code);
3750}
3751
3752
3753Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
3754 // Do a lookup if a code cache exists.
3755 if (!code_cache()->IsFixedArray()) {
3756 return CodeCache::cast(code_cache())->Lookup(name, flags);
3757 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003758 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003759 }
3760}
3761
3762
3763int Map::IndexInCodeCache(Object* name, Code* code) {
3764 // Get the internal index if a code cache exists.
3765 if (!code_cache()->IsFixedArray()) {
3766 return CodeCache::cast(code_cache())->GetIndex(name, code);
3767 }
3768 return -1;
3769}
3770
3771
3772void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
3773 // No GC is supposed to happen between a call to IndexInCodeCache and
3774 // RemoveFromCodeCache so the code cache must be there.
3775 ASSERT(!code_cache()->IsFixedArray());
3776 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
3777}
3778
3779
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003780void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Steve Block053d10c2011-06-13 19:13:29 +01003781 // Traverse the transition tree without using a stack. We do this by
3782 // reversing the pointers in the maps and descriptor arrays.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003783 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003784 Map* meta_map = heap()->meta_map();
Steve Block053d10c2011-06-13 19:13:29 +01003785 Object** map_or_index_field = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01003786 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003787 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00003788 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
Steve Block053d10c2011-06-13 19:13:29 +01003789 if (!d->IsEmpty()) {
3790 FixedArray* contents = reinterpret_cast<FixedArray*>(
3791 d->get(DescriptorArray::kContentArrayIndex));
3792 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
3793 Object* map_or_index = *map_or_index_field;
3794 bool map_done = true; // Controls a nested continue statement.
3795 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
3796 i < contents->length();
3797 i += 2) {
3798 PropertyDetails details(Smi::cast(contents->get(i + 1)));
3799 if (details.IsTransition()) {
3800 // Found a map in the transition array. We record our progress in
3801 // the transition array by recording the current map in the map field
3802 // of the next map and recording the index in the transition array in
3803 // the map field of the array.
3804 Map* next = Map::cast(contents->get(i));
3805 next->set_map(current);
3806 *map_or_index_field = Smi::FromInt(i + 2);
3807 current = next;
3808 map_done = false;
3809 break;
3810 }
3811 }
3812 if (!map_done) continue;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01003813 } else {
3814 map_or_index_field = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003815 }
Steve Block053d10c2011-06-13 19:13:29 +01003816 // That was the regular transitions, now for the prototype transitions.
3817 FixedArray* prototype_transitions =
3818 current->unchecked_prototype_transitions();
3819 Object** proto_map_or_index_field =
3820 RawField(prototype_transitions, HeapObject::kMapOffset);
3821 Object* map_or_index = *proto_map_or_index_field;
3822 const int start = 2;
3823 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
3824 if (i < prototype_transitions->length()) {
3825 // Found a map in the prototype transition array. Record progress in
3826 // an analogous way to the regular transitions array above.
3827 Object* perhaps_map = prototype_transitions->get(i);
3828 if (perhaps_map->IsMap()) {
3829 Map* next = Map::cast(perhaps_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003830 next->set_map(current);
Steve Block053d10c2011-06-13 19:13:29 +01003831 *proto_map_or_index_field =
3832 Smi::FromInt(i + 2);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003833 current = next;
Steve Block053d10c2011-06-13 19:13:29 +01003834 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003835 }
3836 }
Steve Block053d10c2011-06-13 19:13:29 +01003837 *proto_map_or_index_field = heap()->fixed_array_map();
3838 if (map_or_index_field != NULL) {
3839 *map_or_index_field = heap()->fixed_array_map();
3840 }
3841
3842 // The callback expects a map to have a real map as its map, so we save
3843 // the map field, which is being used to track the traversal and put the
3844 // correct map (the meta_map) in place while we do the callback.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003845 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01003846 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01003847 callback(current, data);
3848 current = prev;
3849 }
3850}
3851
3852
John Reck59135872010-11-02 12:39:01 -07003853MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003854 // The number of monomorphic stubs for normal load/store/call IC's can grow to
3855 // a large number and therefore they need to go into a hash table. They are
3856 // used to load global properties from cells.
3857 if (code->type() == NORMAL) {
3858 // Make sure that a hash table is allocated for the normal load code cache.
3859 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07003860 Object* result;
3861 { MaybeObject* maybe_result =
3862 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
3863 if (!maybe_result->ToObject(&result)) return maybe_result;
3864 }
Steve Block6ded16b2010-05-10 14:33:55 +01003865 set_normal_type_cache(result);
3866 }
3867 return UpdateNormalTypeCache(name, code);
3868 } else {
3869 ASSERT(default_cache()->IsFixedArray());
3870 return UpdateDefaultCache(name, code);
3871 }
3872}
3873
3874
John Reck59135872010-11-02 12:39:01 -07003875MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003876 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00003877 // flags. This allows call constant stubs to overwrite call field
3878 // stubs, etc.
3879 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
3880
3881 // First check whether we can update existing code cache without
3882 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01003883 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003884 int length = cache->length();
3885 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01003886 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003887 Object* key = cache->get(i);
3888 if (key->IsNull()) {
3889 if (deleted_index < 0) deleted_index = i;
3890 continue;
3891 }
3892 if (key->IsUndefined()) {
3893 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01003894 cache->set(i + kCodeCacheEntryNameOffset, name);
3895 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003896 return this;
3897 }
3898 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003899 Code::Flags found =
3900 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00003901 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01003902 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003903 return this;
3904 }
3905 }
3906 }
3907
3908 // Reached the end of the code cache. If there were deleted
3909 // elements, reuse the space for the first of them.
3910 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01003911 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
3912 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00003913 return this;
3914 }
3915
Steve Block6ded16b2010-05-10 14:33:55 +01003916 // Extend the code cache with some new entries (at least one). Must be a
3917 // multiple of the entry size.
3918 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
3919 new_length = new_length - new_length % kCodeCacheEntrySize;
3920 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07003921 Object* result;
3922 { MaybeObject* maybe_result = cache->CopySize(new_length);
3923 if (!maybe_result->ToObject(&result)) return maybe_result;
3924 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003925
3926 // Add the (name, code) pair to the new cache.
3927 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01003928 cache->set(length + kCodeCacheEntryNameOffset, name);
3929 cache->set(length + kCodeCacheEntryCodeOffset, code);
3930 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00003931 return this;
3932}
3933
3934
John Reck59135872010-11-02 12:39:01 -07003935MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01003936 // Adding a new entry can cause a new cache to be allocated.
3937 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07003938 Object* new_cache;
3939 { MaybeObject* maybe_new_cache = cache->Put(name, code);
3940 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
3941 }
Steve Block6ded16b2010-05-10 14:33:55 +01003942 set_normal_type_cache(new_cache);
3943 return this;
3944}
3945
3946
3947Object* CodeCache::Lookup(String* name, Code::Flags flags) {
3948 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
3949 return LookupNormalTypeCache(name, flags);
3950 } else {
3951 return LookupDefaultCache(name, flags);
3952 }
3953}
3954
3955
3956Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
3957 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003958 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003959 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
3960 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00003961 // Skip deleted elements.
3962 if (key->IsNull()) continue;
3963 if (key->IsUndefined()) return key;
3964 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01003965 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
3966 if (code->flags() == flags) {
3967 return code;
3968 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003969 }
3970 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003971 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003972}
3973
3974
Steve Block6ded16b2010-05-10 14:33:55 +01003975Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
3976 if (!normal_type_cache()->IsUndefined()) {
3977 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3978 return cache->Lookup(name, flags);
3979 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01003980 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01003981 }
3982}
3983
3984
3985int CodeCache::GetIndex(Object* name, Code* code) {
3986 if (code->type() == NORMAL) {
3987 if (normal_type_cache()->IsUndefined()) return -1;
3988 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
3989 return cache->GetIndex(String::cast(name), code->flags());
3990 }
3991
3992 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00003993 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01003994 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
3995 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00003996 }
3997 return -1;
3998}
3999
4000
Steve Block6ded16b2010-05-10 14:33:55 +01004001void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
4002 if (code->type() == NORMAL) {
4003 ASSERT(!normal_type_cache()->IsUndefined());
4004 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4005 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
4006 cache->RemoveByIndex(index);
4007 } else {
4008 FixedArray* array = default_cache();
4009 ASSERT(array->length() >= index && array->get(index)->IsCode());
4010 // Use null instead of undefined for deleted elements to distinguish
4011 // deleted elements from unused elements. This distinction is used
4012 // when looking up in the cache and when updating the cache.
4013 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4014 array->set_null(index - 1); // Name.
4015 array->set_null(index); // Code.
4016 }
4017}
4018
4019
4020// The key in the code cache hash table consists of the property name and the
4021// code object. The actual match is on the name and the code flags. If a key
4022// is created using the flags and not a code object it can only be used for
4023// lookup not to create a new entry.
4024class CodeCacheHashTableKey : public HashTableKey {
4025 public:
4026 CodeCacheHashTableKey(String* name, Code::Flags flags)
4027 : name_(name), flags_(flags), code_(NULL) { }
4028
4029 CodeCacheHashTableKey(String* name, Code* code)
4030 : name_(name),
4031 flags_(code->flags()),
4032 code_(code) { }
4033
4034
4035 bool IsMatch(Object* other) {
4036 if (!other->IsFixedArray()) return false;
4037 FixedArray* pair = FixedArray::cast(other);
4038 String* name = String::cast(pair->get(0));
4039 Code::Flags flags = Code::cast(pair->get(1))->flags();
4040 if (flags != flags_) {
4041 return false;
4042 }
4043 return name_->Equals(name);
4044 }
4045
4046 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4047 return name->Hash() ^ flags;
4048 }
4049
4050 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4051
4052 uint32_t HashForObject(Object* obj) {
4053 FixedArray* pair = FixedArray::cast(obj);
4054 String* name = String::cast(pair->get(0));
4055 Code* code = Code::cast(pair->get(1));
4056 return NameFlagsHashHelper(name, code->flags());
4057 }
4058
John Reck59135872010-11-02 12:39:01 -07004059 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01004060 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07004061 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004062 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07004063 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4064 }
Steve Block6ded16b2010-05-10 14:33:55 +01004065 FixedArray* pair = FixedArray::cast(obj);
4066 pair->set(0, name_);
4067 pair->set(1, code_);
4068 return pair;
4069 }
4070
4071 private:
4072 String* name_;
4073 Code::Flags flags_;
4074 Code* code_;
4075};
4076
4077
4078Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4079 CodeCacheHashTableKey key(name, flags);
4080 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01004081 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004082 return get(EntryToIndex(entry) + 1);
4083}
4084
4085
John Reck59135872010-11-02 12:39:01 -07004086MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004087 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07004088 Object* obj;
4089 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4090 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4091 }
Steve Block6ded16b2010-05-10 14:33:55 +01004092
4093 // Don't use this, as the table might have grown.
4094 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4095
4096 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004097 Object* k;
4098 { MaybeObject* maybe_k = key.AsObject();
4099 if (!maybe_k->ToObject(&k)) return maybe_k;
4100 }
Steve Block6ded16b2010-05-10 14:33:55 +01004101
4102 cache->set(EntryToIndex(entry), k);
4103 cache->set(EntryToIndex(entry) + 1, code);
4104 cache->ElementAdded();
4105 return cache;
4106}
4107
4108
4109int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4110 CodeCacheHashTableKey key(name, flags);
4111 int entry = FindEntry(&key);
4112 return (entry == kNotFound) ? -1 : entry;
4113}
4114
4115
4116void CodeCacheHashTable::RemoveByIndex(int index) {
4117 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004118 Heap* heap = GetHeap();
4119 set(EntryToIndex(index), heap->null_value());
4120 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004121 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004122}
4123
4124
Steve Blocka7e24c12009-10-30 11:49:00 +00004125static bool HasKey(FixedArray* array, Object* key) {
4126 int len0 = array->length();
4127 for (int i = 0; i < len0; i++) {
4128 Object* element = array->get(i);
4129 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4130 if (element->IsString() &&
4131 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4132 return true;
4133 }
4134 }
4135 return false;
4136}
4137
4138
John Reck59135872010-11-02 12:39:01 -07004139MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Steve Block44f0eee2011-05-26 01:26:41 +01004140 ASSERT(!array->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00004141 switch (array->GetElementsKind()) {
4142 case JSObject::FAST_ELEMENTS:
4143 return UnionOfKeys(FixedArray::cast(array->elements()));
4144 case JSObject::DICTIONARY_ELEMENTS: {
4145 NumberDictionary* dict = array->element_dictionary();
4146 int size = dict->NumberOfElements();
4147
4148 // Allocate a temporary fixed array.
John Reck59135872010-11-02 12:39:01 -07004149 Object* object;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004150 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
John Reck59135872010-11-02 12:39:01 -07004151 if (!maybe_object->ToObject(&object)) return maybe_object;
4152 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004153 FixedArray* key_array = FixedArray::cast(object);
4154
4155 int capacity = dict->Capacity();
4156 int pos = 0;
4157 // Copy the elements from the JSArray to the temporary fixed array.
4158 for (int i = 0; i < capacity; i++) {
4159 if (dict->IsKey(dict->KeyAt(i))) {
4160 key_array->set(pos++, dict->ValueAt(i));
4161 }
4162 }
4163 // Compute the union of this and the temporary fixed array.
4164 return UnionOfKeys(key_array);
4165 }
4166 default:
4167 UNREACHABLE();
4168 }
4169 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01004170 return GetHeap()->null_value(); // Failure case needs to "return" a value.
Steve Blocka7e24c12009-10-30 11:49:00 +00004171}
4172
4173
John Reck59135872010-11-02 12:39:01 -07004174MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004175 int len0 = length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004176#ifdef DEBUG
4177 if (FLAG_enable_slow_asserts) {
4178 for (int i = 0; i < len0; i++) {
4179 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4180 }
4181 }
4182#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004183 int len1 = other->length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004184 // Optimize if 'other' is empty.
4185 // We cannot optimize if 'this' is empty, as other may have holes
4186 // or non keys.
Steve Blocka7e24c12009-10-30 11:49:00 +00004187 if (len1 == 0) return this;
4188
4189 // Compute how many elements are not in this.
4190 int extra = 0;
4191 for (int y = 0; y < len1; y++) {
4192 Object* value = other->get(y);
4193 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
4194 }
4195
4196 if (extra == 0) return this;
4197
4198 // Allocate the result
John Reck59135872010-11-02 12:39:01 -07004199 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004200 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
John Reck59135872010-11-02 12:39:01 -07004201 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4202 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004203 // Fill in the content
Leon Clarke4515c472010-02-03 11:58:03 +00004204 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004205 FixedArray* result = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00004206 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004207 for (int i = 0; i < len0; i++) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004208 Object* e = get(i);
4209 ASSERT(e->IsString() || e->IsNumber());
4210 result->set(i, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004211 }
4212 // Fill in the extra keys.
4213 int index = 0;
4214 for (int y = 0; y < len1; y++) {
4215 Object* value = other->get(y);
4216 if (!value->IsTheHole() && !HasKey(this, value)) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004217 Object* e = other->get(y);
4218 ASSERT(e->IsString() || e->IsNumber());
4219 result->set(len0 + index, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004220 index++;
4221 }
4222 }
4223 ASSERT(extra == index);
4224 return result;
4225}
4226
4227
John Reck59135872010-11-02 12:39:01 -07004228MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004229 Heap* heap = GetHeap();
4230 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004231 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004232 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004233 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4234 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004235 FixedArray* result = FixedArray::cast(obj);
4236 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004237 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004238 int len = length();
4239 if (new_length < len) len = new_length;
4240 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004241 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004242 for (int i = 0; i < len; i++) {
4243 result->set(i, get(i), mode);
4244 }
4245 return result;
4246}
4247
4248
4249void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004250 AssertNoAllocation no_gc;
4251 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004252 for (int index = 0; index < len; index++) {
4253 dest->set(dest_pos+index, get(pos+index), mode);
4254 }
4255}
4256
4257
4258#ifdef DEBUG
4259bool FixedArray::IsEqualTo(FixedArray* other) {
4260 if (length() != other->length()) return false;
4261 for (int i = 0 ; i < length(); ++i) {
4262 if (get(i) != other->get(i)) return false;
4263 }
4264 return true;
4265}
4266#endif
4267
4268
John Reck59135872010-11-02 12:39:01 -07004269MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004270 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004271 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004272 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004273 }
4274 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004275 Object* array;
4276 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004277 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004278 if (!maybe_array->ToObject(&array)) return maybe_array;
4279 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004280 // Do not use DescriptorArray::cast on incomplete object.
4281 FixedArray* result = FixedArray::cast(array);
4282
4283 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004284 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004285 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004286 if (!maybe_array->ToObject(&array)) return maybe_array;
4287 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004288 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00004289 result->set(kContentArrayIndex, array);
4290 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004291 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004292 return result;
4293}
4294
4295
4296void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4297 FixedArray* new_cache) {
4298 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4299 if (HasEnumCache()) {
4300 FixedArray::cast(get(kEnumerationIndexIndex))->
4301 set(kEnumCacheBridgeCacheIndex, new_cache);
4302 } else {
4303 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4304 FixedArray::cast(bridge_storage)->
4305 set(kEnumCacheBridgeCacheIndex, new_cache);
4306 fast_set(FixedArray::cast(bridge_storage),
4307 kEnumCacheBridgeEnumIndex,
4308 get(kEnumerationIndexIndex));
4309 set(kEnumerationIndexIndex, bridge_storage);
4310 }
4311}
4312
4313
John Reck59135872010-11-02 12:39:01 -07004314MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4315 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004316 // Transitions are only kept when inserting another transition.
4317 // This precondition is not required by this function's implementation, but
4318 // is currently required by the semantics of maps, so we check it.
4319 // Conversely, we filter after replacing, so replacing a transition and
4320 // removing all other transitions is not supported.
4321 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4322 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4323 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4324
4325 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004326 Object* result;
4327 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4328 if (!maybe_result->ToObject(&result)) return maybe_result;
4329 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004330
4331 int transitions = 0;
4332 int null_descriptors = 0;
4333 if (remove_transitions) {
4334 for (int i = 0; i < number_of_descriptors(); i++) {
4335 if (IsTransition(i)) transitions++;
4336 if (IsNullDescriptor(i)) null_descriptors++;
4337 }
4338 } else {
4339 for (int i = 0; i < number_of_descriptors(); i++) {
4340 if (IsNullDescriptor(i)) null_descriptors++;
4341 }
4342 }
4343 int new_size = number_of_descriptors() - transitions - null_descriptors;
4344
4345 // If key is in descriptor, we replace it in-place when filtering.
4346 // Count a null descriptor for key as inserted, not replaced.
4347 int index = Search(descriptor->GetKey());
4348 const bool inserting = (index == kNotFound);
4349 const bool replacing = !inserting;
4350 bool keep_enumeration_index = false;
4351 if (inserting) {
4352 ++new_size;
4353 }
4354 if (replacing) {
4355 // We are replacing an existing descriptor. We keep the enumeration
4356 // index of a visible property.
4357 PropertyType t = PropertyDetails(GetDetails(index)).type();
4358 if (t == CONSTANT_FUNCTION ||
4359 t == FIELD ||
4360 t == CALLBACKS ||
4361 t == INTERCEPTOR) {
4362 keep_enumeration_index = true;
4363 } else if (remove_transitions) {
4364 // Replaced descriptor has been counted as removed if it is
4365 // a transition that will be replaced. Adjust count in this case.
4366 ++new_size;
4367 }
4368 }
John Reck59135872010-11-02 12:39:01 -07004369 { MaybeObject* maybe_result = Allocate(new_size);
4370 if (!maybe_result->ToObject(&result)) return maybe_result;
4371 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004372 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4373 // Set the enumeration index in the descriptors and set the enumeration index
4374 // in the result.
4375 int enumeration_index = NextEnumerationIndex();
4376 if (!descriptor->GetDetails().IsTransition()) {
4377 if (keep_enumeration_index) {
4378 descriptor->SetEnumerationIndex(
4379 PropertyDetails(GetDetails(index)).index());
4380 } else {
4381 descriptor->SetEnumerationIndex(enumeration_index);
4382 ++enumeration_index;
4383 }
4384 }
4385 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4386
4387 // Copy the descriptors, filtering out transitions and null descriptors,
4388 // and inserting or replacing a descriptor.
4389 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4390 int from_index = 0;
4391 int to_index = 0;
4392
4393 for (; from_index < number_of_descriptors(); from_index++) {
4394 String* key = GetKey(from_index);
4395 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4396 break;
4397 }
4398 if (IsNullDescriptor(from_index)) continue;
4399 if (remove_transitions && IsTransition(from_index)) continue;
4400 new_descriptors->CopyFrom(to_index++, this, from_index);
4401 }
4402
4403 new_descriptors->Set(to_index++, descriptor);
4404 if (replacing) from_index++;
4405
4406 for (; from_index < number_of_descriptors(); from_index++) {
4407 if (IsNullDescriptor(from_index)) continue;
4408 if (remove_transitions && IsTransition(from_index)) continue;
4409 new_descriptors->CopyFrom(to_index++, this, from_index);
4410 }
4411
4412 ASSERT(to_index == new_descriptors->number_of_descriptors());
4413 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4414
4415 return new_descriptors;
4416}
4417
4418
John Reck59135872010-11-02 12:39:01 -07004419MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004420 // Remove all transitions and null descriptors. Return a copy of the array
4421 // with all transitions removed, or a Failure object if the new array could
4422 // not be allocated.
4423
4424 // Compute the size of the map transition entries to be removed.
4425 int num_removed = 0;
4426 for (int i = 0; i < number_of_descriptors(); i++) {
4427 if (!IsProperty(i)) num_removed++;
4428 }
4429
4430 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07004431 Object* result;
4432 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4433 if (!maybe_result->ToObject(&result)) return maybe_result;
4434 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004435 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4436
4437 // Copy the content.
4438 int next_descriptor = 0;
4439 for (int i = 0; i < number_of_descriptors(); i++) {
4440 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
4441 }
4442 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4443
4444 return new_descriptors;
4445}
4446
4447
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004448void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004449 // In-place heap sort.
4450 int len = number_of_descriptors();
4451
4452 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004453 // Index of the last node with children
4454 const int max_parent_index = (len / 2) - 1;
4455 for (int i = max_parent_index; i >= 0; --i) {
4456 int parent_index = i;
4457 const uint32_t parent_hash = GetKey(i)->Hash();
4458 while (parent_index <= max_parent_index) {
4459 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004460 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004461 if (child_index + 1 < len) {
4462 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4463 if (right_child_hash > child_hash) {
4464 child_index++;
4465 child_hash = right_child_hash;
4466 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004467 }
Steve Block6ded16b2010-05-10 14:33:55 +01004468 if (child_hash <= parent_hash) break;
4469 Swap(parent_index, child_index);
4470 // Now element at child_index could be < its children.
4471 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004472 }
4473 }
4474
4475 // Extract elements and create sorted array.
4476 for (int i = len - 1; i > 0; --i) {
4477 // Put max element at the back of the array.
4478 Swap(0, i);
4479 // Sift down the new top element.
4480 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004481 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4482 const int max_parent_index = (i / 2) - 1;
4483 while (parent_index <= max_parent_index) {
4484 int child_index = parent_index * 2 + 1;
4485 uint32_t child_hash = GetKey(child_index)->Hash();
4486 if (child_index + 1 < i) {
4487 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4488 if (right_child_hash > child_hash) {
4489 child_index++;
4490 child_hash = right_child_hash;
4491 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004492 }
Steve Block6ded16b2010-05-10 14:33:55 +01004493 if (child_hash <= parent_hash) break;
4494 Swap(parent_index, child_index);
4495 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004496 }
4497 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004498}
Steve Blocka7e24c12009-10-30 11:49:00 +00004499
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004500
4501void DescriptorArray::Sort() {
4502 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004503 SLOW_ASSERT(IsSortedNoDuplicates());
4504}
4505
4506
4507int DescriptorArray::BinarySearch(String* name, int low, int high) {
4508 uint32_t hash = name->Hash();
4509
4510 while (low <= high) {
4511 int mid = (low + high) / 2;
4512 String* mid_name = GetKey(mid);
4513 uint32_t mid_hash = mid_name->Hash();
4514
4515 if (mid_hash > hash) {
4516 high = mid - 1;
4517 continue;
4518 }
4519 if (mid_hash < hash) {
4520 low = mid + 1;
4521 continue;
4522 }
4523 // Found an element with the same hash-code.
4524 ASSERT(hash == mid_hash);
4525 // There might be more, so we find the first one and
4526 // check them all to see if we have a match.
4527 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4528 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4529 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4530 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4531 }
4532 break;
4533 }
4534 return kNotFound;
4535}
4536
4537
4538int DescriptorArray::LinearSearch(String* name, int len) {
4539 uint32_t hash = name->Hash();
4540 for (int number = 0; number < len; number++) {
4541 String* entry = GetKey(number);
4542 if ((entry->Hash() == hash) &&
4543 name->Equals(entry) &&
4544 !is_null_descriptor(number)) {
4545 return number;
4546 }
4547 }
4548 return kNotFound;
4549}
4550
4551
Ben Murdochb0fe1622011-05-05 13:52:32 +01004552MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4553 PretenureFlag pretenure) {
4554 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004555 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004556 pretenure);
4557}
4558
4559
4560MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
4561 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01004562 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
4563 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004564 pretenure);
4565}
4566
4567
Steve Blocka7e24c12009-10-30 11:49:00 +00004568#ifdef DEBUG
4569bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
4570 if (IsEmpty()) return other->IsEmpty();
4571 if (other->IsEmpty()) return false;
4572 if (length() != other->length()) return false;
4573 for (int i = 0; i < length(); ++i) {
4574 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
4575 }
4576 return GetContentArray()->IsEqualTo(other->GetContentArray());
4577}
4578#endif
4579
4580
Steve Blocka7e24c12009-10-30 11:49:00 +00004581bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01004582 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00004583 return true;
4584}
4585
4586
4587int String::Utf8Length() {
4588 if (IsAsciiRepresentation()) return length();
4589 // Attempt to flatten before accessing the string. It probably
4590 // doesn't make Utf8Length faster, but it is very likely that
4591 // the string will be accessed later (for example by WriteUtf8)
4592 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01004593 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01004594 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01004595 Access<StringInputBuffer> buffer(
4596 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004597 buffer->Reset(0, this);
4598 int result = 0;
4599 while (buffer->has_more())
4600 result += unibrow::Utf8::Length(buffer->GetNext());
4601 return result;
4602}
4603
4604
4605Vector<const char> String::ToAsciiVector() {
4606 ASSERT(IsAsciiRepresentation());
4607 ASSERT(IsFlat());
4608
4609 int offset = 0;
4610 int length = this->length();
4611 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4612 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004613 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004614 ConsString* cons = ConsString::cast(string);
4615 ASSERT(cons->second()->length() == 0);
4616 string = cons->first();
4617 string_tag = StringShape(string).representation_tag();
4618 }
4619 if (string_tag == kSeqStringTag) {
4620 SeqAsciiString* seq = SeqAsciiString::cast(string);
4621 char* start = seq->GetChars();
4622 return Vector<const char>(start + offset, length);
4623 }
4624 ASSERT(string_tag == kExternalStringTag);
4625 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
4626 const char* start = ext->resource()->data();
4627 return Vector<const char>(start + offset, length);
4628}
4629
4630
4631Vector<const uc16> String::ToUC16Vector() {
4632 ASSERT(IsTwoByteRepresentation());
4633 ASSERT(IsFlat());
4634
4635 int offset = 0;
4636 int length = this->length();
4637 StringRepresentationTag string_tag = StringShape(this).representation_tag();
4638 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00004639 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004640 ConsString* cons = ConsString::cast(string);
4641 ASSERT(cons->second()->length() == 0);
4642 string = cons->first();
4643 string_tag = StringShape(string).representation_tag();
4644 }
4645 if (string_tag == kSeqStringTag) {
4646 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
4647 return Vector<const uc16>(seq->GetChars() + offset, length);
4648 }
4649 ASSERT(string_tag == kExternalStringTag);
4650 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
4651 const uc16* start =
4652 reinterpret_cast<const uc16*>(ext->resource()->data());
4653 return Vector<const uc16>(start + offset, length);
4654}
4655
4656
4657SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4658 RobustnessFlag robust_flag,
4659 int offset,
4660 int length,
4661 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004662 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4663 return SmartPointer<char>(NULL);
4664 }
Steve Block44f0eee2011-05-26 01:26:41 +01004665 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004666
4667 // Negative length means the to the end of the string.
4668 if (length < 0) length = kMaxInt - offset;
4669
4670 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01004671 Access<StringInputBuffer> buffer(
4672 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004673 buffer->Reset(offset, this);
4674 int character_position = offset;
4675 int utf8_bytes = 0;
4676 while (buffer->has_more()) {
4677 uint16_t character = buffer->GetNext();
4678 if (character_position < offset + length) {
4679 utf8_bytes += unibrow::Utf8::Length(character);
4680 }
4681 character_position++;
4682 }
4683
4684 if (length_return) {
4685 *length_return = utf8_bytes;
4686 }
4687
4688 char* result = NewArray<char>(utf8_bytes + 1);
4689
4690 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
4691 buffer->Rewind();
4692 buffer->Seek(offset);
4693 character_position = offset;
4694 int utf8_byte_position = 0;
4695 while (buffer->has_more()) {
4696 uint16_t character = buffer->GetNext();
4697 if (character_position < offset + length) {
4698 if (allow_nulls == DISALLOW_NULLS && character == 0) {
4699 character = ' ';
4700 }
4701 utf8_byte_position +=
4702 unibrow::Utf8::Encode(result + utf8_byte_position, character);
4703 }
4704 character_position++;
4705 }
4706 result[utf8_byte_position] = 0;
4707 return SmartPointer<char>(result);
4708}
4709
4710
4711SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
4712 RobustnessFlag robust_flag,
4713 int* length_return) {
4714 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
4715}
4716
4717
4718const uc16* String::GetTwoByteData() {
4719 return GetTwoByteData(0);
4720}
4721
4722
4723const uc16* String::GetTwoByteData(unsigned start) {
4724 ASSERT(!IsAsciiRepresentation());
4725 switch (StringShape(this).representation_tag()) {
4726 case kSeqStringTag:
4727 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
4728 case kExternalStringTag:
4729 return ExternalTwoByteString::cast(this)->
4730 ExternalTwoByteStringGetData(start);
Steve Blocka7e24c12009-10-30 11:49:00 +00004731 case kConsStringTag:
4732 UNREACHABLE();
4733 return NULL;
4734 }
4735 UNREACHABLE();
4736 return NULL;
4737}
4738
4739
4740SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004741 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
4742 return SmartPointer<uc16>();
4743 }
Steve Block44f0eee2011-05-26 01:26:41 +01004744 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004745
Steve Block44f0eee2011-05-26 01:26:41 +01004746 Access<StringInputBuffer> buffer(
4747 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00004748 buffer->Reset(this);
4749
4750 uc16* result = NewArray<uc16>(length() + 1);
4751
4752 int i = 0;
4753 while (buffer->has_more()) {
4754 uint16_t character = buffer->GetNext();
4755 result[i++] = character;
4756 }
4757 result[i] = 0;
4758 return SmartPointer<uc16>(result);
4759}
4760
4761
4762const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
4763 return reinterpret_cast<uc16*>(
4764 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
4765}
4766
4767
4768void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4769 unsigned* offset_ptr,
4770 unsigned max_chars) {
4771 unsigned chars_read = 0;
4772 unsigned offset = *offset_ptr;
4773 while (chars_read < max_chars) {
4774 uint16_t c = *reinterpret_cast<uint16_t*>(
4775 reinterpret_cast<char*>(this) -
4776 kHeapObjectTag + kHeaderSize + offset * kShortSize);
4777 if (c <= kMaxAsciiCharCode) {
4778 // Fast case for ASCII characters. Cursor is an input output argument.
4779 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4780 rbb->util_buffer,
4781 rbb->capacity,
4782 rbb->cursor)) {
4783 break;
4784 }
4785 } else {
4786 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4787 rbb->util_buffer,
4788 rbb->capacity,
4789 rbb->cursor)) {
4790 break;
4791 }
4792 }
4793 offset++;
4794 chars_read++;
4795 }
4796 *offset_ptr = offset;
4797 rbb->remaining += chars_read;
4798}
4799
4800
4801const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
4802 unsigned* remaining,
4803 unsigned* offset_ptr,
4804 unsigned max_chars) {
4805 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
4806 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
4807 *remaining = max_chars;
4808 *offset_ptr += max_chars;
4809 return b;
4810}
4811
4812
4813// This will iterate unless the block of string data spans two 'halves' of
4814// a ConsString, in which case it will recurse. Since the block of string
4815// data to be read has a maximum size this limits the maximum recursion
4816// depth to something sane. Since C++ does not have tail call recursion
4817// elimination, the iteration must be explicit. Since this is not an
4818// -IntoBuffer method it can delegate to one of the efficient
4819// *AsciiStringReadBlock routines.
4820const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
4821 unsigned* offset_ptr,
4822 unsigned max_chars) {
4823 ConsString* current = this;
4824 unsigned offset = *offset_ptr;
4825 int offset_correction = 0;
4826
4827 while (true) {
4828 String* left = current->first();
4829 unsigned left_length = (unsigned)left->length();
4830 if (left_length > offset &&
4831 (max_chars <= left_length - offset ||
4832 (rbb->capacity <= left_length - offset &&
4833 (max_chars = left_length - offset, true)))) { // comma operator!
4834 // Left hand side only - iterate unless we have reached the bottom of
4835 // the cons tree. The assignment on the left of the comma operator is
4836 // in order to make use of the fact that the -IntoBuffer routines can
4837 // produce at most 'capacity' characters. This enables us to postpone
4838 // the point where we switch to the -IntoBuffer routines (below) in order
4839 // to maximize the chances of delegating a big chunk of work to the
4840 // efficient *AsciiStringReadBlock routines.
4841 if (StringShape(left).IsCons()) {
4842 current = ConsString::cast(left);
4843 continue;
4844 } else {
4845 const unibrow::byte* answer =
4846 String::ReadBlock(left, rbb, &offset, max_chars);
4847 *offset_ptr = offset + offset_correction;
4848 return answer;
4849 }
4850 } else if (left_length <= offset) {
4851 // Right hand side only - iterate unless we have reached the bottom of
4852 // the cons tree.
4853 String* right = current->second();
4854 offset -= left_length;
4855 offset_correction += left_length;
4856 if (StringShape(right).IsCons()) {
4857 current = ConsString::cast(right);
4858 continue;
4859 } else {
4860 const unibrow::byte* answer =
4861 String::ReadBlock(right, rbb, &offset, max_chars);
4862 *offset_ptr = offset + offset_correction;
4863 return answer;
4864 }
4865 } else {
4866 // The block to be read spans two sides of the ConsString, so we call the
4867 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
4868 // are able to assemble data from several part strings because they use
4869 // the util_buffer to store their data and never return direct pointers
4870 // to their storage. We don't try to read more than the buffer capacity
4871 // here or we can get too much recursion.
4872 ASSERT(rbb->remaining == 0);
4873 ASSERT(rbb->cursor == 0);
4874 current->ConsStringReadBlockIntoBuffer(
4875 rbb,
4876 &offset,
4877 max_chars > rbb->capacity ? rbb->capacity : max_chars);
4878 *offset_ptr = offset + offset_correction;
4879 return rbb->util_buffer;
4880 }
4881 }
4882}
4883
4884
Steve Blocka7e24c12009-10-30 11:49:00 +00004885uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
4886 ASSERT(index >= 0 && index < length());
4887 return resource()->data()[index];
4888}
4889
4890
4891const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
4892 unsigned* remaining,
4893 unsigned* offset_ptr,
4894 unsigned max_chars) {
4895 // Cast const char* to unibrow::byte* (signedness difference).
4896 const unibrow::byte* b =
4897 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
4898 *remaining = max_chars;
4899 *offset_ptr += max_chars;
4900 return b;
4901}
4902
4903
4904const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
4905 unsigned start) {
4906 return resource()->data() + start;
4907}
4908
4909
4910uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
4911 ASSERT(index >= 0 && index < length());
4912 return resource()->data()[index];
4913}
4914
4915
4916void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
4917 ReadBlockBuffer* rbb,
4918 unsigned* offset_ptr,
4919 unsigned max_chars) {
4920 unsigned chars_read = 0;
4921 unsigned offset = *offset_ptr;
4922 const uint16_t* data = resource()->data();
4923 while (chars_read < max_chars) {
4924 uint16_t c = data[offset];
4925 if (c <= kMaxAsciiCharCode) {
4926 // Fast case for ASCII characters. Cursor is an input output argument.
4927 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
4928 rbb->util_buffer,
4929 rbb->capacity,
4930 rbb->cursor))
4931 break;
4932 } else {
4933 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
4934 rbb->util_buffer,
4935 rbb->capacity,
4936 rbb->cursor))
4937 break;
4938 }
4939 offset++;
4940 chars_read++;
4941 }
4942 *offset_ptr = offset;
4943 rbb->remaining += chars_read;
4944}
4945
4946
4947void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
4948 unsigned* offset_ptr,
4949 unsigned max_chars) {
4950 unsigned capacity = rbb->capacity - rbb->cursor;
4951 if (max_chars > capacity) max_chars = capacity;
4952 memcpy(rbb->util_buffer + rbb->cursor,
4953 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
4954 *offset_ptr * kCharSize,
4955 max_chars);
4956 rbb->remaining += max_chars;
4957 *offset_ptr += max_chars;
4958 rbb->cursor += max_chars;
4959}
4960
4961
4962void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
4963 ReadBlockBuffer* rbb,
4964 unsigned* offset_ptr,
4965 unsigned max_chars) {
4966 unsigned capacity = rbb->capacity - rbb->cursor;
4967 if (max_chars > capacity) max_chars = capacity;
4968 memcpy(rbb->util_buffer + rbb->cursor,
4969 resource()->data() + *offset_ptr,
4970 max_chars);
4971 rbb->remaining += max_chars;
4972 *offset_ptr += max_chars;
4973 rbb->cursor += max_chars;
4974}
4975
4976
4977// This method determines the type of string involved and then copies
4978// a whole chunk of characters into a buffer, or returns a pointer to a buffer
4979// where they can be found. The pointer is not necessarily valid across a GC
4980// (see AsciiStringReadBlock).
4981const unibrow::byte* String::ReadBlock(String* input,
4982 ReadBlockBuffer* rbb,
4983 unsigned* offset_ptr,
4984 unsigned max_chars) {
4985 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
4986 if (max_chars == 0) {
4987 rbb->remaining = 0;
4988 return NULL;
4989 }
4990 switch (StringShape(input).representation_tag()) {
4991 case kSeqStringTag:
4992 if (input->IsAsciiRepresentation()) {
4993 SeqAsciiString* str = SeqAsciiString::cast(input);
4994 return str->SeqAsciiStringReadBlock(&rbb->remaining,
4995 offset_ptr,
4996 max_chars);
4997 } else {
4998 SeqTwoByteString* str = SeqTwoByteString::cast(input);
4999 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5000 offset_ptr,
5001 max_chars);
5002 return rbb->util_buffer;
5003 }
5004 case kConsStringTag:
5005 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5006 offset_ptr,
5007 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005008 case kExternalStringTag:
5009 if (input->IsAsciiRepresentation()) {
5010 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5011 &rbb->remaining,
5012 offset_ptr,
5013 max_chars);
5014 } else {
5015 ExternalTwoByteString::cast(input)->
5016 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5017 offset_ptr,
5018 max_chars);
5019 return rbb->util_buffer;
5020 }
5021 default:
5022 break;
5023 }
5024
5025 UNREACHABLE();
5026 return 0;
5027}
5028
5029
Steve Blocka7e24c12009-10-30 11:49:00 +00005030void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01005031 Isolate* isolate = Isolate::Current();
5032 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00005033 while (current != NULL) {
5034 current->PostGarbageCollection();
5035 current = current->prev_;
5036 }
5037}
5038
5039
5040// Reserve space for statics needing saving and restoring.
5041int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01005042 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005043}
5044
5045
5046// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005047char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01005048 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5049 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005050 return to + ArchiveSpacePerThread();
5051}
5052
5053
5054// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005055char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01005056 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00005057 return from + ArchiveSpacePerThread();
5058}
5059
5060
5061char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5062 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5063 Iterate(v, top);
5064 return thread_storage + ArchiveSpacePerThread();
5065}
5066
5067
5068void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01005069 Isolate* isolate = Isolate::Current();
5070 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005071}
5072
5073
5074void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5075 Relocatable* current = top;
5076 while (current != NULL) {
5077 current->IterateInstance(v);
5078 current = current->prev_;
5079 }
5080}
5081
5082
Steve Block44f0eee2011-05-26 01:26:41 +01005083FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5084 : Relocatable(isolate),
5085 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00005086 length_(str->length()) {
5087 PostGarbageCollection();
5088}
5089
5090
Steve Block44f0eee2011-05-26 01:26:41 +01005091FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5092 : Relocatable(isolate),
5093 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005094 is_ascii_(true),
5095 length_(input.length()),
5096 start_(input.start()) { }
5097
5098
5099void FlatStringReader::PostGarbageCollection() {
5100 if (str_ == NULL) return;
5101 Handle<String> str(str_);
5102 ASSERT(str->IsFlat());
5103 is_ascii_ = str->IsAsciiRepresentation();
5104 if (is_ascii_) {
5105 start_ = str->ToAsciiVector().start();
5106 } else {
5107 start_ = str->ToUC16Vector().start();
5108 }
5109}
5110
5111
5112void StringInputBuffer::Seek(unsigned pos) {
5113 Reset(pos, input_);
5114}
5115
5116
5117void SafeStringInputBuffer::Seek(unsigned pos) {
5118 Reset(pos, input_);
5119}
5120
5121
5122// This method determines the type of string involved and then copies
5123// a whole chunk of characters into a buffer. It can be used with strings
5124// that have been glued together to form a ConsString and which must cooperate
5125// to fill up a buffer.
5126void String::ReadBlockIntoBuffer(String* input,
5127 ReadBlockBuffer* rbb,
5128 unsigned* offset_ptr,
5129 unsigned max_chars) {
5130 ASSERT(*offset_ptr <= (unsigned)input->length());
5131 if (max_chars == 0) return;
5132
5133 switch (StringShape(input).representation_tag()) {
5134 case kSeqStringTag:
5135 if (input->IsAsciiRepresentation()) {
5136 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5137 offset_ptr,
5138 max_chars);
5139 return;
5140 } else {
5141 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5142 offset_ptr,
5143 max_chars);
5144 return;
5145 }
5146 case kConsStringTag:
5147 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5148 offset_ptr,
5149 max_chars);
5150 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005151 case kExternalStringTag:
5152 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005153 ExternalAsciiString::cast(input)->
5154 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5155 } else {
5156 ExternalTwoByteString::cast(input)->
5157 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5158 offset_ptr,
5159 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005160 }
5161 return;
5162 default:
5163 break;
5164 }
5165
5166 UNREACHABLE();
5167 return;
5168}
5169
5170
5171const unibrow::byte* String::ReadBlock(String* input,
5172 unibrow::byte* util_buffer,
5173 unsigned capacity,
5174 unsigned* remaining,
5175 unsigned* offset_ptr) {
5176 ASSERT(*offset_ptr <= (unsigned)input->length());
5177 unsigned chars = input->length() - *offset_ptr;
5178 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5179 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5180 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5181 *remaining = rbb.remaining;
5182 return answer;
5183}
5184
5185
5186const unibrow::byte* String::ReadBlock(String** raw_input,
5187 unibrow::byte* util_buffer,
5188 unsigned capacity,
5189 unsigned* remaining,
5190 unsigned* offset_ptr) {
5191 Handle<String> input(raw_input);
5192 ASSERT(*offset_ptr <= (unsigned)input->length());
5193 unsigned chars = input->length() - *offset_ptr;
5194 if (chars > capacity) chars = capacity;
5195 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5196 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5197 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5198 *remaining = rbb.remaining;
5199 return rbb.util_buffer;
5200}
5201
5202
5203// This will iterate unless the block of string data spans two 'halves' of
5204// a ConsString, in which case it will recurse. Since the block of string
5205// data to be read has a maximum size this limits the maximum recursion
5206// depth to something sane. Since C++ does not have tail call recursion
5207// elimination, the iteration must be explicit.
5208void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5209 unsigned* offset_ptr,
5210 unsigned max_chars) {
5211 ConsString* current = this;
5212 unsigned offset = *offset_ptr;
5213 int offset_correction = 0;
5214
5215 while (true) {
5216 String* left = current->first();
5217 unsigned left_length = (unsigned)left->length();
5218 if (left_length > offset &&
5219 max_chars <= left_length - offset) {
5220 // Left hand side only - iterate unless we have reached the bottom of
5221 // the cons tree.
5222 if (StringShape(left).IsCons()) {
5223 current = ConsString::cast(left);
5224 continue;
5225 } else {
5226 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5227 *offset_ptr = offset + offset_correction;
5228 return;
5229 }
5230 } else if (left_length <= offset) {
5231 // Right hand side only - iterate unless we have reached the bottom of
5232 // the cons tree.
5233 offset -= left_length;
5234 offset_correction += left_length;
5235 String* right = current->second();
5236 if (StringShape(right).IsCons()) {
5237 current = ConsString::cast(right);
5238 continue;
5239 } else {
5240 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5241 *offset_ptr = offset + offset_correction;
5242 return;
5243 }
5244 } else {
5245 // The block to be read spans two sides of the ConsString, so we recurse.
5246 // First recurse on the left.
5247 max_chars -= left_length - offset;
5248 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5249 // We may have reached the max or there may not have been enough space
5250 // in the buffer for the characters in the left hand side.
5251 if (offset == left_length) {
5252 // Recurse on the right.
5253 String* right = String::cast(current->second());
5254 offset -= left_length;
5255 offset_correction += left_length;
5256 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5257 }
5258 *offset_ptr = offset + offset_correction;
5259 return;
5260 }
5261 }
5262}
5263
5264
Steve Blocka7e24c12009-10-30 11:49:00 +00005265uint16_t ConsString::ConsStringGet(int index) {
5266 ASSERT(index >= 0 && index < this->length());
5267
5268 // Check for a flattened cons string
5269 if (second()->length() == 0) {
5270 String* left = first();
5271 return left->Get(index);
5272 }
5273
5274 String* string = String::cast(this);
5275
5276 while (true) {
5277 if (StringShape(string).IsCons()) {
5278 ConsString* cons_string = ConsString::cast(string);
5279 String* left = cons_string->first();
5280 if (left->length() > index) {
5281 string = left;
5282 } else {
5283 index -= left->length();
5284 string = cons_string->second();
5285 }
5286 } else {
5287 return string->Get(index);
5288 }
5289 }
5290
5291 UNREACHABLE();
5292 return 0;
5293}
5294
5295
5296template <typename sinkchar>
5297void String::WriteToFlat(String* src,
5298 sinkchar* sink,
5299 int f,
5300 int t) {
5301 String* source = src;
5302 int from = f;
5303 int to = t;
5304 while (true) {
5305 ASSERT(0 <= from && from <= to && to <= source->length());
5306 switch (StringShape(source).full_representation_tag()) {
5307 case kAsciiStringTag | kExternalStringTag: {
5308 CopyChars(sink,
5309 ExternalAsciiString::cast(source)->resource()->data() + from,
5310 to - from);
5311 return;
5312 }
5313 case kTwoByteStringTag | kExternalStringTag: {
5314 const uc16* data =
5315 ExternalTwoByteString::cast(source)->resource()->data();
5316 CopyChars(sink,
5317 data + from,
5318 to - from);
5319 return;
5320 }
5321 case kAsciiStringTag | kSeqStringTag: {
5322 CopyChars(sink,
5323 SeqAsciiString::cast(source)->GetChars() + from,
5324 to - from);
5325 return;
5326 }
5327 case kTwoByteStringTag | kSeqStringTag: {
5328 CopyChars(sink,
5329 SeqTwoByteString::cast(source)->GetChars() + from,
5330 to - from);
5331 return;
5332 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005333 case kAsciiStringTag | kConsStringTag:
5334 case kTwoByteStringTag | kConsStringTag: {
5335 ConsString* cons_string = ConsString::cast(source);
5336 String* first = cons_string->first();
5337 int boundary = first->length();
5338 if (to - boundary >= boundary - from) {
5339 // Right hand side is longer. Recurse over left.
5340 if (from < boundary) {
5341 WriteToFlat(first, sink, from, boundary);
5342 sink += boundary - from;
5343 from = 0;
5344 } else {
5345 from -= boundary;
5346 }
5347 to -= boundary;
5348 source = cons_string->second();
5349 } else {
5350 // Left hand side is longer. Recurse over right.
5351 if (to > boundary) {
5352 String* second = cons_string->second();
5353 WriteToFlat(second,
5354 sink + boundary - from,
5355 0,
5356 to - boundary);
5357 to = boundary;
5358 }
5359 source = first;
5360 }
5361 break;
5362 }
5363 }
5364 }
5365}
5366
5367
Steve Blocka7e24c12009-10-30 11:49:00 +00005368template <typename IteratorA, typename IteratorB>
5369static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5370 // General slow case check. We know that the ia and ib iterators
5371 // have the same length.
5372 while (ia->has_more()) {
5373 uc32 ca = ia->GetNext();
5374 uc32 cb = ib->GetNext();
5375 if (ca != cb)
5376 return false;
5377 }
5378 return true;
5379}
5380
5381
5382// Compares the contents of two strings by reading and comparing
5383// int-sized blocks of characters.
5384template <typename Char>
5385static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5386 int length = a.length();
5387 ASSERT_EQ(length, b.length());
5388 const Char* pa = a.start();
5389 const Char* pb = b.start();
5390 int i = 0;
5391#ifndef V8_HOST_CAN_READ_UNALIGNED
5392 // If this architecture isn't comfortable reading unaligned ints
5393 // then we have to check that the strings are aligned before
5394 // comparing them blockwise.
5395 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5396 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5397 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5398 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5399#endif
5400 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5401 int endpoint = length - kStepSize;
5402 // Compare blocks until we reach near the end of the string.
5403 for (; i <= endpoint; i += kStepSize) {
5404 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5405 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5406 if (wa != wb) {
5407 return false;
5408 }
5409 }
5410#ifndef V8_HOST_CAN_READ_UNALIGNED
5411 }
5412#endif
5413 // Compare the remaining characters that didn't fit into a block.
5414 for (; i < length; i++) {
5415 if (a[i] != b[i]) {
5416 return false;
5417 }
5418 }
5419 return true;
5420}
5421
5422
Steve Blocka7e24c12009-10-30 11:49:00 +00005423template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005424static inline bool CompareStringContentsPartial(Isolate* isolate,
5425 IteratorA* ia,
5426 String* b) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005427 if (b->IsFlat()) {
5428 if (b->IsAsciiRepresentation()) {
5429 VectorIterator<char> ib(b->ToAsciiVector());
5430 return CompareStringContents(ia, &ib);
5431 } else {
5432 VectorIterator<uc16> ib(b->ToUC16Vector());
5433 return CompareStringContents(ia, &ib);
5434 }
5435 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005436 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5437 return CompareStringContents(ia,
5438 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005439 }
5440}
5441
5442
Steve Blocka7e24c12009-10-30 11:49:00 +00005443bool String::SlowEquals(String* other) {
5444 // Fast check: negative check with lengths.
5445 int len = length();
5446 if (len != other->length()) return false;
5447 if (len == 0) return true;
5448
5449 // Fast check: if hash code is computed for both strings
5450 // a fast negative check can be performed.
5451 if (HasHashCode() && other->HasHashCode()) {
5452 if (Hash() != other->Hash()) return false;
5453 }
5454
Leon Clarkef7060e22010-06-03 12:02:55 +01005455 // We know the strings are both non-empty. Compare the first chars
5456 // before we try to flatten the strings.
5457 if (this->Get(0) != other->Get(0)) return false;
5458
5459 String* lhs = this->TryFlattenGetString();
5460 String* rhs = other->TryFlattenGetString();
5461
5462 if (StringShape(lhs).IsSequentialAscii() &&
5463 StringShape(rhs).IsSequentialAscii()) {
5464 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5465 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005466 return CompareRawStringContents(Vector<const char>(str1, len),
5467 Vector<const char>(str2, len));
5468 }
5469
Steve Block44f0eee2011-05-26 01:26:41 +01005470 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01005471 if (lhs->IsFlat()) {
Ben Murdochbb769b22010-08-11 14:56:33 +01005472 if (lhs->IsAsciiRepresentation()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01005473 Vector<const char> vec1 = lhs->ToAsciiVector();
5474 if (rhs->IsFlat()) {
5475 if (rhs->IsAsciiRepresentation()) {
5476 Vector<const char> vec2 = rhs->ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005477 return CompareRawStringContents(vec1, vec2);
5478 } else {
5479 VectorIterator<char> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005480 VectorIterator<uc16> ib(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005481 return CompareStringContents(&buf1, &ib);
5482 }
5483 } else {
5484 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005485 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5486 return CompareStringContents(&buf1,
5487 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005488 }
5489 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005490 Vector<const uc16> vec1 = lhs->ToUC16Vector();
5491 if (rhs->IsFlat()) {
5492 if (rhs->IsAsciiRepresentation()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005493 VectorIterator<uc16> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01005494 VectorIterator<char> ib(rhs->ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005495 return CompareStringContents(&buf1, &ib);
5496 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01005497 Vector<const uc16> vec2(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005498 return CompareRawStringContents(vec1, vec2);
5499 }
5500 } else {
5501 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005502 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5503 return CompareStringContents(&buf1,
5504 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005505 }
5506 }
5507 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005508 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5509 return CompareStringContentsPartial(isolate,
5510 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00005511 }
5512}
5513
5514
5515bool String::MarkAsUndetectable() {
5516 if (StringShape(this).IsSymbol()) return false;
5517
5518 Map* map = this->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005519 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01005520 if (map == heap->string_map()) {
5521 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005522 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01005523 } else if (map == heap->ascii_string_map()) {
5524 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00005525 return true;
5526 }
5527 // Rest cannot be marked as undetectable
5528 return false;
5529}
5530
5531
5532bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01005533 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00005534 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005535 Access<UnicodeCache::Utf8Decoder>
5536 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00005537 decoder->Reset(str.start(), str.length());
5538 int i;
5539 for (i = 0; i < slen && decoder->has_more(); i++) {
5540 uc32 r = decoder->GetNext();
5541 if (Get(i) != r) return false;
5542 }
5543 return i == slen && !decoder->has_more();
5544}
5545
5546
Steve Block9fac8402011-05-12 15:51:54 +01005547bool String::IsAsciiEqualTo(Vector<const char> str) {
5548 int slen = length();
5549 if (str.length() != slen) return false;
Ben Murdoch257744e2011-11-30 15:57:28 +00005550 if (this->IsSeqAsciiString()) {
5551 SeqAsciiString* seq = SeqAsciiString::cast(this);
5552 char* ch = seq->GetChars();
5553 for (int i = 0; i < slen; i++, ch++) {
5554 if (*ch != str[i]) return false;
5555 }
5556 } else {
5557 for (int i = 0; i < slen; i++) {
5558 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
5559 }
Steve Block9fac8402011-05-12 15:51:54 +01005560 }
5561 return true;
5562}
5563
5564
5565bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
5566 int slen = length();
5567 if (str.length() != slen) return false;
5568 for (int i = 0; i < slen; i++) {
5569 if (Get(i) != str[i]) return false;
5570 }
5571 return true;
5572}
5573
5574
Steve Blocka7e24c12009-10-30 11:49:00 +00005575uint32_t String::ComputeAndSetHash() {
5576 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005577 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005578
Steve Block6ded16b2010-05-10 14:33:55 +01005579 const int len = length();
5580
Steve Blocka7e24c12009-10-30 11:49:00 +00005581 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01005582 uint32_t field = 0;
5583 if (StringShape(this).IsSequentialAscii()) {
5584 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
5585 } else if (StringShape(this).IsSequentialTwoByte()) {
5586 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
5587 } else {
5588 StringInputBuffer buffer(this);
5589 field = ComputeHashField(&buffer, len);
5590 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005591
5592 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00005593 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00005594
5595 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005596 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00005597 uint32_t result = field >> kHashShift;
5598 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
5599 return result;
5600}
5601
5602
5603bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
5604 uint32_t* index,
5605 int length) {
5606 if (length == 0 || length > kMaxArrayIndexSize) return false;
5607 uc32 ch = buffer->GetNext();
5608
5609 // If the string begins with a '0' character, it must only consist
5610 // of it to be a legal array index.
5611 if (ch == '0') {
5612 *index = 0;
5613 return length == 1;
5614 }
5615
5616 // Convert string to uint32 array index; character by character.
5617 int d = ch - '0';
5618 if (d < 0 || d > 9) return false;
5619 uint32_t result = d;
5620 while (buffer->has_more()) {
5621 d = buffer->GetNext() - '0';
5622 if (d < 0 || d > 9) return false;
5623 // Check that the new result is below the 32 bit limit.
5624 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
5625 result = (result * 10) + d;
5626 }
5627
5628 *index = result;
5629 return true;
5630}
5631
5632
5633bool String::SlowAsArrayIndex(uint32_t* index) {
5634 if (length() <= kMaxCachedArrayIndexLength) {
5635 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00005636 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01005637 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00005638 // Isolate the array index form the full hash field.
5639 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00005640 return true;
5641 } else {
5642 StringInputBuffer buffer(this);
5643 return ComputeArrayIndex(&buffer, index, length());
5644 }
5645}
5646
5647
Iain Merrick9ac36c92010-09-13 15:29:50 +01005648uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005649 // For array indexes mix the length into the hash as an array index could
5650 // be zero.
5651 ASSERT(length > 0);
5652 ASSERT(length <= String::kMaxArrayIndexSize);
5653 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
5654 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01005655
5656 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005657 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01005658
5659 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
5660 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
5661 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005662 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00005663}
5664
5665
5666uint32_t StringHasher::GetHashField() {
5667 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00005668 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005669 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005670 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00005671 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005672 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005673 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01005674 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00005675 }
5676}
5677
5678
Steve Blockd0582a62009-12-15 09:54:21 +00005679uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
5680 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005681 StringHasher hasher(length);
5682
5683 // Very long strings have a trivial hash that doesn't inspect the
5684 // string contents.
5685 if (hasher.has_trivial_hash()) {
5686 return hasher.GetHashField();
5687 }
5688
5689 // Do the iterative array index computation as long as there is a
5690 // chance this is an array index.
5691 while (buffer->has_more() && hasher.is_array_index()) {
5692 hasher.AddCharacter(buffer->GetNext());
5693 }
5694
5695 // Process the remaining characters without updating the array
5696 // index.
5697 while (buffer->has_more()) {
5698 hasher.AddCharacterNoIndex(buffer->GetNext());
5699 }
5700
5701 return hasher.GetHashField();
5702}
5703
5704
John Reck59135872010-11-02 12:39:01 -07005705MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005706 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005707 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01005708 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00005709 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005710}
5711
5712
5713void String::PrintOn(FILE* file) {
5714 int length = this->length();
5715 for (int i = 0; i < length; i++) {
5716 fprintf(file, "%c", Get(i));
5717 }
5718}
5719
5720
5721void Map::CreateBackPointers() {
5722 DescriptorArray* descriptors = instance_descriptors();
5723 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01005724 if (descriptors->GetType(i) == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005725 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005726 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005727 // Get target.
5728 Map* target = Map::cast(descriptors->GetValue(i));
5729#ifdef DEBUG
5730 // Verify target.
5731 Object* source_prototype = prototype();
5732 Object* target_prototype = target->prototype();
5733 ASSERT(source_prototype->IsJSObject() ||
5734 source_prototype->IsMap() ||
5735 source_prototype->IsNull());
5736 ASSERT(target_prototype->IsJSObject() ||
5737 target_prototype->IsNull());
5738 ASSERT(source_prototype->IsMap() ||
5739 source_prototype == target_prototype);
5740#endif
5741 // Point target back to source. set_prototype() will not let us set
5742 // the prototype to a map, as we do here.
5743 *RawField(target, kPrototypeOffset) = this;
5744 }
5745 }
5746}
5747
5748
Steve Block44f0eee2011-05-26 01:26:41 +01005749void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005750 // Live DescriptorArray objects will be marked, so we must use
5751 // low-level accessors to get and modify their data.
5752 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00005753 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
5754 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005755 Smi* NullDescriptorDetails =
5756 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
5757 FixedArray* contents = reinterpret_cast<FixedArray*>(
5758 d->get(DescriptorArray::kContentArrayIndex));
5759 ASSERT(contents->length() >= 2);
5760 for (int i = 0; i < contents->length(); i += 2) {
5761 // If the pair (value, details) is a map transition,
5762 // check if the target is live. If not, null the descriptor.
5763 // Also drop the back pointer for that map transition, so that this
5764 // map is not reached again by following a back pointer from a
5765 // non-live object.
5766 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01005767 if (details.type() == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01005768 details.type() == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01005769 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005770 Map* target = reinterpret_cast<Map*>(contents->get(i));
5771 ASSERT(target->IsHeapObject());
5772 if (!target->IsMarked()) {
5773 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01005774 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01005775 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00005776 ASSERT(target->prototype() == this ||
5777 target->prototype() == real_prototype);
5778 // Getter prototype() is read-only, set_prototype() has side effects.
5779 *RawField(target, Map::kPrototypeOffset) = real_prototype;
5780 }
5781 }
5782 }
5783}
5784
5785
Steve Block791712a2010-08-27 10:21:07 +01005786void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
5787 // Iterate over all fields in the body but take care in dealing with
5788 // the code entry.
5789 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
5790 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
5791 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
5792}
5793
5794
Ben Murdochb0fe1622011-05-05 13:52:32 +01005795void JSFunction::MarkForLazyRecompilation() {
5796 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01005797 ASSERT(shared()->allows_lazy_compilation() ||
5798 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01005799 Builtins* builtins = GetIsolate()->builtins();
5800 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01005801}
5802
5803
5804uint32_t JSFunction::SourceHash() {
5805 uint32_t hash = 0;
5806 Object* script = shared()->script();
5807 if (!script->IsUndefined()) {
5808 Object* source = Script::cast(script)->source();
5809 if (source->IsUndefined()) hash = String::cast(source)->Hash();
5810 }
5811 hash ^= ComputeIntegerHash(shared()->start_position_and_type());
5812 hash += ComputeIntegerHash(shared()->end_position());
5813 return hash;
5814}
5815
5816
5817bool JSFunction::IsInlineable() {
5818 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005819 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005820 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005821 if (!shared_info->script()->IsScript()) return false;
5822 if (shared_info->optimization_disabled()) return false;
5823 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01005824 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
5825 // If we never ran this (unlikely) then lets try to optimize it.
5826 if (code->kind() != Code::FUNCTION) return true;
5827 return code->optimizable();
5828}
5829
5830
Steve Blocka7e24c12009-10-30 11:49:00 +00005831Object* JSFunction::SetInstancePrototype(Object* value) {
5832 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01005833 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005834 if (has_initial_map()) {
5835 initial_map()->set_prototype(value);
5836 } else {
5837 // Put the value in the initial map field until an initial map is
5838 // needed. At that point, a new initial map is created and the
5839 // prototype is put into the initial map where it belongs.
5840 set_prototype_or_initial_map(value);
5841 }
Steve Block44f0eee2011-05-26 01:26:41 +01005842 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00005843 return value;
5844}
5845
5846
John Reck59135872010-11-02 12:39:01 -07005847MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01005848 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00005849 Object* construct_prototype = value;
5850
5851 // If the value is not a JSObject, store the value in the map's
5852 // constructor field so it can be accessed. Also, set the prototype
5853 // used for constructing objects to the original object prototype.
5854 // See ECMA-262 13.2.2.
5855 if (!value->IsJSObject()) {
5856 // Copy the map so this does not affect unrelated functions.
5857 // Remove map transitions because they point to maps with a
5858 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01005859 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07005860 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005861 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07005862 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01005863 Map* new_map = Map::cast(new_object);
5864 Heap* heap = new_map->heap();
5865 set_map(new_map);
5866 new_map->set_constructor(value);
5867 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00005868 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01005869 heap->isolate()->context()->global_context()->
5870 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00005871 } else {
5872 map()->set_non_instance_prototype(false);
5873 }
5874
5875 return SetInstancePrototype(construct_prototype);
5876}
5877
5878
Steve Block6ded16b2010-05-10 14:33:55 +01005879Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01005880 Context* global_context = context()->global_context();
5881 Map* no_prototype_map = shared()->strict_mode()
5882 ? global_context->strict_mode_function_without_prototype_map()
5883 : global_context->function_without_prototype_map();
5884
5885 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01005886 // Be idempotent.
5887 return this;
5888 }
Steve Block44f0eee2011-05-26 01:26:41 +01005889
5890 ASSERT(!shared()->strict_mode() ||
5891 map() == global_context->strict_mode_function_map());
5892 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
5893
5894 set_map(no_prototype_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01005895 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01005896 return this;
5897}
5898
5899
Steve Blocka7e24c12009-10-30 11:49:00 +00005900Object* JSFunction::SetInstanceClassName(String* name) {
5901 shared()->set_instance_class_name(name);
5902 return this;
5903}
5904
5905
Ben Murdochb0fe1622011-05-05 13:52:32 +01005906void JSFunction::PrintName(FILE* out) {
5907 SmartPointer<char> name = shared()->DebugName()->ToCString();
5908 PrintF(out, "%s", *name);
5909}
5910
5911
Steve Blocka7e24c12009-10-30 11:49:00 +00005912Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
5913 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
5914}
5915
5916
Steve Block44f0eee2011-05-26 01:26:41 +01005917MaybeObject* Oddball::Initialize(const char* to_string,
5918 Object* to_number,
5919 byte kind) {
John Reck59135872010-11-02 12:39:01 -07005920 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01005921 { MaybeObject* maybe_symbol =
5922 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07005923 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
5924 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005925 set_to_string(String::cast(symbol));
5926 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01005927 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00005928 return this;
5929}
5930
5931
Ben Murdochf87a2032010-10-22 12:50:53 +01005932String* SharedFunctionInfo::DebugName() {
5933 Object* n = name();
5934 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
5935 return String::cast(n);
5936}
5937
5938
Steve Blocka7e24c12009-10-30 11:49:00 +00005939bool SharedFunctionInfo::HasSourceCode() {
5940 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01005941 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00005942}
5943
5944
5945Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01005946 Isolate* isolate = GetIsolate();
5947 if (!HasSourceCode()) return isolate->heap()->undefined_value();
5948 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00005949 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01005950 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00005951 start_position(), end_position());
5952}
5953
5954
Ben Murdochb0fe1622011-05-05 13:52:32 +01005955int SharedFunctionInfo::SourceSize() {
5956 return end_position() - start_position();
5957}
5958
5959
Steve Blocka7e24c12009-10-30 11:49:00 +00005960int SharedFunctionInfo::CalculateInstanceSize() {
5961 int instance_size =
5962 JSObject::kHeaderSize +
5963 expected_nof_properties() * kPointerSize;
5964 if (instance_size > JSObject::kMaxInstanceSize) {
5965 instance_size = JSObject::kMaxInstanceSize;
5966 }
5967 return instance_size;
5968}
5969
5970
5971int SharedFunctionInfo::CalculateInObjectProperties() {
5972 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
5973}
5974
5975
Andrei Popescu402d9372010-02-26 13:31:12 +00005976bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
5977 // Check the basic conditions for generating inline constructor code.
5978 if (!FLAG_inline_new
5979 || !has_only_simple_this_property_assignments()
5980 || this_property_assignments_count() == 0) {
5981 return false;
5982 }
5983
5984 // If the prototype is null inline constructors cause no problems.
5985 if (!prototype->IsJSObject()) {
5986 ASSERT(prototype->IsNull());
5987 return true;
5988 }
5989
Ben Murdoch8b112d22011-06-08 16:22:53 +01005990 Heap* heap = GetHeap();
5991
Andrei Popescu402d9372010-02-26 13:31:12 +00005992 // Traverse the proposed prototype chain looking for setters for properties of
5993 // the same names as are set by the inline constructor.
5994 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01005995 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00005996 obj = obj->GetPrototype()) {
5997 JSObject* js_object = JSObject::cast(obj);
5998 for (int i = 0; i < this_property_assignments_count(); i++) {
5999 LookupResult result;
6000 String* name = GetThisPropertyAssignmentName(i);
6001 js_object->LocalLookupRealNamedProperty(name, &result);
6002 if (result.IsProperty() && result.type() == CALLBACKS) {
6003 return false;
6004 }
6005 }
6006 }
6007
6008 return true;
6009}
6010
6011
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006012void SharedFunctionInfo::ForbidInlineConstructor() {
6013 set_compiler_hints(BooleanBit::set(compiler_hints(),
6014 kHasOnlySimpleThisPropertyAssignments,
6015 false));
6016}
6017
6018
Steve Blocka7e24c12009-10-30 11:49:00 +00006019void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00006020 bool only_simple_this_property_assignments,
6021 FixedArray* assignments) {
6022 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006023 kHasOnlySimpleThisPropertyAssignments,
6024 only_simple_this_property_assignments));
6025 set_this_property_assignments(assignments);
6026 set_this_property_assignments_count(assignments->length() / 3);
6027}
6028
6029
6030void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01006031 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006032 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006033 kHasOnlySimpleThisPropertyAssignments,
6034 false));
Steve Block44f0eee2011-05-26 01:26:41 +01006035 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006036 set_this_property_assignments_count(0);
6037}
6038
6039
6040String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6041 Object* obj = this_property_assignments();
6042 ASSERT(obj->IsFixedArray());
6043 ASSERT(index < this_property_assignments_count());
6044 obj = FixedArray::cast(obj)->get(index * 3);
6045 ASSERT(obj->IsString());
6046 return String::cast(obj);
6047}
6048
6049
6050bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6051 Object* obj = this_property_assignments();
6052 ASSERT(obj->IsFixedArray());
6053 ASSERT(index < this_property_assignments_count());
6054 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6055 return Smi::cast(obj)->value() != -1;
6056}
6057
6058
6059int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6060 ASSERT(IsThisPropertyAssignmentArgument(index));
6061 Object* obj =
6062 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6063 return Smi::cast(obj)->value();
6064}
6065
6066
6067Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6068 ASSERT(!IsThisPropertyAssignmentArgument(index));
6069 Object* obj =
6070 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6071 return obj;
6072}
6073
6074
Steve Blocka7e24c12009-10-30 11:49:00 +00006075// Support function for printing the source code to a StringStream
6076// without any allocation in the heap.
6077void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6078 int max_length) {
6079 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006080 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006081 accumulator->Add("<No Source>");
6082 return;
6083 }
6084
Steve Blockd0582a62009-12-15 09:54:21 +00006085 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00006086 // Don't use String::cast because we don't want more assertion errors while
6087 // we are already creating a stack dump.
6088 String* script_source =
6089 reinterpret_cast<String*>(Script::cast(script())->source());
6090
6091 if (!script_source->LooksValid()) {
6092 accumulator->Add("<Invalid Source>");
6093 return;
6094 }
6095
6096 if (!is_toplevel()) {
6097 accumulator->Add("function ");
6098 Object* name = this->name();
6099 if (name->IsString() && String::cast(name)->length() > 0) {
6100 accumulator->PrintName(name);
6101 }
6102 }
6103
6104 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006105 if (len <= max_length || max_length < 0) {
6106 accumulator->Put(script_source, start_position(), end_position());
6107 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006108 accumulator->Put(script_source,
6109 start_position(),
6110 start_position() + max_length);
6111 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006112 }
6113}
6114
6115
Ben Murdochb0fe1622011-05-05 13:52:32 +01006116static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6117 if (code->instruction_size() != recompiled->instruction_size()) return false;
6118 ByteArray* code_relocation = code->relocation_info();
6119 ByteArray* recompiled_relocation = recompiled->relocation_info();
6120 int length = code_relocation->length();
6121 if (length != recompiled_relocation->length()) return false;
6122 int compare = memcmp(code_relocation->GetDataStartAddress(),
6123 recompiled_relocation->GetDataStartAddress(),
6124 length);
6125 return compare == 0;
6126}
6127
6128
6129void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6130 ASSERT(!has_deoptimization_support());
6131 AssertNoAllocation no_allocation;
6132 Code* code = this->code();
6133 if (IsCodeEquivalent(code, recompiled)) {
6134 // Copy the deoptimization data from the recompiled code.
6135 code->set_deoptimization_data(recompiled->deoptimization_data());
6136 code->set_has_deoptimization_support(true);
6137 } else {
6138 // TODO(3025757): In case the recompiled isn't equivalent to the
6139 // old code, we have to replace it. We should try to avoid this
6140 // altogether because it flushes valuable type feedback by
6141 // effectively resetting all IC state.
6142 set_code(recompiled);
6143 }
6144 ASSERT(has_deoptimization_support());
6145}
6146
6147
Ben Murdoch257744e2011-11-30 15:57:28 +00006148void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6149 // Disable optimization for the shared function info and mark the
6150 // code as non-optimizable. The marker on the shared function info
6151 // is there because we flush non-optimized code thereby loosing the
6152 // non-optimizable information for the code. When the code is
6153 // regenerated and set on the shared function info it is marked as
6154 // non-optimizable if optimization is disabled for the shared
6155 // function info.
6156 set_optimization_disabled(true);
6157 // Code should be the lazy compilation stub or else unoptimized. If the
6158 // latter, disable optimization for the code too.
6159 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6160 if (code()->kind() == Code::FUNCTION) {
6161 code()->set_optimizable(false);
6162 }
6163 if (FLAG_trace_opt) {
6164 PrintF("[disabled optimization for: ");
6165 function->PrintName();
6166 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6167 }
6168}
6169
6170
Ben Murdochb0fe1622011-05-05 13:52:32 +01006171bool SharedFunctionInfo::VerifyBailoutId(int id) {
6172 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6173 // we are always bailing out on ARM.
6174
6175 ASSERT(id != AstNode::kNoNumber);
6176 Code* unoptimized = code();
6177 DeoptimizationOutputData* data =
6178 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6179 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6180 USE(ignore);
6181 return true; // Return true if there was no ASSERT.
6182}
6183
6184
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006185void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6186 ASSERT(!IsInobjectSlackTrackingInProgress());
6187
6188 // Only initiate the tracking the first time.
6189 if (live_objects_may_exist()) return;
6190 set_live_objects_may_exist(true);
6191
6192 // No tracking during the snapshot construction phase.
6193 if (Serializer::enabled()) return;
6194
6195 if (map->unused_property_fields() == 0) return;
6196
6197 // Nonzero counter is a leftover from the previous attempt interrupted
6198 // by GC, keep it.
6199 if (construction_count() == 0) {
6200 set_construction_count(kGenerousAllocationCount);
6201 }
6202 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006203 Builtins* builtins = map->heap()->isolate()->builtins();
6204 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006205 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006206 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006207}
6208
6209
6210// Called from GC, hence reinterpret_cast and unchecked accessors.
6211void SharedFunctionInfo::DetachInitialMap() {
6212 Map* map = reinterpret_cast<Map*>(initial_map());
6213
6214 // Make the map remember to restore the link if it survives the GC.
6215 map->set_bit_field2(
6216 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6217
6218 // Undo state changes made by StartInobjectTracking (except the
6219 // construction_count). This way if the initial map does not survive the GC
6220 // then StartInobjectTracking will be called again the next time the
6221 // constructor is called. The countdown will continue and (possibly after
6222 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006223 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6224 Builtins* builtins = map->heap()->isolate()->builtins();
6225 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006226 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006227 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006228 // It is safe to clear the flag: it will be set again if the map is live.
6229 set_live_objects_may_exist(false);
6230}
6231
6232
6233// Called from GC, hence reinterpret_cast and unchecked accessors.
6234void SharedFunctionInfo::AttachInitialMap(Map* map) {
6235 map->set_bit_field2(
6236 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6237
6238 // Resume inobject slack tracking.
6239 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006240 Builtins* builtins = map->heap()->isolate()->builtins();
6241 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006242 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006243 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006244 // The map survived the gc, so there may be objects referencing it.
6245 set_live_objects_may_exist(true);
6246}
6247
6248
6249static void GetMinInobjectSlack(Map* map, void* data) {
6250 int slack = map->unused_property_fields();
6251 if (*reinterpret_cast<int*>(data) > slack) {
6252 *reinterpret_cast<int*>(data) = slack;
6253 }
6254}
6255
6256
6257static void ShrinkInstanceSize(Map* map, void* data) {
6258 int slack = *reinterpret_cast<int*>(data);
6259 map->set_inobject_properties(map->inobject_properties() - slack);
6260 map->set_unused_property_fields(map->unused_property_fields() - slack);
6261 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6262
6263 // Visitor id might depend on the instance size, recalculate it.
6264 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6265}
6266
6267
6268void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6269 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6270 Map* map = Map::cast(initial_map());
6271
Steve Block44f0eee2011-05-26 01:26:41 +01006272 Heap* heap = map->heap();
6273 set_initial_map(heap->undefined_value());
6274 Builtins* builtins = heap->isolate()->builtins();
6275 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006276 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006277 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006278
6279 int slack = map->unused_property_fields();
6280 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6281 if (slack != 0) {
6282 // Resize the initial map and all maps in its transition tree.
6283 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
6284 // Give the correct expected_nof_properties to initial maps created later.
6285 ASSERT(expected_nof_properties() >= slack);
6286 set_expected_nof_properties(expected_nof_properties() - slack);
6287 }
6288}
6289
6290
Steve Blocka7e24c12009-10-30 11:49:00 +00006291void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6292 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6293 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6294 Object* old_target = target;
6295 VisitPointer(&target);
6296 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6297}
6298
6299
Steve Block791712a2010-08-27 10:21:07 +01006300void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6301 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6302 Object* old_code = code;
6303 VisitPointer(&code);
6304 if (code != old_code) {
6305 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6306 }
6307}
6308
6309
Ben Murdochb0fe1622011-05-05 13:52:32 +01006310void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6311 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6312 Object* cell = rinfo->target_cell();
6313 Object* old_cell = cell;
6314 VisitPointer(&cell);
6315 if (cell != old_cell) {
6316 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6317 }
6318}
6319
6320
Steve Blocka7e24c12009-10-30 11:49:00 +00006321void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006322 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6323 rinfo->IsPatchedReturnSequence()) ||
6324 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6325 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006326 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6327 Object* old_target = target;
6328 VisitPointer(&target);
6329 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6330}
6331
6332
Ben Murdochb0fe1622011-05-05 13:52:32 +01006333void Code::InvalidateRelocation() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006334 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006335}
6336
6337
Steve Blockd0582a62009-12-15 09:54:21 +00006338void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006339 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6340 it.rinfo()->apply(delta);
6341 }
6342 CPU::FlushICache(instruction_start(), instruction_size());
6343}
6344
6345
6346void Code::CopyFrom(const CodeDesc& desc) {
6347 // copy code
6348 memmove(instruction_start(), desc.buffer, desc.instr_size);
6349
Steve Blocka7e24c12009-10-30 11:49:00 +00006350 // copy reloc info
6351 memmove(relocation_start(),
6352 desc.buffer + desc.buffer_size - desc.reloc_size,
6353 desc.reloc_size);
6354
6355 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006356 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006357 int mode_mask = RelocInfo::kCodeTargetMask |
6358 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006359 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006360 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006361 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006362 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6363 RelocInfo::Mode mode = it.rinfo()->rmode();
6364 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006365 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006366 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006367 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006368 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006369 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006370 } else if (RelocInfo::IsCodeTarget(mode)) {
6371 // rewrite code handles in inline cache targets to direct
6372 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006373 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006374 Code* code = Code::cast(*p);
6375 it.rinfo()->set_target_address(code->instruction_start());
6376 } else {
6377 it.rinfo()->apply(delta);
6378 }
6379 }
6380 CPU::FlushICache(instruction_start(), instruction_size());
6381}
6382
6383
6384// Locate the source position which is closest to the address in the code. This
6385// is using the source position information embedded in the relocation info.
6386// The position returned is relative to the beginning of the script where the
6387// source for this function is found.
6388int Code::SourcePosition(Address pc) {
6389 int distance = kMaxInt;
6390 int position = RelocInfo::kNoPosition; // Initially no position found.
6391 // Run through all the relocation info to find the best matching source
6392 // position. All the code needs to be considered as the sequence of the
6393 // instructions in the code does not necessarily follow the same order as the
6394 // source.
6395 RelocIterator it(this, RelocInfo::kPositionMask);
6396 while (!it.done()) {
6397 // Only look at positions after the current pc.
6398 if (it.rinfo()->pc() < pc) {
6399 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006400
6401 int dist = static_cast<int>(pc - it.rinfo()->pc());
6402 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006403 // If this position is closer than the current candidate or if it has the
6404 // same distance as the current candidate and the position is higher then
6405 // this position is the new candidate.
6406 if ((dist < distance) ||
6407 (dist == distance && pos > position)) {
6408 position = pos;
6409 distance = dist;
6410 }
6411 }
6412 it.next();
6413 }
6414 return position;
6415}
6416
6417
6418// Same as Code::SourcePosition above except it only looks for statement
6419// positions.
6420int Code::SourceStatementPosition(Address pc) {
6421 // First find the position as close as possible using all position
6422 // information.
6423 int position = SourcePosition(pc);
6424 // Now find the closest statement position before the position.
6425 int statement_position = 0;
6426 RelocIterator it(this, RelocInfo::kPositionMask);
6427 while (!it.done()) {
6428 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006429 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006430 if (statement_position < p && p <= position) {
6431 statement_position = p;
6432 }
6433 }
6434 it.next();
6435 }
6436 return statement_position;
6437}
6438
6439
Ben Murdochb8e0da22011-05-16 14:20:40 +01006440SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006441 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006442 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006443}
6444
6445
6446void Code::SetNoStackCheckTable() {
6447 // Indicate the absence of a stack-check table by a table start after the
6448 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006449 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006450}
6451
6452
6453Map* Code::FindFirstMap() {
6454 ASSERT(is_inline_cache_stub());
6455 AssertNoAllocation no_allocation;
6456 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6457 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6458 RelocInfo* info = it.rinfo();
6459 Object* object = info->target_object();
6460 if (object->IsMap()) return Map::cast(object);
6461 }
6462 return NULL;
6463}
6464
6465
Steve Blocka7e24c12009-10-30 11:49:00 +00006466#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006467
6468#ifdef OBJECT_PRINT
6469
6470void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6471 disasm::NameConverter converter;
6472 int deopt_count = DeoptCount();
6473 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6474 if (0 == deopt_count) return;
6475
6476 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
6477 for (int i = 0; i < deopt_count; i++) {
6478 int command_count = 0;
6479 PrintF(out, "%6d %6d %6d",
6480 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
6481 int translation_index = TranslationIndex(i)->value();
6482 TranslationIterator iterator(TranslationByteArray(), translation_index);
6483 Translation::Opcode opcode =
6484 static_cast<Translation::Opcode>(iterator.Next());
6485 ASSERT(Translation::BEGIN == opcode);
6486 int frame_count = iterator.Next();
6487 if (FLAG_print_code_verbose) {
6488 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6489 frame_count);
6490 }
6491
6492 for (int i = 0; i < frame_count; ++i) {
6493 opcode = static_cast<Translation::Opcode>(iterator.Next());
6494 ASSERT(Translation::FRAME == opcode);
6495 int ast_id = iterator.Next();
6496 int function_id = iterator.Next();
6497 JSFunction* function =
6498 JSFunction::cast(LiteralArray()->get(function_id));
6499 unsigned height = iterator.Next();
6500 if (FLAG_print_code_verbose) {
6501 PrintF(out, "%24s %s {ast_id=%d, function=",
6502 "", Translation::StringFor(opcode), ast_id);
6503 function->PrintName(out);
6504 PrintF(out, ", height=%u}\n", height);
6505 }
6506
6507 // Size of translation is height plus all incoming arguments including
6508 // receiver.
6509 int size = height + function->shared()->formal_parameter_count() + 1;
6510 command_count += size;
6511 for (int j = 0; j < size; ++j) {
6512 opcode = static_cast<Translation::Opcode>(iterator.Next());
6513 if (FLAG_print_code_verbose) {
6514 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
6515 }
6516
6517 if (opcode == Translation::DUPLICATE) {
6518 opcode = static_cast<Translation::Opcode>(iterator.Next());
6519 if (FLAG_print_code_verbose) {
6520 PrintF(out, "%s ", Translation::StringFor(opcode));
6521 }
6522 --j; // Two commands share the same frame index.
6523 }
6524
6525 switch (opcode) {
6526 case Translation::BEGIN:
6527 case Translation::FRAME:
6528 case Translation::DUPLICATE:
6529 UNREACHABLE();
6530 break;
6531
6532 case Translation::REGISTER: {
6533 int reg_code = iterator.Next();
6534 if (FLAG_print_code_verbose) {
6535 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6536 }
6537 break;
6538 }
6539
6540 case Translation::INT32_REGISTER: {
6541 int reg_code = iterator.Next();
6542 if (FLAG_print_code_verbose) {
6543 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
6544 }
6545 break;
6546 }
6547
6548 case Translation::DOUBLE_REGISTER: {
6549 int reg_code = iterator.Next();
6550 if (FLAG_print_code_verbose) {
6551 PrintF(out, "{input=%s}",
6552 DoubleRegister::AllocationIndexToString(reg_code));
6553 }
6554 break;
6555 }
6556
6557 case Translation::STACK_SLOT: {
6558 int input_slot_index = iterator.Next();
6559 if (FLAG_print_code_verbose) {
6560 PrintF(out, "{input=%d}", input_slot_index);
6561 }
6562 break;
6563 }
6564
6565 case Translation::INT32_STACK_SLOT: {
6566 int input_slot_index = iterator.Next();
6567 if (FLAG_print_code_verbose) {
6568 PrintF(out, "{input=%d}", input_slot_index);
6569 }
6570 break;
6571 }
6572
6573 case Translation::DOUBLE_STACK_SLOT: {
6574 int input_slot_index = iterator.Next();
6575 if (FLAG_print_code_verbose) {
6576 PrintF(out, "{input=%d}", input_slot_index);
6577 }
6578 break;
6579 }
6580
6581 case Translation::LITERAL: {
6582 unsigned literal_index = iterator.Next();
6583 if (FLAG_print_code_verbose) {
6584 PrintF(out, "{literal_id=%u}", literal_index);
6585 }
6586 break;
6587 }
6588
6589 case Translation::ARGUMENTS_OBJECT:
6590 break;
6591 }
6592 if (FLAG_print_code_verbose) PrintF(out, "\n");
6593 }
6594 }
6595 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
6596 }
6597}
6598
6599
6600void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
6601 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
6602 this->DeoptPoints());
6603 if (this->DeoptPoints() == 0) return;
6604
6605 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
6606 for (int i = 0; i < this->DeoptPoints(); i++) {
6607 int pc_and_state = this->PcAndState(i)->value();
6608 PrintF("%6d %8d %s\n",
6609 this->AstId(i)->value(),
6610 FullCodeGenerator::PcField::decode(pc_and_state),
6611 FullCodeGenerator::State2String(
6612 FullCodeGenerator::StateField::decode(pc_and_state)));
6613 }
6614}
6615
6616#endif
6617
6618
Steve Blocka7e24c12009-10-30 11:49:00 +00006619// Identify kind of code.
6620const char* Code::Kind2String(Kind kind) {
6621 switch (kind) {
6622 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006623 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006624 case STUB: return "STUB";
6625 case BUILTIN: return "BUILTIN";
6626 case LOAD_IC: return "LOAD_IC";
6627 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
6628 case STORE_IC: return "STORE_IC";
6629 case KEYED_STORE_IC: return "KEYED_STORE_IC";
6630 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006631 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00006632 case UNARY_OP_IC: return "UNARY_OP_IC";
6633 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01006634 case COMPARE_IC: return "COMPARE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00006635 }
6636 UNREACHABLE();
6637 return NULL;
6638}
6639
6640
6641const char* Code::ICState2String(InlineCacheState state) {
6642 switch (state) {
6643 case UNINITIALIZED: return "UNINITIALIZED";
6644 case PREMONOMORPHIC: return "PREMONOMORPHIC";
6645 case MONOMORPHIC: return "MONOMORPHIC";
6646 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
6647 case MEGAMORPHIC: return "MEGAMORPHIC";
6648 case DEBUG_BREAK: return "DEBUG_BREAK";
6649 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
6650 }
6651 UNREACHABLE();
6652 return NULL;
6653}
6654
6655
6656const char* Code::PropertyType2String(PropertyType type) {
6657 switch (type) {
6658 case NORMAL: return "NORMAL";
6659 case FIELD: return "FIELD";
6660 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
6661 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00006662 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00006663 case INTERCEPTOR: return "INTERCEPTOR";
6664 case MAP_TRANSITION: return "MAP_TRANSITION";
Steve Block44f0eee2011-05-26 01:26:41 +01006665 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00006666 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
6667 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
6668 }
6669 UNREACHABLE();
6670 return NULL;
6671}
6672
Ben Murdochb0fe1622011-05-05 13:52:32 +01006673
Steve Block1e0659c2011-05-24 12:43:12 +01006674void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
6675 const char* name = NULL;
6676 switch (kind) {
6677 case CALL_IC:
6678 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
6679 name = "STRING_INDEX_OUT_OF_BOUNDS";
6680 }
6681 break;
6682 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006683 case KEYED_STORE_IC:
6684 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01006685 name = "STRICT";
6686 }
6687 break;
6688 default:
6689 break;
6690 }
6691 if (name != NULL) {
6692 PrintF(out, "extra_ic_state = %s\n", name);
6693 } else {
6694 PrintF(out, "etra_ic_state = %d\n", extra);
6695 }
6696}
6697
6698
Ben Murdochb0fe1622011-05-05 13:52:32 +01006699void Code::Disassemble(const char* name, FILE* out) {
6700 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006701 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006702 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01006703 PrintExtraICState(out, kind(), extra_ic_state());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006704 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
Steve Blocka7e24c12009-10-30 11:49:00 +00006705 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006706 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006707 }
6708 }
6709 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006710 PrintF(out, "name = %s\n", name);
6711 }
6712 if (kind() == OPTIMIZED_FUNCTION) {
6713 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00006714 }
6715
Ben Murdochb0fe1622011-05-05 13:52:32 +01006716 PrintF(out, "Instructions (size = %d)\n", instruction_size());
6717 Disassembler::Decode(out, this);
6718 PrintF(out, "\n");
6719
6720#ifdef DEBUG
6721 if (kind() == FUNCTION) {
6722 DeoptimizationOutputData* data =
6723 DeoptimizationOutputData::cast(this->deoptimization_data());
6724 data->DeoptimizationOutputDataPrint(out);
6725 } else if (kind() == OPTIMIZED_FUNCTION) {
6726 DeoptimizationInputData* data =
6727 DeoptimizationInputData::cast(this->deoptimization_data());
6728 data->DeoptimizationInputDataPrint(out);
6729 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006730 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006731#endif
6732
6733 if (kind() == OPTIMIZED_FUNCTION) {
6734 SafepointTable table(this);
6735 PrintF(out, "Safepoints (size = %u)\n", table.size());
6736 for (unsigned i = 0; i < table.length(); i++) {
6737 unsigned pc_offset = table.GetPcOffset(i);
6738 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
6739 table.PrintEntry(i);
6740 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01006741 SafepointEntry entry = table.GetEntry(i);
6742 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
6743 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006744 } else {
6745 PrintF(out, " <none>");
6746 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01006747 if (entry.argument_count() > 0) {
6748 PrintF(out, " argc: %d", entry.argument_count());
6749 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01006750 PrintF(out, "\n");
6751 }
6752 PrintF(out, "\n");
6753 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01006754 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006755 // If there is no stack check table, the "table start" will at or after
6756 // (due to alignment) the end of the instruction stream.
6757 if (static_cast<int>(offset) < instruction_size()) {
6758 unsigned* address =
6759 reinterpret_cast<unsigned*>(instruction_start() + offset);
6760 unsigned length = address[0];
6761 PrintF(out, "Stack checks (size = %u)\n", length);
6762 PrintF(out, "ast_id pc_offset\n");
6763 for (unsigned i = 0; i < length; ++i) {
6764 unsigned index = (2 * i) + 1;
6765 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
6766 }
6767 PrintF(out, "\n");
6768 }
6769 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006770
6771 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006772 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
6773 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006774}
6775#endif // ENABLE_DISASSEMBLER
6776
6777
John Reck59135872010-11-02 12:39:01 -07006778MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
6779 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01006780 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00006781 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006782 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01006783
John Reck59135872010-11-02 12:39:01 -07006784 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006785 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006786 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6787 }
Steve Block8defd9f2010-07-08 12:39:36 +01006788 FixedArray* elems = FixedArray::cast(obj);
6789
John Reck59135872010-11-02 12:39:01 -07006790 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
6791 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6792 }
Steve Block8defd9f2010-07-08 12:39:36 +01006793 Map* new_map = Map::cast(obj);
6794
Leon Clarke4515c472010-02-03 11:58:03 +00006795 AssertNoAllocation no_gc;
6796 WriteBarrierMode mode = elems->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00006797 switch (GetElementsKind()) {
6798 case FAST_ELEMENTS: {
6799 FixedArray* old_elements = FixedArray::cast(elements());
6800 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
6801 // Fill out the new array with this content and array holes.
6802 for (uint32_t i = 0; i < old_length; i++) {
6803 elems->set(i, old_elements->get(i), mode);
6804 }
6805 break;
6806 }
6807 case DICTIONARY_ELEMENTS: {
6808 NumberDictionary* dictionary = NumberDictionary::cast(elements());
6809 for (int i = 0; i < dictionary->Capacity(); i++) {
6810 Object* key = dictionary->KeyAt(i);
6811 if (key->IsNumber()) {
6812 uint32_t entry = static_cast<uint32_t>(key->Number());
6813 elems->set(entry, dictionary->ValueAt(i), mode);
6814 }
6815 }
6816 break;
6817 }
6818 default:
6819 UNREACHABLE();
6820 break;
6821 }
Steve Block8defd9f2010-07-08 12:39:36 +01006822
6823 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00006824 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01006825
6826 if (IsJSArray()) {
6827 JSArray::cast(this)->set_length(Smi::FromInt(length));
6828 }
6829
6830 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00006831}
6832
6833
John Reck59135872010-11-02 12:39:01 -07006834MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006835 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01006836 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00006837
6838 uint32_t new_length = static_cast<uint32_t>(len->Number());
6839
6840 switch (GetElementsKind()) {
6841 case FAST_ELEMENTS: {
6842 // Make sure we never try to shrink dense arrays into sparse arrays.
6843 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
6844 new_length);
John Reck59135872010-11-02 12:39:01 -07006845 Object* obj;
6846 { MaybeObject* maybe_obj = NormalizeElements();
6847 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6848 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006849
6850 // Update length for JSArrays.
6851 if (IsJSArray()) JSArray::cast(this)->set_length(len);
6852 break;
6853 }
6854 case DICTIONARY_ELEMENTS: {
6855 if (IsJSArray()) {
6856 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01006857 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00006858 element_dictionary()->RemoveNumberEntries(new_length, old_length),
6859 JSArray::cast(this)->set_length(len);
6860 }
6861 break;
6862 }
6863 default:
6864 UNREACHABLE();
6865 break;
6866 }
6867 return this;
6868}
6869
6870
John Reck59135872010-11-02 12:39:01 -07006871MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01006872 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006873 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00006874 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00006875 FixedArray* new_elements;
6876 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01006877 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00006878 } else {
John Reck59135872010-11-02 12:39:01 -07006879 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01006880 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07006881 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6882 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006883 new_elements = FixedArray::cast(obj);
6884 }
6885 set_elements(new_elements);
6886 return this;
6887}
6888
6889
6890void JSArray::Expand(int required_size) {
6891 Handle<JSArray> self(this);
6892 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
6893 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00006894 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01006895 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00006896 // Can't use this any more now because we may have had a GC!
6897 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
6898 self->SetContent(*new_backing);
6899}
6900
6901
Steve Block44f0eee2011-05-26 01:26:41 +01006902static Failure* ArrayLengthRangeError(Heap* heap) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006903 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01006904 return heap->isolate()->Throw(
6905 *FACTORY->NewRangeError("invalid_array_length",
6906 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00006907}
6908
6909
John Reck59135872010-11-02 12:39:01 -07006910MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00006911 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01006912 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00006913
John Reck59135872010-11-02 12:39:01 -07006914 MaybeObject* maybe_smi_length = len->ToSmi();
6915 Object* smi_length = Smi::FromInt(0);
6916 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01006917 const int value = Smi::cast(smi_length)->value();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006918 if (value < 0) return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00006919 switch (GetElementsKind()) {
6920 case FAST_ELEMENTS: {
6921 int old_capacity = FixedArray::cast(elements())->length();
6922 if (value <= old_capacity) {
6923 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07006924 Object* obj;
6925 { MaybeObject* maybe_obj = EnsureWritableFastElements();
6926 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6927 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006928 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
6929 // NOTE: We may be able to optimize this by removing the
6930 // last part of the elements backing storage array and
6931 // setting the capacity to the new size.
6932 for (int i = value; i < old_length; i++) {
6933 FixedArray::cast(elements())->set_the_hole(i);
6934 }
Leon Clarke4515c472010-02-03 11:58:03 +00006935 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006936 }
6937 return this;
6938 }
6939 int min = NewElementsCapacity(old_capacity);
6940 int new_capacity = value > min ? value : min;
6941 if (new_capacity <= kMaxFastElementsLength ||
6942 !ShouldConvertToSlowElements(new_capacity)) {
John Reck59135872010-11-02 12:39:01 -07006943 Object* obj;
6944 { MaybeObject* maybe_obj =
6945 SetFastElementsCapacityAndLength(new_capacity, value);
6946 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6947 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006948 return this;
6949 }
6950 break;
6951 }
6952 case DICTIONARY_ELEMENTS: {
6953 if (IsJSArray()) {
6954 if (value == 0) {
6955 // If the length of a slow array is reset to zero, we clear
6956 // the array and flush backing storage. This has the added
6957 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07006958 Object* obj;
6959 { MaybeObject* maybe_obj = ResetElements();
6960 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6961 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006962 } else {
6963 // Remove deleted elements.
6964 uint32_t old_length =
6965 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
6966 element_dictionary()->RemoveNumberEntries(value, old_length);
6967 }
Leon Clarke4515c472010-02-03 11:58:03 +00006968 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00006969 }
6970 return this;
6971 }
6972 default:
6973 UNREACHABLE();
6974 break;
6975 }
6976 }
6977
6978 // General slow case.
6979 if (len->IsNumber()) {
6980 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006981 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006982 return SetSlowElements(len);
6983 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006984 return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00006985 }
6986 }
6987
6988 // len is not a number so make the array size one and
6989 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07006990 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01006991 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07006992 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6993 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006994 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00006995 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00006996 set_elements(FixedArray::cast(obj));
6997 return this;
6998}
6999
7000
Steve Block053d10c2011-06-13 19:13:29 +01007001Object* Map::GetPrototypeTransition(Object* prototype) {
7002 FixedArray* cache = prototype_transitions();
7003 int capacity = cache->length();
7004 if (capacity == 0) return NULL;
7005 int finger = Smi::cast(cache->get(0))->value();
7006 for (int i = 1; i < finger; i += 2) {
7007 if (cache->get(i) == prototype) return cache->get(i + 1);
7008 }
7009 return NULL;
7010}
7011
7012
7013MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
7014 // Don't cache prototype transition if this map is shared.
7015 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7016
7017 FixedArray* cache = prototype_transitions();
7018
7019 int capacity = cache->length();
7020
7021 int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value();
7022
7023 if (finger >= capacity) {
7024 if (capacity > kMaxCachedPrototypeTransitions) return this;
7025
7026 FixedArray* new_cache;
7027 { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1);
7028 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7029 }
7030
7031 for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i));
7032 cache = new_cache;
7033 set_prototype_transitions(cache);
7034 }
7035
7036 cache->set(finger, prototype);
7037 cache->set(finger + 1, map);
7038 cache->set(0, Smi::FromInt(finger + 2));
7039
7040 return cache;
7041}
7042
7043
John Reck59135872010-11-02 12:39:01 -07007044MaybeObject* JSObject::SetPrototype(Object* value,
7045 bool skip_hidden_prototypes) {
Steve Block44f0eee2011-05-26 01:26:41 +01007046 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00007047 // Silently ignore the change if value is not a JSObject or null.
7048 // SpiderMonkey behaves this way.
7049 if (!value->IsJSObject() && !value->IsNull()) return value;
7050
Ben Murdoch8b112d22011-06-08 16:22:53 +01007051 // From 8.6.2 Object Internal Methods
7052 // ...
7053 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7054 // [[Prototype]] internal properties of the object may not be modified.
7055 // ...
7056 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7057 // or [[Extensible]] must not violate the invariants defined in the preceding
7058 // paragraph.
7059 if (!this->map()->is_extensible()) {
7060 HandleScope scope;
7061 Handle<Object> handle(this, heap->isolate());
7062 return heap->isolate()->Throw(
7063 *FACTORY->NewTypeError("non_extensible_proto",
7064 HandleVector<Object>(&handle, 1)));
7065 }
7066
Andrei Popescu402d9372010-02-26 13:31:12 +00007067 // Before we can set the prototype we need to be sure
7068 // prototype cycles are prevented.
7069 // It is sufficient to validate that the receiver is not in the new prototype
7070 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01007071 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007072 if (JSObject::cast(pt) == this) {
7073 // Cycle detected.
7074 HandleScope scope;
Steve Block44f0eee2011-05-26 01:26:41 +01007075 return heap->isolate()->Throw(
7076 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00007077 }
7078 }
7079
7080 JSObject* real_receiver = this;
7081
7082 if (skip_hidden_prototypes) {
7083 // Find the first object in the chain whose prototype object is not
7084 // hidden and set the new prototype on that object.
7085 Object* current_proto = real_receiver->GetPrototype();
7086 while (current_proto->IsJSObject() &&
7087 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7088 real_receiver = JSObject::cast(current_proto);
7089 current_proto = current_proto->GetPrototype();
7090 }
7091 }
7092
7093 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01007094 Map* map = real_receiver->map();
7095
7096 // Nothing to do if prototype is already set.
7097 if (map->prototype() == value) return value;
7098
7099 Object* new_map = map->GetPrototypeTransition(value);
7100 if (new_map == NULL) {
7101 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7102 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7103 }
7104
7105 { MaybeObject* maybe_new_cache =
7106 map->PutPrototypeTransition(value, Map::cast(new_map));
7107 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7108 }
7109
7110 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07007111 }
Steve Block053d10c2011-06-13 19:13:29 +01007112 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00007113 real_receiver->set_map(Map::cast(new_map));
7114
Steve Block44f0eee2011-05-26 01:26:41 +01007115 heap->ClearInstanceofCache();
Kristian Monsen25f61362010-05-21 11:50:48 +01007116
Andrei Popescu402d9372010-02-26 13:31:12 +00007117 return value;
7118}
7119
7120
Steve Blocka7e24c12009-10-30 11:49:00 +00007121bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) {
7122 switch (GetElementsKind()) {
7123 case FAST_ELEMENTS: {
7124 uint32_t length = IsJSArray() ?
7125 static_cast<uint32_t>
7126 (Smi::cast(JSArray::cast(this)->length())->value()) :
7127 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7128 if ((index < length) &&
7129 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7130 return true;
7131 }
7132 break;
7133 }
Steve Block44f0eee2011-05-26 01:26:41 +01007134 case EXTERNAL_PIXEL_ELEMENTS: {
7135 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007136 if (index < static_cast<uint32_t>(pixels->length())) {
7137 return true;
7138 }
7139 break;
7140 }
Steve Block3ce2e202009-11-05 08:53:23 +00007141 case EXTERNAL_BYTE_ELEMENTS:
7142 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7143 case EXTERNAL_SHORT_ELEMENTS:
7144 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7145 case EXTERNAL_INT_ELEMENTS:
7146 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007147 case EXTERNAL_FLOAT_ELEMENTS:
7148 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007149 ExternalArray* array = ExternalArray::cast(elements());
7150 if (index < static_cast<uint32_t>(array->length())) {
7151 return true;
7152 }
7153 break;
7154 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007155 case DICTIONARY_ELEMENTS: {
7156 if (element_dictionary()->FindEntry(index)
7157 != NumberDictionary::kNotFound) {
7158 return true;
7159 }
7160 break;
7161 }
7162 default:
7163 UNREACHABLE();
7164 break;
7165 }
7166
7167 // Handle [] on String objects.
7168 if (this->IsStringObjectWithCharacterAt(index)) return true;
7169
7170 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007171 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007172 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7173}
7174
7175
7176bool JSObject::HasElementWithInterceptor(JSObject* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007177 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007178 // Make sure that the top context does not change when doing
7179 // callbacks or interceptor calls.
7180 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007181 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007182 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7183 Handle<JSObject> receiver_handle(receiver);
7184 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007185 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007186 v8::AccessorInfo info(args.end());
7187 if (!interceptor->query()->IsUndefined()) {
7188 v8::IndexedPropertyQuery query =
7189 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007190 LOG(isolate,
7191 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007192 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007193 {
7194 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007195 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007196 result = query(index, info);
7197 }
Iain Merrick75681382010-08-19 15:07:18 +01007198 if (!result.IsEmpty()) {
7199 ASSERT(result->IsInt32());
7200 return true; // absence of property is signaled by empty handle.
7201 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007202 } else if (!interceptor->getter()->IsUndefined()) {
7203 v8::IndexedPropertyGetter getter =
7204 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007205 LOG(isolate,
7206 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007207 v8::Handle<v8::Value> result;
7208 {
7209 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007210 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007211 result = getter(index, info);
7212 }
7213 if (!result.IsEmpty()) return true;
7214 }
7215 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7216}
7217
7218
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007219JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007220 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007221 if (IsAccessCheckNeeded()) {
7222 Heap* heap = GetHeap();
7223 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7224 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7225 return UNDEFINED_ELEMENT;
7226 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007227 }
7228
Steve Block1e0659c2011-05-24 12:43:12 +01007229 if (IsJSGlobalProxy()) {
7230 Object* proto = GetPrototype();
7231 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7232 ASSERT(proto->IsJSGlobalObject());
7233 return JSObject::cast(proto)->HasLocalElement(index);
7234 }
7235
Steve Blocka7e24c12009-10-30 11:49:00 +00007236 // Check for lookup interceptor
7237 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007238 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7239 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007240 }
7241
7242 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007243 if (this->IsStringObjectWithCharacterAt(index)) {
7244 return STRING_CHARACTER_ELEMENT;
7245 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007246
7247 switch (GetElementsKind()) {
7248 case FAST_ELEMENTS: {
7249 uint32_t length = IsJSArray() ?
7250 static_cast<uint32_t>
7251 (Smi::cast(JSArray::cast(this)->length())->value()) :
7252 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007253 if ((index < length) &&
7254 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7255 return FAST_ELEMENT;
7256 }
7257 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007258 }
Steve Block44f0eee2011-05-26 01:26:41 +01007259 case EXTERNAL_PIXEL_ELEMENTS: {
7260 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007261 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7262 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007263 }
Steve Block3ce2e202009-11-05 08:53:23 +00007264 case EXTERNAL_BYTE_ELEMENTS:
7265 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7266 case EXTERNAL_SHORT_ELEMENTS:
7267 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7268 case EXTERNAL_INT_ELEMENTS:
7269 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007270 case EXTERNAL_FLOAT_ELEMENTS:
7271 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007272 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007273 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7274 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007275 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007276 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007277 if (element_dictionary()->FindEntry(index) !=
7278 NumberDictionary::kNotFound) {
7279 return DICTIONARY_ELEMENT;
7280 }
7281 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007282 }
7283 default:
7284 UNREACHABLE();
7285 break;
7286 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007287
7288 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007289}
7290
7291
7292bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) {
7293 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007294 if (IsAccessCheckNeeded()) {
7295 Heap* heap = GetHeap();
7296 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7297 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7298 return false;
7299 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007300 }
7301
7302 // Check for lookup interceptor
7303 if (HasIndexedInterceptor()) {
7304 return HasElementWithInterceptor(receiver, index);
7305 }
7306
7307 switch (GetElementsKind()) {
7308 case FAST_ELEMENTS: {
7309 uint32_t length = IsJSArray() ?
7310 static_cast<uint32_t>
7311 (Smi::cast(JSArray::cast(this)->length())->value()) :
7312 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7313 if ((index < length) &&
7314 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
7315 break;
7316 }
Steve Block44f0eee2011-05-26 01:26:41 +01007317 case EXTERNAL_PIXEL_ELEMENTS: {
7318 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007319 if (index < static_cast<uint32_t>(pixels->length())) {
7320 return true;
7321 }
7322 break;
7323 }
Steve Block3ce2e202009-11-05 08:53:23 +00007324 case EXTERNAL_BYTE_ELEMENTS:
7325 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7326 case EXTERNAL_SHORT_ELEMENTS:
7327 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7328 case EXTERNAL_INT_ELEMENTS:
7329 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007330 case EXTERNAL_FLOAT_ELEMENTS:
7331 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007332 ExternalArray* array = ExternalArray::cast(elements());
7333 if (index < static_cast<uint32_t>(array->length())) {
7334 return true;
7335 }
7336 break;
7337 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007338 case DICTIONARY_ELEMENTS: {
7339 if (element_dictionary()->FindEntry(index)
7340 != NumberDictionary::kNotFound) {
7341 return true;
7342 }
7343 break;
7344 }
7345 default:
7346 UNREACHABLE();
7347 break;
7348 }
7349
7350 // Handle [] on String objects.
7351 if (this->IsStringObjectWithCharacterAt(index)) return true;
7352
7353 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007354 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007355 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7356}
7357
7358
John Reck59135872010-11-02 12:39:01 -07007359MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007360 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007361 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007362 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007363 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007364 // Make sure that the top context does not change when doing
7365 // callbacks or interceptor calls.
7366 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007367 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007368 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
7369 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007370 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007371 if (!interceptor->setter()->IsUndefined()) {
7372 v8::IndexedPropertySetter setter =
7373 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01007374 LOG(isolate,
7375 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
7376 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007377 v8::AccessorInfo info(args.end());
7378 v8::Handle<v8::Value> result;
7379 {
7380 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007381 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007382 result = setter(index, v8::Utils::ToLocal(value_handle), info);
7383 }
Steve Block44f0eee2011-05-26 01:26:41 +01007384 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007385 if (!result.IsEmpty()) return *value_handle;
7386 }
John Reck59135872010-11-02 12:39:01 -07007387 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01007388 this_handle->SetElementWithoutInterceptor(index,
7389 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007390 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007391 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007392 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007393 return raw_result;
7394}
7395
7396
John Reck59135872010-11-02 12:39:01 -07007397MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
7398 Object* structure,
7399 uint32_t index,
7400 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007401 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00007402 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01007403
7404 // api style callbacks.
7405 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00007406 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01007407 Object* fun_obj = data->getter();
7408 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01007409 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007410 Handle<JSObject> self(JSObject::cast(receiver));
7411 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01007412 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7413 Handle<String> key(isolate->factory()->NumberToString(number));
7414 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
7415 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01007416 v8::AccessorInfo info(args.end());
7417 v8::Handle<v8::Value> result;
7418 {
7419 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007420 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007421 result = call_fun(v8::Utils::ToLocal(key), info);
7422 }
Steve Block44f0eee2011-05-26 01:26:41 +01007423 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
7424 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007425 return *v8::Utils::OpenHandle(*result);
7426 }
7427
7428 // __defineGetter__ callback
7429 if (structure->IsFixedArray()) {
7430 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
7431 if (getter->IsJSFunction()) {
7432 return Object::GetPropertyWithDefinedGetter(receiver,
7433 JSFunction::cast(getter));
7434 }
7435 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01007436 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01007437 }
7438
7439 UNREACHABLE();
7440 return NULL;
7441}
7442
7443
John Reck59135872010-11-02 12:39:01 -07007444MaybeObject* JSObject::SetElementWithCallback(Object* structure,
7445 uint32_t index,
7446 Object* value,
7447 JSObject* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01007448 Isolate* isolate = GetIsolate();
7449 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007450
7451 // We should never get here to initialize a const with the hole
7452 // value since a const declaration would conflict with the setter.
7453 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01007454 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007455
7456 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00007457 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01007458 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00007459 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01007460
7461 if (structure->IsAccessorInfo()) {
7462 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00007463 Handle<JSObject> self(this);
7464 Handle<JSObject> holder_handle(JSObject::cast(holder));
7465 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01007466 Object* call_obj = data->setter();
7467 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
7468 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01007469 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
7470 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00007471 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
7472 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01007473 v8::AccessorInfo info(args.end());
7474 {
7475 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007476 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01007477 call_fun(v8::Utils::ToLocal(key),
7478 v8::Utils::ToLocal(value_handle),
7479 info);
7480 }
Steve Block44f0eee2011-05-26 01:26:41 +01007481 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01007482 return *value_handle;
7483 }
7484
7485 if (structure->IsFixedArray()) {
7486 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
7487 if (setter->IsJSFunction()) {
7488 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
7489 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01007490 Handle<Object> holder_handle(holder, isolate);
7491 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01007492 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01007493 return isolate->Throw(
7494 *isolate->factory()->NewTypeError("no_setter_in_callback",
7495 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01007496 }
7497 }
7498
7499 UNREACHABLE();
7500 return NULL;
7501}
7502
7503
Steve Blocka7e24c12009-10-30 11:49:00 +00007504// Adding n elements in fast case is O(n*n).
7505// Note: revisit design to have dual undefined values to capture absent
7506// elements.
Steve Block9fac8402011-05-12 15:51:54 +01007507MaybeObject* JSObject::SetFastElement(uint32_t index,
7508 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007509 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007510 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007511 ASSERT(HasFastElements());
7512
John Reck59135872010-11-02 12:39:01 -07007513 Object* elms_obj;
7514 { MaybeObject* maybe_elms_obj = EnsureWritableFastElements();
7515 if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
7516 }
Iain Merrick75681382010-08-19 15:07:18 +01007517 FixedArray* elms = FixedArray::cast(elms_obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00007518 uint32_t elms_length = static_cast<uint32_t>(elms->length());
7519
Steve Block9fac8402011-05-12 15:51:54 +01007520 if (check_prototype &&
Steve Block1e0659c2011-05-24 12:43:12 +01007521 (index >= elms_length || elms->get(index)->IsTheHole())) {
7522 bool found;
7523 MaybeObject* result =
7524 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7525 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007526 }
7527
Steve Block9fac8402011-05-12 15:51:54 +01007528
Steve Blocka7e24c12009-10-30 11:49:00 +00007529 // Check whether there is extra space in fixed array..
7530 if (index < elms_length) {
7531 elms->set(index, value);
7532 if (IsJSArray()) {
7533 // Update the length of the array if needed.
7534 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007535 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007536 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00007537 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007538 }
7539 }
7540 return value;
7541 }
7542
7543 // Allow gap in fast case.
7544 if ((index - elms_length) < kMaxGap) {
7545 // Try allocating extra space.
7546 int new_capacity = NewElementsCapacity(index+1);
7547 if (new_capacity <= kMaxFastElementsLength ||
7548 !ShouldConvertToSlowElements(new_capacity)) {
7549 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07007550 Object* obj;
7551 { MaybeObject* maybe_obj =
7552 SetFastElementsCapacityAndLength(new_capacity, index + 1);
7553 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7554 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007555 FixedArray::cast(elements())->set(index, value);
7556 return value;
7557 }
7558 }
7559
7560 // Otherwise default to slow case.
John Reck59135872010-11-02 12:39:01 -07007561 Object* obj;
7562 { MaybeObject* maybe_obj = NormalizeElements();
7563 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7564 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007565 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007566 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007567}
7568
Iain Merrick75681382010-08-19 15:07:18 +01007569
Steve Block9fac8402011-05-12 15:51:54 +01007570MaybeObject* JSObject::SetElement(uint32_t index,
7571 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007572 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007573 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007574 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007575 if (IsAccessCheckNeeded()) {
7576 Heap* heap = GetHeap();
7577 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
7578 HandleScope scope;
7579 Handle<Object> value_handle(value);
7580 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
7581 return *value_handle;
7582 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007583 }
7584
7585 if (IsJSGlobalProxy()) {
7586 Object* proto = GetPrototype();
7587 if (proto->IsNull()) return value;
7588 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007589 return JSObject::cast(proto)->SetElement(index,
7590 value,
7591 strict_mode,
7592 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007593 }
7594
7595 // Check for lookup interceptor
7596 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007597 return SetElementWithInterceptor(index,
7598 value,
7599 strict_mode,
7600 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007601 }
7602
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007603 return SetElementWithoutInterceptor(index,
7604 value,
7605 strict_mode,
7606 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00007607}
7608
7609
John Reck59135872010-11-02 12:39:01 -07007610MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01007611 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007612 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01007613 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01007614 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007615 switch (GetElementsKind()) {
7616 case FAST_ELEMENTS:
7617 // Fast case.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007618 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01007619 case EXTERNAL_PIXEL_ELEMENTS: {
7620 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007621 return pixels->SetValue(index, value);
7622 }
Steve Block3ce2e202009-11-05 08:53:23 +00007623 case EXTERNAL_BYTE_ELEMENTS: {
7624 ExternalByteArray* array = ExternalByteArray::cast(elements());
7625 return array->SetValue(index, value);
7626 }
7627 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7628 ExternalUnsignedByteArray* array =
7629 ExternalUnsignedByteArray::cast(elements());
7630 return array->SetValue(index, value);
7631 }
7632 case EXTERNAL_SHORT_ELEMENTS: {
7633 ExternalShortArray* array = ExternalShortArray::cast(elements());
7634 return array->SetValue(index, value);
7635 }
7636 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7637 ExternalUnsignedShortArray* array =
7638 ExternalUnsignedShortArray::cast(elements());
7639 return array->SetValue(index, value);
7640 }
7641 case EXTERNAL_INT_ELEMENTS: {
7642 ExternalIntArray* array = ExternalIntArray::cast(elements());
7643 return array->SetValue(index, value);
7644 }
7645 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7646 ExternalUnsignedIntArray* array =
7647 ExternalUnsignedIntArray::cast(elements());
7648 return array->SetValue(index, value);
7649 }
7650 case EXTERNAL_FLOAT_ELEMENTS: {
7651 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
7652 return array->SetValue(index, value);
7653 }
Ben Murdoch257744e2011-11-30 15:57:28 +00007654 case EXTERNAL_DOUBLE_ELEMENTS: {
7655 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
7656 return array->SetValue(index, value);
7657 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007658 case DICTIONARY_ELEMENTS: {
7659 // Insert element in the dictionary.
7660 FixedArray* elms = FixedArray::cast(elements());
7661 NumberDictionary* dictionary = NumberDictionary::cast(elms);
7662
7663 int entry = dictionary->FindEntry(index);
7664 if (entry != NumberDictionary::kNotFound) {
7665 Object* element = dictionary->ValueAt(entry);
7666 PropertyDetails details = dictionary->DetailsAt(entry);
7667 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007668 return SetElementWithCallback(element, index, value, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007669 } else {
7670 dictionary->UpdateMaxNumberKey(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007671 // If put fails instrict mode, throw exception.
7672 if (!dictionary->ValueAtPut(entry, value) &&
7673 strict_mode == kStrictMode) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007674 Handle<Object> holder(this);
Ben Murdoch257744e2011-11-30 15:57:28 +00007675 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007676 Handle<Object> args[2] = { number, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01007677 return isolate->Throw(
7678 *isolate->factory()->NewTypeError("strict_read_only_property",
7679 HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007680 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007681 }
7682 } else {
7683 // Index not already used. Look for an accessor in the prototype chain.
Steve Block1e0659c2011-05-24 12:43:12 +01007684 if (check_prototype) {
7685 bool found;
7686 MaybeObject* result =
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007687 // Strict mode not needed. No-setter case already handled.
Steve Block1e0659c2011-05-24 12:43:12 +01007688 SetElementWithCallbackSetterInPrototypes(index, value, &found);
7689 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007690 }
Steve Block8defd9f2010-07-08 12:39:36 +01007691 // When we set the is_extensible flag to false we always force
7692 // the element into dictionary mode (and force them to stay there).
7693 if (!map()->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007694 if (strict_mode == kNonStrictMode) {
7695 return isolate->heap()->undefined_value();
7696 } else {
7697 Handle<Object> number(isolate->factory()->NewNumberFromUint(index));
7698 Handle<String> index_string(
7699 isolate->factory()->NumberToString(number));
7700 Handle<Object> args[1] = { index_string };
7701 return isolate->Throw(
7702 *isolate->factory()->NewTypeError("object_not_extensible",
7703 HandleVector(args, 1)));
7704 }
Steve Block8defd9f2010-07-08 12:39:36 +01007705 }
John Reck59135872010-11-02 12:39:01 -07007706 Object* result;
7707 { MaybeObject* maybe_result = dictionary->AtNumberPut(index, value);
7708 if (!maybe_result->ToObject(&result)) return maybe_result;
7709 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007710 if (elms != FixedArray::cast(result)) {
7711 set_elements(FixedArray::cast(result));
7712 }
7713 }
7714
7715 // Update the array length if this JSObject is an array.
7716 if (IsJSArray()) {
7717 JSArray* array = JSArray::cast(this);
John Reck59135872010-11-02 12:39:01 -07007718 Object* return_value;
7719 { MaybeObject* maybe_return_value =
7720 array->JSArrayUpdateLengthFromIndex(index, value);
7721 if (!maybe_return_value->ToObject(&return_value)) {
7722 return maybe_return_value;
7723 }
7724 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007725 }
7726
7727 // Attempt to put this object back in fast case.
7728 if (ShouldConvertToFastElements()) {
7729 uint32_t new_length = 0;
7730 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007731 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007732 } else {
7733 new_length = NumberDictionary::cast(elements())->max_number_key() + 1;
7734 }
John Reck59135872010-11-02 12:39:01 -07007735 Object* obj;
7736 { MaybeObject* maybe_obj =
7737 SetFastElementsCapacityAndLength(new_length, new_length);
7738 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7739 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007740#ifdef DEBUG
7741 if (FLAG_trace_normalization) {
7742 PrintF("Object elements are fast case again:\n");
7743 Print();
7744 }
7745#endif
7746 }
7747
7748 return value;
7749 }
7750 default:
7751 UNREACHABLE();
7752 break;
7753 }
7754 // All possible cases have been handled above. Add a return to avoid the
7755 // complaints from the compiler.
7756 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01007757 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007758}
7759
7760
John Reck59135872010-11-02 12:39:01 -07007761MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
7762 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007763 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007764 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00007765 // Check to see if we need to update the length. For now, we make
7766 // sure that the length stays within 32-bits (unsigned).
7767 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07007768 Object* len;
7769 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01007770 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07007771 if (!maybe_len->ToObject(&len)) return maybe_len;
7772 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007773 set_length(len);
7774 }
7775 return value;
7776}
7777
7778
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007779MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007780 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007781 // Get element works for both JSObject and JSArray since
7782 // JSArray::length cannot change.
7783 switch (GetElementsKind()) {
7784 case FAST_ELEMENTS: {
7785 FixedArray* elms = FixedArray::cast(elements());
7786 if (index < static_cast<uint32_t>(elms->length())) {
7787 Object* value = elms->get(index);
7788 if (!value->IsTheHole()) return value;
7789 }
7790 break;
7791 }
Steve Block44f0eee2011-05-26 01:26:41 +01007792 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00007793 case EXTERNAL_BYTE_ELEMENTS:
7794 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7795 case EXTERNAL_SHORT_ELEMENTS:
7796 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7797 case EXTERNAL_INT_ELEMENTS:
7798 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007799 case EXTERNAL_FLOAT_ELEMENTS:
7800 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007801 MaybeObject* maybe_value = GetExternalElement(index);
7802 Object* value;
7803 if (!maybe_value->ToObject(&value)) return maybe_value;
7804 if (!value->IsUndefined()) return value;
Steve Block3ce2e202009-11-05 08:53:23 +00007805 break;
7806 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007807 case DICTIONARY_ELEMENTS: {
7808 NumberDictionary* dictionary = element_dictionary();
7809 int entry = dictionary->FindEntry(index);
7810 if (entry != NumberDictionary::kNotFound) {
7811 Object* element = dictionary->ValueAt(entry);
7812 PropertyDetails details = dictionary->DetailsAt(entry);
7813 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01007814 return GetElementWithCallback(receiver,
7815 element,
7816 index,
7817 this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007818 }
7819 return element;
7820 }
7821 break;
7822 }
7823 default:
7824 UNREACHABLE();
7825 break;
7826 }
7827
7828 // Continue searching via the prototype chain.
7829 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007830 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00007831 return pt->GetElementWithReceiver(receiver, index);
7832}
7833
7834
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007835MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007836 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007837 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007838 // Make sure that the top context does not change when doing
7839 // callbacks or interceptor calls.
7840 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007841 HandleScope scope(isolate);
7842 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
7843 Handle<Object> this_handle(receiver, isolate);
7844 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007845 if (!interceptor->getter()->IsUndefined()) {
7846 v8::IndexedPropertyGetter getter =
7847 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007848 LOG(isolate,
7849 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
7850 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007851 v8::AccessorInfo info(args.end());
7852 v8::Handle<v8::Value> result;
7853 {
7854 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007855 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007856 result = getter(index, info);
7857 }
Steve Block44f0eee2011-05-26 01:26:41 +01007858 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007859 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
7860 }
7861
John Reck59135872010-11-02 12:39:01 -07007862 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00007863 holder_handle->GetElementPostInterceptor(*this_handle, index);
Steve Block44f0eee2011-05-26 01:26:41 +01007864 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007865 return raw_result;
7866}
7867
7868
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007869MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07007870 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007871 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007872 if (IsAccessCheckNeeded()) {
7873 Heap* heap = GetHeap();
7874 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
7875 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
7876 return heap->undefined_value();
7877 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007878 }
7879
7880 if (HasIndexedInterceptor()) {
7881 return GetElementWithInterceptor(receiver, index);
7882 }
7883
7884 // Get element works for both JSObject and JSArray since
7885 // JSArray::length cannot change.
7886 switch (GetElementsKind()) {
7887 case FAST_ELEMENTS: {
7888 FixedArray* elms = FixedArray::cast(elements());
7889 if (index < static_cast<uint32_t>(elms->length())) {
7890 Object* value = elms->get(index);
7891 if (!value->IsTheHole()) return value;
7892 }
7893 break;
7894 }
Steve Block44f0eee2011-05-26 01:26:41 +01007895 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007896 case EXTERNAL_BYTE_ELEMENTS:
7897 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7898 case EXTERNAL_SHORT_ELEMENTS:
7899 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7900 case EXTERNAL_INT_ELEMENTS:
7901 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007902 case EXTERNAL_FLOAT_ELEMENTS:
7903 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007904 MaybeObject* maybe_value = GetExternalElement(index);
7905 Object* value;
7906 if (!maybe_value->ToObject(&value)) return maybe_value;
7907 if (!value->IsUndefined()) return value;
7908 break;
7909 }
7910 case DICTIONARY_ELEMENTS: {
7911 NumberDictionary* dictionary = element_dictionary();
7912 int entry = dictionary->FindEntry(index);
7913 if (entry != NumberDictionary::kNotFound) {
7914 Object* element = dictionary->ValueAt(entry);
7915 PropertyDetails details = dictionary->DetailsAt(entry);
7916 if (details.type() == CALLBACKS) {
7917 return GetElementWithCallback(receiver,
7918 element,
7919 index,
7920 this);
7921 }
7922 return element;
7923 }
7924 break;
7925 }
7926 }
7927
7928 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007929 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01007930 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007931 return pt->GetElementWithReceiver(receiver, index);
7932}
7933
7934
7935MaybeObject* JSObject::GetExternalElement(uint32_t index) {
7936 // Get element works for both JSObject and JSArray since
7937 // JSArray::length cannot change.
7938 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01007939 case EXTERNAL_PIXEL_ELEMENTS: {
7940 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007941 if (index < static_cast<uint32_t>(pixels->length())) {
7942 uint8_t value = pixels->get(index);
7943 return Smi::FromInt(value);
7944 }
7945 break;
7946 }
Steve Block3ce2e202009-11-05 08:53:23 +00007947 case EXTERNAL_BYTE_ELEMENTS: {
7948 ExternalByteArray* array = ExternalByteArray::cast(elements());
7949 if (index < static_cast<uint32_t>(array->length())) {
7950 int8_t value = array->get(index);
7951 return Smi::FromInt(value);
7952 }
7953 break;
7954 }
7955 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
7956 ExternalUnsignedByteArray* array =
7957 ExternalUnsignedByteArray::cast(elements());
7958 if (index < static_cast<uint32_t>(array->length())) {
7959 uint8_t value = array->get(index);
7960 return Smi::FromInt(value);
7961 }
7962 break;
7963 }
7964 case EXTERNAL_SHORT_ELEMENTS: {
7965 ExternalShortArray* array = ExternalShortArray::cast(elements());
7966 if (index < static_cast<uint32_t>(array->length())) {
7967 int16_t value = array->get(index);
7968 return Smi::FromInt(value);
7969 }
7970 break;
7971 }
7972 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
7973 ExternalUnsignedShortArray* array =
7974 ExternalUnsignedShortArray::cast(elements());
7975 if (index < static_cast<uint32_t>(array->length())) {
7976 uint16_t value = array->get(index);
7977 return Smi::FromInt(value);
7978 }
7979 break;
7980 }
7981 case EXTERNAL_INT_ELEMENTS: {
7982 ExternalIntArray* array = ExternalIntArray::cast(elements());
7983 if (index < static_cast<uint32_t>(array->length())) {
7984 int32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007985 return GetHeap()->NumberFromInt32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007986 }
7987 break;
7988 }
7989 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
7990 ExternalUnsignedIntArray* array =
7991 ExternalUnsignedIntArray::cast(elements());
7992 if (index < static_cast<uint32_t>(array->length())) {
7993 uint32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01007994 return GetHeap()->NumberFromUint32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00007995 }
7996 break;
7997 }
7998 case EXTERNAL_FLOAT_ELEMENTS: {
7999 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8000 if (index < static_cast<uint32_t>(array->length())) {
8001 float value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01008002 return GetHeap()->AllocateHeapNumber(value);
Steve Block3ce2e202009-11-05 08:53:23 +00008003 }
8004 break;
8005 }
Ben Murdoch257744e2011-11-30 15:57:28 +00008006 case EXTERNAL_DOUBLE_ELEMENTS: {
8007 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8008 if (index < static_cast<uint32_t>(array->length())) {
8009 double value = array->get(index);
8010 return GetHeap()->AllocateHeapNumber(value);
8011 }
8012 break;
8013 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008014 case FAST_ELEMENTS:
8015 case DICTIONARY_ELEMENTS:
8016 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00008017 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008018 }
Steve Block44f0eee2011-05-26 01:26:41 +01008019 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008020}
8021
8022
8023bool JSObject::HasDenseElements() {
8024 int capacity = 0;
8025 int number_of_elements = 0;
8026
8027 switch (GetElementsKind()) {
8028 case FAST_ELEMENTS: {
8029 FixedArray* elms = FixedArray::cast(elements());
8030 capacity = elms->length();
8031 for (int i = 0; i < capacity; i++) {
8032 if (!elms->get(i)->IsTheHole()) number_of_elements++;
8033 }
8034 break;
8035 }
Steve Block44f0eee2011-05-26 01:26:41 +01008036 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00008037 case EXTERNAL_BYTE_ELEMENTS:
8038 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8039 case EXTERNAL_SHORT_ELEMENTS:
8040 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8041 case EXTERNAL_INT_ELEMENTS:
8042 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008043 case EXTERNAL_FLOAT_ELEMENTS:
8044 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +00008045 return true;
8046 }
8047 case DICTIONARY_ELEMENTS: {
8048 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8049 capacity = dictionary->Capacity();
8050 number_of_elements = dictionary->NumberOfElements();
8051 break;
8052 }
8053 default:
8054 UNREACHABLE();
8055 break;
8056 }
8057
8058 if (capacity == 0) return true;
8059 return (number_of_elements > (capacity / 2));
8060}
8061
8062
8063bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
8064 ASSERT(HasFastElements());
8065 // Keep the array in fast case if the current backing storage is
8066 // almost filled and if the new capacity is no more than twice the
8067 // old capacity.
8068 int elements_length = FixedArray::cast(elements())->length();
8069 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
8070}
8071
8072
8073bool JSObject::ShouldConvertToFastElements() {
8074 ASSERT(HasDictionaryElements());
8075 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8076 // If the elements are sparse, we should not go back to fast case.
8077 if (!HasDenseElements()) return false;
8078 // If an element has been added at a very high index in the elements
8079 // dictionary, we cannot go back to fast case.
8080 if (dictionary->requires_slow_elements()) return false;
8081 // An object requiring access checks is never allowed to have fast
8082 // elements. If it had fast elements we would skip security checks.
8083 if (IsAccessCheckNeeded()) return false;
8084 // If the dictionary backing storage takes up roughly half as much
8085 // space as a fast-case backing storage would the array should have
8086 // fast elements.
8087 uint32_t length = 0;
8088 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008089 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
Steve Blocka7e24c12009-10-30 11:49:00 +00008090 } else {
8091 length = dictionary->max_number_key();
8092 }
8093 return static_cast<uint32_t>(dictionary->Capacity()) >=
8094 (length / (2 * NumberDictionary::kEntrySize));
8095}
8096
8097
8098// Certain compilers request function template instantiation when they
8099// see the definition of the other template functions in the
8100// class. This requires us to have the template functions put
8101// together, so even though this function belongs in objects-debug.cc,
8102// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008103#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00008104template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01008105void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008106 int capacity = HashTable<Shape, Key>::Capacity();
8107 for (int i = 0; i < capacity; i++) {
8108 Object* k = HashTable<Shape, Key>::KeyAt(i);
8109 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008110 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00008111 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008112 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008113 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008114 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008115 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008116 PrintF(out, ": ");
8117 ValueAt(i)->ShortPrint(out);
8118 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008119 }
8120 }
8121}
8122#endif
8123
8124
8125template<typename Shape, typename Key>
8126void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
8127 int pos = 0;
8128 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00008129 AssertNoAllocation no_gc;
8130 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008131 for (int i = 0; i < capacity; i++) {
8132 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8133 if (Dictionary<Shape, Key>::IsKey(k)) {
8134 elements->set(pos++, ValueAt(i), mode);
8135 }
8136 }
8137 ASSERT(pos == elements->length());
8138}
8139
8140
8141InterceptorInfo* JSObject::GetNamedInterceptor() {
8142 ASSERT(map()->has_named_interceptor());
8143 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008144 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008145 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008146 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008147 return InterceptorInfo::cast(result);
8148}
8149
8150
8151InterceptorInfo* JSObject::GetIndexedInterceptor() {
8152 ASSERT(map()->has_indexed_interceptor());
8153 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008154 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008155 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008156 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008157 return InterceptorInfo::cast(result);
8158}
8159
8160
John Reck59135872010-11-02 12:39:01 -07008161MaybeObject* JSObject::GetPropertyPostInterceptor(
8162 JSObject* receiver,
8163 String* name,
8164 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008165 // Check local property in holder, ignore interceptor.
8166 LookupResult result;
8167 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008168 if (result.IsProperty()) {
8169 return GetProperty(receiver, &result, name, attributes);
8170 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008171 // Continue searching via the prototype chain.
8172 Object* pt = GetPrototype();
8173 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008174 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008175 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8176}
8177
8178
John Reck59135872010-11-02 12:39:01 -07008179MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Steve Blockd0582a62009-12-15 09:54:21 +00008180 JSObject* receiver,
8181 String* name,
8182 PropertyAttributes* attributes) {
8183 // Check local property in holder, ignore interceptor.
8184 LookupResult result;
8185 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008186 if (result.IsProperty()) {
8187 return GetProperty(receiver, &result, name, attributes);
8188 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01008189 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00008190}
8191
8192
John Reck59135872010-11-02 12:39:01 -07008193MaybeObject* JSObject::GetPropertyWithInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00008194 JSObject* receiver,
8195 String* name,
8196 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01008197 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008198 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01008199 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008200 Handle<JSObject> receiver_handle(receiver);
8201 Handle<JSObject> holder_handle(this);
8202 Handle<String> name_handle(name);
8203
8204 if (!interceptor->getter()->IsUndefined()) {
8205 v8::NamedPropertyGetter getter =
8206 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008207 LOG(isolate,
8208 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8209 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008210 v8::AccessorInfo info(args.end());
8211 v8::Handle<v8::Value> result;
8212 {
8213 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008214 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008215 result = getter(v8::Utils::ToLocal(name_handle), info);
8216 }
Steve Block44f0eee2011-05-26 01:26:41 +01008217 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008218 if (!result.IsEmpty()) {
8219 *attributes = NONE;
8220 return *v8::Utils::OpenHandle(*result);
8221 }
8222 }
8223
John Reck59135872010-11-02 12:39:01 -07008224 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00008225 *receiver_handle,
8226 *name_handle,
8227 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01008228 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008229 return result;
8230}
8231
8232
8233bool JSObject::HasRealNamedProperty(String* key) {
8234 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008235 if (IsAccessCheckNeeded()) {
8236 Heap* heap = GetHeap();
8237 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8238 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8239 return false;
8240 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008241 }
8242
8243 LookupResult result;
8244 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008245 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00008246}
8247
8248
8249bool JSObject::HasRealElementProperty(uint32_t index) {
8250 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008251 if (IsAccessCheckNeeded()) {
8252 Heap* heap = GetHeap();
8253 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8254 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8255 return false;
8256 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008257 }
8258
8259 // Handle [] on String objects.
8260 if (this->IsStringObjectWithCharacterAt(index)) return true;
8261
8262 switch (GetElementsKind()) {
8263 case FAST_ELEMENTS: {
8264 uint32_t length = IsJSArray() ?
8265 static_cast<uint32_t>(
8266 Smi::cast(JSArray::cast(this)->length())->value()) :
8267 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8268 return (index < length) &&
8269 !FixedArray::cast(elements())->get(index)->IsTheHole();
8270 }
Steve Block44f0eee2011-05-26 01:26:41 +01008271 case EXTERNAL_PIXEL_ELEMENTS: {
8272 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008273 return index < static_cast<uint32_t>(pixels->length());
8274 }
Steve Block3ce2e202009-11-05 08:53:23 +00008275 case EXTERNAL_BYTE_ELEMENTS:
8276 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8277 case EXTERNAL_SHORT_ELEMENTS:
8278 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8279 case EXTERNAL_INT_ELEMENTS:
8280 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008281 case EXTERNAL_FLOAT_ELEMENTS:
8282 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008283 ExternalArray* array = ExternalArray::cast(elements());
8284 return index < static_cast<uint32_t>(array->length());
8285 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008286 case DICTIONARY_ELEMENTS: {
8287 return element_dictionary()->FindEntry(index)
8288 != NumberDictionary::kNotFound;
8289 }
8290 default:
8291 UNREACHABLE();
8292 break;
8293 }
8294 // All possibilities have been handled above already.
8295 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008296 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008297}
8298
8299
8300bool JSObject::HasRealNamedCallbackProperty(String* key) {
8301 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008302 if (IsAccessCheckNeeded()) {
8303 Heap* heap = GetHeap();
8304 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
8305 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8306 return false;
8307 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008308 }
8309
8310 LookupResult result;
8311 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008312 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00008313}
8314
8315
8316int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
8317 if (HasFastProperties()) {
8318 DescriptorArray* descs = map()->instance_descriptors();
8319 int result = 0;
8320 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01008321 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008322 if (details.IsProperty() && (details.attributes() & filter) == 0) {
8323 result++;
8324 }
8325 }
8326 return result;
8327 } else {
8328 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
8329 }
8330}
8331
8332
8333int JSObject::NumberOfEnumProperties() {
8334 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
8335}
8336
8337
8338void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
8339 Object* temp = get(i);
8340 set(i, get(j));
8341 set(j, temp);
8342 if (this != numbers) {
8343 temp = numbers->get(i);
8344 numbers->set(i, numbers->get(j));
8345 numbers->set(j, temp);
8346 }
8347}
8348
8349
8350static void InsertionSortPairs(FixedArray* content,
8351 FixedArray* numbers,
8352 int len) {
8353 for (int i = 1; i < len; i++) {
8354 int j = i;
8355 while (j > 0 &&
8356 (NumberToUint32(numbers->get(j - 1)) >
8357 NumberToUint32(numbers->get(j)))) {
8358 content->SwapPairs(numbers, j - 1, j);
8359 j--;
8360 }
8361 }
8362}
8363
8364
8365void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
8366 // In-place heap sort.
8367 ASSERT(content->length() == numbers->length());
8368
8369 // Bottom-up max-heap construction.
8370 for (int i = 1; i < len; ++i) {
8371 int child_index = i;
8372 while (child_index > 0) {
8373 int parent_index = ((child_index + 1) >> 1) - 1;
8374 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8375 uint32_t child_value = NumberToUint32(numbers->get(child_index));
8376 if (parent_value < child_value) {
8377 content->SwapPairs(numbers, parent_index, child_index);
8378 } else {
8379 break;
8380 }
8381 child_index = parent_index;
8382 }
8383 }
8384
8385 // Extract elements and create sorted array.
8386 for (int i = len - 1; i > 0; --i) {
8387 // Put max element at the back of the array.
8388 content->SwapPairs(numbers, 0, i);
8389 // Sift down the new top element.
8390 int parent_index = 0;
8391 while (true) {
8392 int child_index = ((parent_index + 1) << 1) - 1;
8393 if (child_index >= i) break;
8394 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
8395 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
8396 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
8397 if (child_index + 1 >= i || child1_value > child2_value) {
8398 if (parent_value > child1_value) break;
8399 content->SwapPairs(numbers, parent_index, child_index);
8400 parent_index = child_index;
8401 } else {
8402 if (parent_value > child2_value) break;
8403 content->SwapPairs(numbers, parent_index, child_index + 1);
8404 parent_index = child_index + 1;
8405 }
8406 }
8407 }
8408}
8409
8410
8411// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
8412void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
8413 ASSERT(this->length() == numbers->length());
8414 // For small arrays, simply use insertion sort.
8415 if (len <= 10) {
8416 InsertionSortPairs(this, numbers, len);
8417 return;
8418 }
8419 // Check the range of indices.
8420 uint32_t min_index = NumberToUint32(numbers->get(0));
8421 uint32_t max_index = min_index;
8422 uint32_t i;
8423 for (i = 1; i < len; i++) {
8424 if (NumberToUint32(numbers->get(i)) < min_index) {
8425 min_index = NumberToUint32(numbers->get(i));
8426 } else if (NumberToUint32(numbers->get(i)) > max_index) {
8427 max_index = NumberToUint32(numbers->get(i));
8428 }
8429 }
8430 if (max_index - min_index + 1 == len) {
8431 // Indices form a contiguous range, unless there are duplicates.
8432 // Do an in-place linear time sort assuming distinct numbers, but
8433 // avoid hanging in case they are not.
8434 for (i = 0; i < len; i++) {
8435 uint32_t p;
8436 uint32_t j = 0;
8437 // While the current element at i is not at its correct position p,
8438 // swap the elements at these two positions.
8439 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
8440 j++ < len) {
8441 SwapPairs(numbers, i, p);
8442 }
8443 }
8444 } else {
8445 HeapSortPairs(this, numbers, len);
8446 return;
8447 }
8448}
8449
8450
8451// Fill in the names of local properties into the supplied storage. The main
8452// purpose of this function is to provide reflection information for the object
8453// mirrors.
8454void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
8455 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
8456 if (HasFastProperties()) {
8457 DescriptorArray* descs = map()->instance_descriptors();
8458 for (int i = 0; i < descs->number_of_descriptors(); i++) {
8459 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
8460 }
8461 ASSERT(storage->length() >= index);
8462 } else {
Ben Murdoch257744e2011-11-30 15:57:28 +00008463 property_dictionary()->CopyKeysTo(storage, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008464 }
8465}
8466
8467
8468int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
8469 return GetLocalElementKeys(NULL, filter);
8470}
8471
8472
8473int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00008474 // Fast case for objects with no elements.
8475 if (!IsJSValue() && HasFastElements()) {
8476 uint32_t length = IsJSArray() ?
8477 static_cast<uint32_t>(
8478 Smi::cast(JSArray::cast(this)->length())->value()) :
8479 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8480 if (length == 0) return 0;
8481 }
8482 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00008483 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
8484}
8485
8486
8487int JSObject::GetLocalElementKeys(FixedArray* storage,
8488 PropertyAttributes filter) {
8489 int counter = 0;
8490 switch (GetElementsKind()) {
8491 case FAST_ELEMENTS: {
8492 int length = IsJSArray() ?
8493 Smi::cast(JSArray::cast(this)->length())->value() :
8494 FixedArray::cast(elements())->length();
8495 for (int i = 0; i < length; i++) {
8496 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
8497 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008498 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008499 }
8500 counter++;
8501 }
8502 }
8503 ASSERT(!storage || storage->length() >= counter);
8504 break;
8505 }
Steve Block44f0eee2011-05-26 01:26:41 +01008506 case EXTERNAL_PIXEL_ELEMENTS: {
8507 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00008508 while (counter < length) {
8509 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008510 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00008511 }
8512 counter++;
8513 }
8514 ASSERT(!storage || storage->length() >= counter);
8515 break;
8516 }
Steve Block3ce2e202009-11-05 08:53:23 +00008517 case EXTERNAL_BYTE_ELEMENTS:
8518 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8519 case EXTERNAL_SHORT_ELEMENTS:
8520 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8521 case EXTERNAL_INT_ELEMENTS:
8522 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008523 case EXTERNAL_FLOAT_ELEMENTS:
8524 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008525 int length = ExternalArray::cast(elements())->length();
8526 while (counter < length) {
8527 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00008528 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00008529 }
8530 counter++;
8531 }
8532 ASSERT(!storage || storage->length() >= counter);
8533 break;
8534 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008535 case DICTIONARY_ELEMENTS: {
8536 if (storage != NULL) {
8537 element_dictionary()->CopyKeysTo(storage, filter);
8538 }
8539 counter = element_dictionary()->NumberOfElementsFilterAttributes(filter);
8540 break;
8541 }
8542 default:
8543 UNREACHABLE();
8544 break;
8545 }
8546
8547 if (this->IsJSValue()) {
8548 Object* val = JSValue::cast(this)->value();
8549 if (val->IsString()) {
8550 String* str = String::cast(val);
8551 if (storage) {
8552 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00008553 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00008554 }
8555 }
8556 counter += str->length();
8557 }
8558 }
8559 ASSERT(!storage || storage->length() == counter);
8560 return counter;
8561}
8562
8563
8564int JSObject::GetEnumElementKeys(FixedArray* storage) {
8565 return GetLocalElementKeys(storage,
8566 static_cast<PropertyAttributes>(DONT_ENUM));
8567}
8568
8569
Steve Blocka7e24c12009-10-30 11:49:00 +00008570// StringKey simply carries a string object as key.
8571class StringKey : public HashTableKey {
8572 public:
8573 explicit StringKey(String* string) :
8574 string_(string),
8575 hash_(HashForObject(string)) { }
8576
8577 bool IsMatch(Object* string) {
8578 // We know that all entries in a hash table had their hash keys created.
8579 // Use that knowledge to have fast failure.
8580 if (hash_ != HashForObject(string)) {
8581 return false;
8582 }
8583 return string_->Equals(String::cast(string));
8584 }
8585
8586 uint32_t Hash() { return hash_; }
8587
8588 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
8589
8590 Object* AsObject() { return string_; }
8591
8592 String* string_;
8593 uint32_t hash_;
8594};
8595
8596
8597// StringSharedKeys are used as keys in the eval cache.
8598class StringSharedKey : public HashTableKey {
8599 public:
Steve Block1e0659c2011-05-24 12:43:12 +01008600 StringSharedKey(String* source,
8601 SharedFunctionInfo* shared,
8602 StrictModeFlag strict_mode)
8603 : source_(source),
8604 shared_(shared),
8605 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008606
8607 bool IsMatch(Object* other) {
8608 if (!other->IsFixedArray()) return false;
8609 FixedArray* pair = FixedArray::cast(other);
8610 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8611 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01008612 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8613 Smi::cast(pair->get(2))->value());
8614 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008615 String* source = String::cast(pair->get(1));
8616 return source->Equals(source_);
8617 }
8618
8619 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01008620 SharedFunctionInfo* shared,
8621 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008622 uint32_t hash = source->Hash();
8623 if (shared->HasSourceCode()) {
8624 // Instead of using the SharedFunctionInfo pointer in the hash
8625 // code computation, we use a combination of the hash of the
8626 // script source code and the start and end positions. We do
8627 // this to ensure that the cache entries can survive garbage
8628 // collection.
8629 Script* script = Script::cast(shared->script());
8630 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01008631 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00008632 hash += shared->start_position();
8633 }
8634 return hash;
8635 }
8636
8637 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01008638 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008639 }
8640
8641 uint32_t HashForObject(Object* obj) {
8642 FixedArray* pair = FixedArray::cast(obj);
8643 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
8644 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01008645 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
8646 Smi::cast(pair->get(2))->value());
8647 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00008648 }
8649
John Reck59135872010-11-02 12:39:01 -07008650 MUST_USE_RESULT MaybeObject* AsObject() {
8651 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008652 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07008653 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8654 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008655 FixedArray* pair = FixedArray::cast(obj);
8656 pair->set(0, shared_);
8657 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01008658 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00008659 return pair;
8660 }
8661
8662 private:
8663 String* source_;
8664 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01008665 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008666};
8667
8668
8669// RegExpKey carries the source and flags of a regular expression as key.
8670class RegExpKey : public HashTableKey {
8671 public:
8672 RegExpKey(String* string, JSRegExp::Flags flags)
8673 : string_(string),
8674 flags_(Smi::FromInt(flags.value())) { }
8675
Steve Block3ce2e202009-11-05 08:53:23 +00008676 // Rather than storing the key in the hash table, a pointer to the
8677 // stored value is stored where the key should be. IsMatch then
8678 // compares the search key to the found object, rather than comparing
8679 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00008680 bool IsMatch(Object* obj) {
8681 FixedArray* val = FixedArray::cast(obj);
8682 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
8683 && (flags_ == val->get(JSRegExp::kFlagsIndex));
8684 }
8685
8686 uint32_t Hash() { return RegExpHash(string_, flags_); }
8687
8688 Object* AsObject() {
8689 // Plain hash maps, which is where regexp keys are used, don't
8690 // use this function.
8691 UNREACHABLE();
8692 return NULL;
8693 }
8694
8695 uint32_t HashForObject(Object* obj) {
8696 FixedArray* val = FixedArray::cast(obj);
8697 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
8698 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
8699 }
8700
8701 static uint32_t RegExpHash(String* string, Smi* flags) {
8702 return string->Hash() + flags->value();
8703 }
8704
8705 String* string_;
8706 Smi* flags_;
8707};
8708
8709// Utf8SymbolKey carries a vector of chars as key.
8710class Utf8SymbolKey : public HashTableKey {
8711 public:
8712 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00008713 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008714
8715 bool IsMatch(Object* string) {
8716 return String::cast(string)->IsEqualTo(string_);
8717 }
8718
8719 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00008720 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008721 unibrow::Utf8InputBuffer<> buffer(string_.start(),
8722 static_cast<unsigned>(string_.length()));
8723 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00008724 hash_field_ = String::ComputeHashField(&buffer, chars_);
8725 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00008726 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8727 return result;
8728 }
8729
8730 uint32_t HashForObject(Object* other) {
8731 return String::cast(other)->Hash();
8732 }
8733
John Reck59135872010-11-02 12:39:01 -07008734 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00008735 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008736 return Isolate::Current()->heap()->AllocateSymbol(
8737 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008738 }
8739
8740 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00008741 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00008742 int chars_; // Caches the number of characters when computing the hash code.
8743};
8744
8745
Steve Block9fac8402011-05-12 15:51:54 +01008746template <typename Char>
8747class SequentialSymbolKey : public HashTableKey {
8748 public:
8749 explicit SequentialSymbolKey(Vector<const Char> string)
8750 : string_(string), hash_field_(0) { }
8751
8752 uint32_t Hash() {
8753 StringHasher hasher(string_.length());
8754
8755 // Very long strings have a trivial hash that doesn't inspect the
8756 // string contents.
8757 if (hasher.has_trivial_hash()) {
8758 hash_field_ = hasher.GetHashField();
8759 } else {
8760 int i = 0;
8761 // Do the iterative array index computation as long as there is a
8762 // chance this is an array index.
8763 while (i < string_.length() && hasher.is_array_index()) {
8764 hasher.AddCharacter(static_cast<uc32>(string_[i]));
8765 i++;
8766 }
8767
8768 // Process the remaining characters without updating the array
8769 // index.
8770 while (i < string_.length()) {
8771 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
8772 i++;
8773 }
8774 hash_field_ = hasher.GetHashField();
8775 }
8776
8777 uint32_t result = hash_field_ >> String::kHashShift;
8778 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8779 return result;
8780 }
8781
8782
8783 uint32_t HashForObject(Object* other) {
8784 return String::cast(other)->Hash();
8785 }
8786
8787 Vector<const Char> string_;
8788 uint32_t hash_field_;
8789};
8790
8791
8792
8793class AsciiSymbolKey : public SequentialSymbolKey<char> {
8794 public:
8795 explicit AsciiSymbolKey(Vector<const char> str)
8796 : SequentialSymbolKey<char>(str) { }
8797
8798 bool IsMatch(Object* string) {
8799 return String::cast(string)->IsAsciiEqualTo(string_);
8800 }
8801
8802 MaybeObject* AsObject() {
8803 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008804 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008805 }
8806};
8807
8808
Ben Murdoch257744e2011-11-30 15:57:28 +00008809class SubStringAsciiSymbolKey : public HashTableKey {
8810 public:
8811 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
8812 int from,
8813 int length)
8814 : string_(string), from_(from), length_(length) { }
8815
8816 uint32_t Hash() {
8817 ASSERT(length_ >= 0);
8818 ASSERT(from_ + length_ <= string_->length());
8819 StringHasher hasher(length_);
8820
8821 // Very long strings have a trivial hash that doesn't inspect the
8822 // string contents.
8823 if (hasher.has_trivial_hash()) {
8824 hash_field_ = hasher.GetHashField();
8825 } else {
8826 int i = 0;
8827 // Do the iterative array index computation as long as there is a
8828 // chance this is an array index.
8829 while (i < length_ && hasher.is_array_index()) {
8830 hasher.AddCharacter(static_cast<uc32>(
8831 string_->SeqAsciiStringGet(i + from_)));
8832 i++;
8833 }
8834
8835 // Process the remaining characters without updating the array
8836 // index.
8837 while (i < length_) {
8838 hasher.AddCharacterNoIndex(static_cast<uc32>(
8839 string_->SeqAsciiStringGet(i + from_)));
8840 i++;
8841 }
8842 hash_field_ = hasher.GetHashField();
8843 }
8844
8845 uint32_t result = hash_field_ >> String::kHashShift;
8846 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
8847 return result;
8848 }
8849
8850
8851 uint32_t HashForObject(Object* other) {
8852 return String::cast(other)->Hash();
8853 }
8854
8855 bool IsMatch(Object* string) {
8856 Vector<const char> chars(string_->GetChars() + from_, length_);
8857 return String::cast(string)->IsAsciiEqualTo(chars);
8858 }
8859
8860 MaybeObject* AsObject() {
8861 if (hash_field_ == 0) Hash();
8862 Vector<const char> chars(string_->GetChars() + from_, length_);
8863 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
8864 }
8865
8866 private:
8867 Handle<SeqAsciiString> string_;
8868 int from_;
8869 int length_;
8870 uint32_t hash_field_;
8871};
8872
8873
Steve Block9fac8402011-05-12 15:51:54 +01008874class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
8875 public:
8876 explicit TwoByteSymbolKey(Vector<const uc16> str)
8877 : SequentialSymbolKey<uc16>(str) { }
8878
8879 bool IsMatch(Object* string) {
8880 return String::cast(string)->IsTwoByteEqualTo(string_);
8881 }
8882
8883 MaybeObject* AsObject() {
8884 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01008885 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01008886 }
8887};
8888
8889
Steve Blocka7e24c12009-10-30 11:49:00 +00008890// SymbolKey carries a string/symbol object as key.
8891class SymbolKey : public HashTableKey {
8892 public:
Steve Block44f0eee2011-05-26 01:26:41 +01008893 explicit SymbolKey(String* string)
8894 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00008895
8896 bool IsMatch(Object* string) {
8897 return String::cast(string)->Equals(string_);
8898 }
8899
8900 uint32_t Hash() { return string_->Hash(); }
8901
8902 uint32_t HashForObject(Object* other) {
8903 return String::cast(other)->Hash();
8904 }
8905
John Reck59135872010-11-02 12:39:01 -07008906 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01008907 // Attempt to flatten the string, so that symbols will most often
8908 // be flat strings.
8909 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01008910 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00008911 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01008912 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00008913 if (map != NULL) {
8914 string_->set_map(map);
8915 ASSERT(string_->IsSymbol());
8916 return string_;
8917 }
8918 // Otherwise allocate a new symbol.
8919 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01008920 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00008921 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00008922 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00008923 }
8924
8925 static uint32_t StringHash(Object* obj) {
8926 return String::cast(obj)->Hash();
8927 }
8928
8929 String* string_;
8930};
8931
8932
8933template<typename Shape, typename Key>
8934void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
8935 IteratePointers(v, 0, kElementsStartOffset);
8936}
8937
8938
8939template<typename Shape, typename Key>
8940void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
8941 IteratePointers(v,
8942 kElementsStartOffset,
8943 kHeaderSize + length() * kPointerSize);
8944}
8945
8946
8947template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07008948MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
8949 PretenureFlag pretenure) {
Steve Block6ded16b2010-05-10 14:33:55 +01008950 const int kMinCapacity = 32;
8951 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
8952 if (capacity < kMinCapacity) {
8953 capacity = kMinCapacity; // Guarantee min capacity.
Leon Clarkee46be812010-01-19 14:06:41 +00008954 } else if (capacity > HashTable::kMaxCapacity) {
8955 return Failure::OutOfMemoryException();
8956 }
8957
John Reck59135872010-11-02 12:39:01 -07008958 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01008959 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
8960 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07008961 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00008962 }
John Reck59135872010-11-02 12:39:01 -07008963 HashTable::cast(obj)->SetNumberOfElements(0);
8964 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
8965 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00008966 return obj;
8967}
8968
8969
Leon Clarkee46be812010-01-19 14:06:41 +00008970// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01008971int StringDictionary::FindEntry(String* key) {
8972 if (!key->IsSymbol()) {
8973 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
8974 }
8975
8976 // Optimized for symbol key. Knowledge of the key type allows:
8977 // 1. Move the check if the key is a symbol out of the loop.
8978 // 2. Avoid comparing hash codes in symbol to symbol comparision.
8979 // 3. Detect a case when a dictionary key is not a symbol but the key is.
8980 // In case of positive result the dictionary key may be replaced by
8981 // the symbol with minimal performance penalty. It gives a chance to
8982 // perform further lookups in code stubs (and significant performance boost
8983 // a certain style of code).
8984
8985 // EnsureCapacity will guarantee the hash table is never full.
8986 uint32_t capacity = Capacity();
8987 uint32_t entry = FirstProbe(key->Hash(), capacity);
8988 uint32_t count = 1;
8989
8990 while (true) {
8991 int index = EntryToIndex(entry);
8992 Object* element = get(index);
8993 if (element->IsUndefined()) break; // Empty entry.
8994 if (key == element) return entry;
8995 if (!element->IsSymbol() &&
8996 !element->IsNull() &&
8997 String::cast(element)->Equals(key)) {
8998 // Replace a non-symbol key by the equivalent symbol for faster further
8999 // lookups.
9000 set(index, key);
9001 return entry;
9002 }
9003 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9004 entry = NextProbe(entry, count++, capacity);
9005 }
9006 return kNotFound;
9007}
9008
9009
Steve Blocka7e24c12009-10-30 11:49:00 +00009010template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009011MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009012 int capacity = Capacity();
9013 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00009014 int nod = NumberOfDeletedElements();
9015 // Return if:
9016 // 50% is still free after adding n elements and
9017 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01009018 if (nod <= (capacity - nof) >> 1) {
9019 int needed_free = nof >> 1;
9020 if (nof + needed_free <= capacity) return this;
9021 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009022
Steve Block6ded16b2010-05-10 14:33:55 +01009023 const int kMinCapacityForPretenure = 256;
9024 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +01009025 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07009026 Object* obj;
9027 { MaybeObject* maybe_obj =
9028 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9029 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9030 }
Leon Clarke4515c472010-02-03 11:58:03 +00009031
9032 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00009033 HashTable* table = HashTable::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00009034 WriteBarrierMode mode = table->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009035
9036 // Copy prefix to new array.
9037 for (int i = kPrefixStartIndex;
9038 i < kPrefixStartIndex + Shape::kPrefixSize;
9039 i++) {
9040 table->set(i, get(i), mode);
9041 }
9042 // Rehash the elements.
9043 for (int i = 0; i < capacity; i++) {
9044 uint32_t from_index = EntryToIndex(i);
9045 Object* k = get(from_index);
9046 if (IsKey(k)) {
9047 uint32_t hash = Shape::HashForObject(key, k);
9048 uint32_t insertion_index =
9049 EntryToIndex(table->FindInsertionEntry(hash));
9050 for (int j = 0; j < Shape::kEntrySize; j++) {
9051 table->set(insertion_index + j, get(from_index + j), mode);
9052 }
9053 }
9054 }
9055 table->SetNumberOfElements(NumberOfElements());
Leon Clarkee46be812010-01-19 14:06:41 +00009056 table->SetNumberOfDeletedElements(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00009057 return table;
9058}
9059
9060
9061template<typename Shape, typename Key>
9062uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
9063 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00009064 uint32_t entry = FirstProbe(hash, capacity);
9065 uint32_t count = 1;
9066 // EnsureCapacity will guarantee the hash table is never full.
9067 while (true) {
9068 Object* element = KeyAt(entry);
9069 if (element->IsUndefined() || element->IsNull()) break;
9070 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009071 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009072 return entry;
9073}
9074
9075// Force instantiation of template instances class.
9076// Please note this list is compiler dependent.
9077
9078template class HashTable<SymbolTableShape, HashTableKey*>;
9079
9080template class HashTable<CompilationCacheShape, HashTableKey*>;
9081
9082template class HashTable<MapCacheShape, HashTableKey*>;
9083
9084template class Dictionary<StringDictionaryShape, String*>;
9085
9086template class Dictionary<NumberDictionaryShape, uint32_t>;
9087
John Reck59135872010-11-02 12:39:01 -07009088template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00009089 int);
9090
John Reck59135872010-11-02 12:39:01 -07009091template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00009092 int);
9093
John Reck59135872010-11-02 12:39:01 -07009094template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +00009095 uint32_t, Object*);
9096
9097template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9098 Object*);
9099
9100template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9101 Object*);
9102
9103template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
9104 FixedArray*, PropertyAttributes);
9105
9106template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9107 int, JSObject::DeleteMode);
9108
9109template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
9110 int, JSObject::DeleteMode);
9111
9112template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch6d7cb002011-08-04 19:25:22 +01009113 FixedArray*, int);
Steve Blocka7e24c12009-10-30 11:49:00 +00009114
9115template int
9116Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
9117 PropertyAttributes);
9118
John Reck59135872010-11-02 12:39:01 -07009119template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00009120 String*, Object*, PropertyDetails);
9121
John Reck59135872010-11-02 12:39:01 -07009122template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +00009123Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
9124
9125template int
9126Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
9127 PropertyAttributes);
9128
John Reck59135872010-11-02 12:39:01 -07009129template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +00009130 uint32_t, Object*, PropertyDetails);
9131
John Reck59135872010-11-02 12:39:01 -07009132template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
9133 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +00009134
John Reck59135872010-11-02 12:39:01 -07009135template MaybeObject* Dictionary<StringDictionaryShape, String*>::
9136 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +00009137
John Reck59135872010-11-02 12:39:01 -07009138template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00009139 uint32_t, Object*, PropertyDetails, uint32_t);
9140
John Reck59135872010-11-02 12:39:01 -07009141template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +00009142 String*, Object*, PropertyDetails, uint32_t);
9143
9144template
9145int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
9146
9147template
9148int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
9149
Leon Clarkee46be812010-01-19 14:06:41 +00009150template
9151int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
9152
9153
Steve Blocka7e24c12009-10-30 11:49:00 +00009154// Collates undefined and unexisting elements below limit from position
9155// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -07009156MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009157 ASSERT(HasDictionaryElements());
9158 // Must stay in dictionary mode, either because of requires_slow_elements,
9159 // or because we are not going to sort (and therefore compact) all of the
9160 // elements.
9161 NumberDictionary* dict = element_dictionary();
9162 HeapNumber* result_double = NULL;
9163 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9164 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -07009165 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009166 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07009167 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9168 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009169 result_double = HeapNumber::cast(new_double);
9170 }
9171
John Reck59135872010-11-02 12:39:01 -07009172 Object* obj;
9173 { MaybeObject* maybe_obj =
9174 NumberDictionary::Allocate(dict->NumberOfElements());
9175 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9176 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009177 NumberDictionary* new_dict = NumberDictionary::cast(obj);
9178
9179 AssertNoAllocation no_alloc;
9180
9181 uint32_t pos = 0;
9182 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01009183 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +00009184 for (int i = 0; i < capacity; i++) {
9185 Object* k = dict->KeyAt(i);
9186 if (dict->IsKey(k)) {
9187 ASSERT(k->IsNumber());
9188 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
9189 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
9190 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
9191 Object* value = dict->ValueAt(i);
9192 PropertyDetails details = dict->DetailsAt(i);
9193 if (details.type() == CALLBACKS) {
9194 // Bail out and do the sorting of undefineds and array holes in JS.
9195 return Smi::FromInt(-1);
9196 }
9197 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -07009198 // In the following we assert that adding the entry to the new dictionary
9199 // does not cause GC. This is the case because we made sure to allocate
9200 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +00009201 if (key < limit) {
9202 if (value->IsUndefined()) {
9203 undefs++;
9204 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01009205 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9206 // Adding an entry with the key beyond smi-range requires
9207 // allocation. Bailout.
9208 return Smi::FromInt(-1);
9209 }
John Reck59135872010-11-02 12:39:01 -07009210 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009211 pos++;
9212 }
9213 } else {
Steve Block1e0659c2011-05-24 12:43:12 +01009214 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
9215 // Adding an entry with the key beyond smi-range requires
9216 // allocation. Bailout.
9217 return Smi::FromInt(-1);
9218 }
John Reck59135872010-11-02 12:39:01 -07009219 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009220 }
9221 }
9222 }
9223
9224 uint32_t result = pos;
9225 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009226 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009227 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +01009228 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
9229 // Adding an entry with the key beyond smi-range requires
9230 // allocation. Bailout.
9231 return Smi::FromInt(-1);
9232 }
Steve Block44f0eee2011-05-26 01:26:41 +01009233 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -07009234 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00009235 pos++;
9236 undefs--;
9237 }
9238
9239 set_elements(new_dict);
9240
9241 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9242 return Smi::FromInt(static_cast<int>(result));
9243 }
9244
9245 ASSERT_NE(NULL, result_double);
9246 result_double->set_value(static_cast<double>(result));
9247 return result_double;
9248}
9249
9250
9251// Collects all defined (non-hole) and non-undefined (array) elements at
9252// the start of the elements array.
9253// If the object is in dictionary mode, it is converted to fast elements
9254// mode.
John Reck59135872010-11-02 12:39:01 -07009255MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Steve Block44f0eee2011-05-26 01:26:41 +01009256 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009257
Ben Murdoch8b112d22011-06-08 16:22:53 +01009258 Heap* heap = GetHeap();
9259
Steve Blocka7e24c12009-10-30 11:49:00 +00009260 if (HasDictionaryElements()) {
9261 // Convert to fast elements containing only the existing properties.
9262 // Ordering is irrelevant, since we are going to sort anyway.
9263 NumberDictionary* dict = element_dictionary();
9264 if (IsJSArray() || dict->requires_slow_elements() ||
9265 dict->max_number_key() >= limit) {
9266 return PrepareSlowElementsForSort(limit);
9267 }
9268 // Convert to fast elements.
9269
John Reck59135872010-11-02 12:39:01 -07009270 Object* obj;
9271 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
9272 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9273 }
Steve Block8defd9f2010-07-08 12:39:36 +01009274 Map* new_map = Map::cast(obj);
9275
Steve Block44f0eee2011-05-26 01:26:41 +01009276 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -07009277 Object* new_array;
9278 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +01009279 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -07009280 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
9281 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009282 FixedArray* fast_elements = FixedArray::cast(new_array);
9283 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +01009284
9285 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +00009286 set_elements(fast_elements);
Iain Merrick75681382010-08-19 15:07:18 +01009287 } else {
John Reck59135872010-11-02 12:39:01 -07009288 Object* obj;
9289 { MaybeObject* maybe_obj = EnsureWritableFastElements();
9290 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9291 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009292 }
9293 ASSERT(HasFastElements());
9294
9295 // Collect holes at the end, undefined before that and the rest at the
9296 // start, and return the number of non-hole, non-undefined values.
9297
9298 FixedArray* elements = FixedArray::cast(this->elements());
9299 uint32_t elements_length = static_cast<uint32_t>(elements->length());
9300 if (limit > elements_length) {
9301 limit = elements_length ;
9302 }
9303 if (limit == 0) {
9304 return Smi::FromInt(0);
9305 }
9306
9307 HeapNumber* result_double = NULL;
9308 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
9309 // Pessimistically allocate space for return value before
9310 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -07009311 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +01009312 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -07009313 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
9314 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009315 result_double = HeapNumber::cast(new_double);
9316 }
9317
9318 AssertNoAllocation no_alloc;
9319
9320 // Split elements into defined, undefined and the_hole, in that order.
9321 // Only count locations for undefined and the hole, and fill them afterwards.
Leon Clarke4515c472010-02-03 11:58:03 +00009322 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009323 unsigned int undefs = limit;
9324 unsigned int holes = limit;
9325 // Assume most arrays contain no holes and undefined values, so minimize the
9326 // number of stores of non-undefined, non-the-hole values.
9327 for (unsigned int i = 0; i < undefs; i++) {
9328 Object* current = elements->get(i);
9329 if (current->IsTheHole()) {
9330 holes--;
9331 undefs--;
9332 } else if (current->IsUndefined()) {
9333 undefs--;
9334 } else {
9335 continue;
9336 }
9337 // Position i needs to be filled.
9338 while (undefs > i) {
9339 current = elements->get(undefs);
9340 if (current->IsTheHole()) {
9341 holes--;
9342 undefs--;
9343 } else if (current->IsUndefined()) {
9344 undefs--;
9345 } else {
9346 elements->set(i, current, write_barrier);
9347 break;
9348 }
9349 }
9350 }
9351 uint32_t result = undefs;
9352 while (undefs < holes) {
9353 elements->set_undefined(undefs);
9354 undefs++;
9355 }
9356 while (holes < limit) {
9357 elements->set_the_hole(holes);
9358 holes++;
9359 }
9360
9361 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
9362 return Smi::FromInt(static_cast<int>(result));
9363 }
9364 ASSERT_NE(NULL, result_double);
9365 result_double->set_value(static_cast<double>(result));
9366 return result_double;
9367}
9368
9369
Steve Block44f0eee2011-05-26 01:26:41 +01009370Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009371 uint8_t clamped_value = 0;
9372 if (index < static_cast<uint32_t>(length())) {
9373 if (value->IsSmi()) {
9374 int int_value = Smi::cast(value)->value();
9375 if (int_value < 0) {
9376 clamped_value = 0;
9377 } else if (int_value > 255) {
9378 clamped_value = 255;
9379 } else {
9380 clamped_value = static_cast<uint8_t>(int_value);
9381 }
9382 } else if (value->IsHeapNumber()) {
9383 double double_value = HeapNumber::cast(value)->value();
9384 if (!(double_value > 0)) {
9385 // NaN and less than zero clamp to zero.
9386 clamped_value = 0;
9387 } else if (double_value > 255) {
9388 // Greater than 255 clamp to 255.
9389 clamped_value = 255;
9390 } else {
9391 // Other doubles are rounded to the nearest integer.
9392 clamped_value = static_cast<uint8_t>(double_value + 0.5);
9393 }
9394 } else {
9395 // Clamp undefined to zero (default). All other types have been
9396 // converted to a number type further up in the call chain.
9397 ASSERT(value->IsUndefined());
9398 }
9399 set(index, clamped_value);
9400 }
9401 return Smi::FromInt(clamped_value);
9402}
9403
9404
Steve Block3ce2e202009-11-05 08:53:23 +00009405template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +01009406static MaybeObject* ExternalArrayIntSetter(Heap* heap,
9407 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -07009408 uint32_t index,
9409 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009410 ValueType cast_value = 0;
9411 if (index < static_cast<uint32_t>(receiver->length())) {
9412 if (value->IsSmi()) {
9413 int int_value = Smi::cast(value)->value();
9414 cast_value = static_cast<ValueType>(int_value);
9415 } else if (value->IsHeapNumber()) {
9416 double double_value = HeapNumber::cast(value)->value();
9417 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
9418 } else {
9419 // Clamp undefined to zero (default). All other types have been
9420 // converted to a number type further up in the call chain.
9421 ASSERT(value->IsUndefined());
9422 }
9423 receiver->set(index, cast_value);
9424 }
Steve Block44f0eee2011-05-26 01:26:41 +01009425 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009426}
9427
9428
John Reck59135872010-11-02 12:39:01 -07009429MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009430 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009431 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009432}
9433
9434
John Reck59135872010-11-02 12:39:01 -07009435MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
9436 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009437 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009438 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009439}
9440
9441
John Reck59135872010-11-02 12:39:01 -07009442MaybeObject* ExternalShortArray::SetValue(uint32_t index,
9443 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009444 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009445 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009446}
9447
9448
John Reck59135872010-11-02 12:39:01 -07009449MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
9450 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009451 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009452 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009453}
9454
9455
John Reck59135872010-11-02 12:39:01 -07009456MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009457 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +01009458 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +00009459}
9460
9461
John Reck59135872010-11-02 12:39:01 -07009462MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009463 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009464 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009465 if (index < static_cast<uint32_t>(length())) {
9466 if (value->IsSmi()) {
9467 int int_value = Smi::cast(value)->value();
9468 cast_value = static_cast<uint32_t>(int_value);
9469 } else if (value->IsHeapNumber()) {
9470 double double_value = HeapNumber::cast(value)->value();
9471 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
9472 } else {
9473 // Clamp undefined to zero (default). All other types have been
9474 // converted to a number type further up in the call chain.
9475 ASSERT(value->IsUndefined());
9476 }
9477 set(index, cast_value);
9478 }
Steve Block44f0eee2011-05-26 01:26:41 +01009479 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009480}
9481
9482
John Reck59135872010-11-02 12:39:01 -07009483MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +00009484 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009485 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00009486 if (index < static_cast<uint32_t>(length())) {
9487 if (value->IsSmi()) {
9488 int int_value = Smi::cast(value)->value();
9489 cast_value = static_cast<float>(int_value);
9490 } else if (value->IsHeapNumber()) {
9491 double double_value = HeapNumber::cast(value)->value();
9492 cast_value = static_cast<float>(double_value);
9493 } else {
9494 // Clamp undefined to zero (default). All other types have been
9495 // converted to a number type further up in the call chain.
9496 ASSERT(value->IsUndefined());
9497 }
9498 set(index, cast_value);
9499 }
Steve Block44f0eee2011-05-26 01:26:41 +01009500 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +00009501}
9502
9503
Ben Murdoch257744e2011-11-30 15:57:28 +00009504MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
9505 double double_value = 0;
9506 Heap* heap = GetHeap();
9507 if (index < static_cast<uint32_t>(length())) {
9508 if (value->IsSmi()) {
9509 int int_value = Smi::cast(value)->value();
9510 double_value = static_cast<double>(int_value);
9511 } else if (value->IsHeapNumber()) {
9512 double_value = HeapNumber::cast(value)->value();
9513 } else {
9514 // Clamp undefined to zero (default). All other types have been
9515 // converted to a number type further up in the call chain.
9516 ASSERT(value->IsUndefined());
9517 }
9518 set(index, double_value);
9519 }
9520 return heap->AllocateHeapNumber(double_value);
9521}
9522
9523
Ben Murdochb0fe1622011-05-05 13:52:32 +01009524JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009525 ASSERT(!HasFastProperties());
9526 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +01009527 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +00009528}
9529
9530
John Reck59135872010-11-02 12:39:01 -07009531MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009532 ASSERT(!HasFastProperties());
9533 int entry = property_dictionary()->FindEntry(name);
9534 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009535 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07009536 Object* cell;
9537 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +01009538 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -07009539 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
9540 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009541 PropertyDetails details(NONE, NORMAL);
9542 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -07009543 Object* dictionary;
9544 { MaybeObject* maybe_dictionary =
9545 property_dictionary()->Add(name, cell, details);
9546 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
9547 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009548 set_properties(StringDictionary::cast(dictionary));
9549 return cell;
9550 } else {
9551 Object* value = property_dictionary()->ValueAt(entry);
9552 ASSERT(value->IsJSGlobalPropertyCell());
9553 return value;
9554 }
9555}
9556
9557
John Reck59135872010-11-02 12:39:01 -07009558MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009559 SymbolKey key(string);
9560 return LookupKey(&key, s);
9561}
9562
9563
Steve Blockd0582a62009-12-15 09:54:21 +00009564// This class is used for looking up two character strings in the symbol table.
9565// If we don't have a hit we don't want to waste much time so we unroll the
9566// string hash calculation loop here for speed. Doesn't work if the two
9567// characters form a decimal integer, since such strings have a different hash
9568// algorithm.
9569class TwoCharHashTableKey : public HashTableKey {
9570 public:
9571 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
9572 : c1_(c1), c2_(c2) {
9573 // Char 1.
9574 uint32_t hash = c1 + (c1 << 10);
9575 hash ^= hash >> 6;
9576 // Char 2.
9577 hash += c2;
9578 hash += hash << 10;
9579 hash ^= hash >> 6;
9580 // GetHash.
9581 hash += hash << 3;
9582 hash ^= hash >> 11;
9583 hash += hash << 15;
9584 if (hash == 0) hash = 27;
9585#ifdef DEBUG
9586 StringHasher hasher(2);
9587 hasher.AddCharacter(c1);
9588 hasher.AddCharacter(c2);
9589 // If this assert fails then we failed to reproduce the two-character
9590 // version of the string hashing algorithm above. One reason could be
9591 // that we were passed two digits as characters, since the hash
9592 // algorithm is different in that case.
9593 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
9594#endif
9595 hash_ = hash;
9596 }
9597
9598 bool IsMatch(Object* o) {
9599 if (!o->IsString()) return false;
9600 String* other = String::cast(o);
9601 if (other->length() != 2) return false;
9602 if (other->Get(0) != c1_) return false;
9603 return other->Get(1) == c2_;
9604 }
9605
9606 uint32_t Hash() { return hash_; }
9607 uint32_t HashForObject(Object* key) {
9608 if (!key->IsString()) return 0;
9609 return String::cast(key)->Hash();
9610 }
9611
9612 Object* AsObject() {
9613 // The TwoCharHashTableKey is only used for looking in the symbol
9614 // table, not for adding to it.
9615 UNREACHABLE();
9616 return NULL;
9617 }
9618 private:
9619 uint32_t c1_;
9620 uint32_t c2_;
9621 uint32_t hash_;
9622};
9623
9624
Steve Blocka7e24c12009-10-30 11:49:00 +00009625bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
9626 SymbolKey key(string);
9627 int entry = FindEntry(&key);
9628 if (entry == kNotFound) {
9629 return false;
9630 } else {
9631 String* result = String::cast(KeyAt(entry));
9632 ASSERT(StringShape(result).IsSymbol());
9633 *symbol = result;
9634 return true;
9635 }
9636}
9637
9638
Steve Blockd0582a62009-12-15 09:54:21 +00009639bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
9640 uint32_t c2,
9641 String** symbol) {
9642 TwoCharHashTableKey key(c1, c2);
9643 int entry = FindEntry(&key);
9644 if (entry == kNotFound) {
9645 return false;
9646 } else {
9647 String* result = String::cast(KeyAt(entry));
9648 ASSERT(StringShape(result).IsSymbol());
9649 *symbol = result;
9650 return true;
9651 }
9652}
9653
9654
John Reck59135872010-11-02 12:39:01 -07009655MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009656 Utf8SymbolKey key(str);
9657 return LookupKey(&key, s);
9658}
9659
9660
Steve Block9fac8402011-05-12 15:51:54 +01009661MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
9662 Object** s) {
9663 AsciiSymbolKey key(str);
9664 return LookupKey(&key, s);
9665}
9666
9667
Ben Murdoch257744e2011-11-30 15:57:28 +00009668MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
9669 int from,
9670 int length,
9671 Object** s) {
9672 SubStringAsciiSymbolKey key(str, from, length);
9673 return LookupKey(&key, s);
9674}
9675
9676
Steve Block9fac8402011-05-12 15:51:54 +01009677MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
9678 Object** s) {
9679 TwoByteSymbolKey key(str);
9680 return LookupKey(&key, s);
9681}
9682
John Reck59135872010-11-02 12:39:01 -07009683MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009684 int entry = FindEntry(key);
9685
9686 // Symbol already in table.
9687 if (entry != kNotFound) {
9688 *s = KeyAt(entry);
9689 return this;
9690 }
9691
9692 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -07009693 Object* obj;
9694 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
9695 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9696 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009697
9698 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -07009699 Object* symbol;
9700 { MaybeObject* maybe_symbol = key->AsObject();
9701 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
9702 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009703
9704 // If the symbol table grew as part of EnsureCapacity, obj is not
9705 // the current symbol table and therefore we cannot use
9706 // SymbolTable::cast here.
9707 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
9708
9709 // Add the new symbol and return it along with the symbol table.
9710 entry = table->FindInsertionEntry(key->Hash());
9711 table->set(EntryToIndex(entry), symbol);
9712 table->ElementAdded();
9713 *s = symbol;
9714 return table;
9715}
9716
9717
9718Object* CompilationCacheTable::Lookup(String* src) {
9719 StringKey key(src);
9720 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009721 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009722 return get(EntryToIndex(entry) + 1);
9723}
9724
9725
Steve Block1e0659c2011-05-24 12:43:12 +01009726Object* CompilationCacheTable::LookupEval(String* src,
9727 Context* context,
9728 StrictModeFlag strict_mode) {
9729 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009730 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01009731 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009732 return get(EntryToIndex(entry) + 1);
9733}
9734
9735
9736Object* CompilationCacheTable::LookupRegExp(String* src,
9737 JSRegExp::Flags flags) {
9738 RegExpKey key(src, flags);
9739 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009740 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009741 return get(EntryToIndex(entry) + 1);
9742}
9743
9744
John Reck59135872010-11-02 12:39:01 -07009745MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009746 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -07009747 Object* obj;
9748 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9749 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9750 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009751
9752 CompilationCacheTable* cache =
9753 reinterpret_cast<CompilationCacheTable*>(obj);
9754 int entry = cache->FindInsertionEntry(key.Hash());
9755 cache->set(EntryToIndex(entry), src);
9756 cache->set(EntryToIndex(entry) + 1, value);
9757 cache->ElementAdded();
9758 return cache;
9759}
9760
9761
John Reck59135872010-11-02 12:39:01 -07009762MaybeObject* CompilationCacheTable::PutEval(String* src,
9763 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +01009764 SharedFunctionInfo* value) {
9765 StringSharedKey key(src,
9766 context->closure()->shared(),
9767 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -07009768 Object* obj;
9769 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9770 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9771 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009772
9773 CompilationCacheTable* cache =
9774 reinterpret_cast<CompilationCacheTable*>(obj);
9775 int entry = cache->FindInsertionEntry(key.Hash());
9776
John Reck59135872010-11-02 12:39:01 -07009777 Object* k;
9778 { MaybeObject* maybe_k = key.AsObject();
9779 if (!maybe_k->ToObject(&k)) return maybe_k;
9780 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009781
9782 cache->set(EntryToIndex(entry), k);
9783 cache->set(EntryToIndex(entry) + 1, value);
9784 cache->ElementAdded();
9785 return cache;
9786}
9787
9788
John Reck59135872010-11-02 12:39:01 -07009789MaybeObject* CompilationCacheTable::PutRegExp(String* src,
9790 JSRegExp::Flags flags,
9791 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009792 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -07009793 Object* obj;
9794 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9795 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9796 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009797
9798 CompilationCacheTable* cache =
9799 reinterpret_cast<CompilationCacheTable*>(obj);
9800 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +00009801 // We store the value in the key slot, and compare the search key
9802 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +00009803 cache->set(EntryToIndex(entry), value);
9804 cache->set(EntryToIndex(entry) + 1, value);
9805 cache->ElementAdded();
9806 return cache;
9807}
9808
9809
Ben Murdochb0fe1622011-05-05 13:52:32 +01009810void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009811 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +01009812 for (int entry = 0, size = Capacity(); entry < size; entry++) {
9813 int entry_index = EntryToIndex(entry);
9814 int value_index = entry_index + 1;
9815 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +01009816 fast_set(this, entry_index, null_value);
9817 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +01009818 ElementRemoved();
9819 }
9820 }
9821 return;
9822}
9823
9824
Steve Blocka7e24c12009-10-30 11:49:00 +00009825// SymbolsKey used for HashTable where key is array of symbols.
9826class SymbolsKey : public HashTableKey {
9827 public:
9828 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
9829
9830 bool IsMatch(Object* symbols) {
9831 FixedArray* o = FixedArray::cast(symbols);
9832 int len = symbols_->length();
9833 if (o->length() != len) return false;
9834 for (int i = 0; i < len; i++) {
9835 if (o->get(i) != symbols_->get(i)) return false;
9836 }
9837 return true;
9838 }
9839
9840 uint32_t Hash() { return HashForObject(symbols_); }
9841
9842 uint32_t HashForObject(Object* obj) {
9843 FixedArray* symbols = FixedArray::cast(obj);
9844 int len = symbols->length();
9845 uint32_t hash = 0;
9846 for (int i = 0; i < len; i++) {
9847 hash ^= String::cast(symbols->get(i))->Hash();
9848 }
9849 return hash;
9850 }
9851
9852 Object* AsObject() { return symbols_; }
9853
9854 private:
9855 FixedArray* symbols_;
9856};
9857
9858
9859Object* MapCache::Lookup(FixedArray* array) {
9860 SymbolsKey key(array);
9861 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +01009862 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009863 return get(EntryToIndex(entry) + 1);
9864}
9865
9866
John Reck59135872010-11-02 12:39:01 -07009867MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009868 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -07009869 Object* obj;
9870 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
9871 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9872 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009873
9874 MapCache* cache = reinterpret_cast<MapCache*>(obj);
9875 int entry = cache->FindInsertionEntry(key.Hash());
9876 cache->set(EntryToIndex(entry), array);
9877 cache->set(EntryToIndex(entry) + 1, value);
9878 cache->ElementAdded();
9879 return cache;
9880}
9881
9882
9883template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009884MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
9885 Object* obj;
9886 { MaybeObject* maybe_obj =
9887 HashTable<Shape, Key>::Allocate(at_least_space_for);
9888 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009889 }
John Reck59135872010-11-02 12:39:01 -07009890 // Initialize the next enumeration index.
9891 Dictionary<Shape, Key>::cast(obj)->
9892 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +00009893 return obj;
9894}
9895
9896
9897template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009898MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +01009899 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009900 int length = HashTable<Shape, Key>::NumberOfElements();
9901
9902 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -07009903 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009904 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009905 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9906 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009907 FixedArray* iteration_order = FixedArray::cast(obj);
9908 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009909 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009910 }
9911
9912 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +01009913 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -07009914 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9915 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009916 FixedArray* enumeration_order = FixedArray::cast(obj);
9917
9918 // Fill the enumeration order array with property details.
9919 int capacity = HashTable<Shape, Key>::Capacity();
9920 int pos = 0;
9921 for (int i = 0; i < capacity; i++) {
9922 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +00009923 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +00009924 }
9925 }
9926
9927 // Sort the arrays wrt. enumeration order.
9928 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
9929
9930 // Overwrite the enumeration_order with the enumeration indices.
9931 for (int i = 0; i < length; i++) {
9932 int index = Smi::cast(iteration_order->get(i))->value();
9933 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +00009934 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +00009935 }
9936
9937 // Update the dictionary with new indices.
9938 capacity = HashTable<Shape, Key>::Capacity();
9939 pos = 0;
9940 for (int i = 0; i < capacity; i++) {
9941 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
9942 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
9943 PropertyDetails details = DetailsAt(i);
9944 PropertyDetails new_details =
9945 PropertyDetails(details.attributes(), details.type(), enum_index);
9946 DetailsAtPut(i, new_details);
9947 }
9948 }
9949
9950 // Set the next enumeration index.
9951 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
9952 return this;
9953}
9954
9955template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009956MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009957 // Check whether there are enough enumeration indices to add n elements.
9958 if (Shape::kIsEnumerable &&
9959 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
9960 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -07009961 Object* result;
9962 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
9963 if (!maybe_result->ToObject(&result)) return maybe_result;
9964 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009965 }
9966 return HashTable<Shape, Key>::EnsureCapacity(n, key);
9967}
9968
9969
9970void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
9971 // Do nothing if the interval [from, to) is empty.
9972 if (from >= to) return;
9973
Steve Block44f0eee2011-05-26 01:26:41 +01009974 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009975 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01009976 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009977 int capacity = Capacity();
9978 for (int i = 0; i < capacity; i++) {
9979 Object* key = KeyAt(i);
9980 if (key->IsNumber()) {
9981 uint32_t number = static_cast<uint32_t>(key->Number());
9982 if (from <= number && number < to) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009983 SetEntry(i, sentinel, sentinel);
Steve Blocka7e24c12009-10-30 11:49:00 +00009984 removed_entries++;
9985 }
9986 }
9987 }
9988
9989 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +00009990 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +00009991}
9992
9993
9994template<typename Shape, typename Key>
9995Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
9996 JSObject::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01009997 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009998 PropertyDetails details = DetailsAt(entry);
9999 // Ignore attributes if forcing a deletion.
Ben Murdoche0cee9b2011-05-25 10:26:03 +010010000 if (details.IsDontDelete() && mode != JSObject::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010010001 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010002 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010003 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010004 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010010005 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010006}
10007
10008
10009template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010010MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010011 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010012
10013 // If the entry is present set the value;
10014 if (entry != Dictionary<Shape, Key>::kNotFound) {
10015 ValueAtPut(entry, value);
10016 return this;
10017 }
10018
10019 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010020 Object* obj;
10021 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10022 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10023 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010024
John Reck59135872010-11-02 12:39:01 -070010025 Object* k;
10026 { MaybeObject* maybe_k = Shape::AsObject(key);
10027 if (!maybe_k->ToObject(&k)) return maybe_k;
10028 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010029 PropertyDetails details = PropertyDetails(NONE, NORMAL);
10030 return Dictionary<Shape, Key>::cast(obj)->
10031 AddEntry(key, value, details, Shape::Hash(key));
10032}
10033
10034
10035template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010036MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10037 Object* value,
10038 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010039 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010040 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000010041 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010042 Object* obj;
10043 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10044 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10045 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010046 return Dictionary<Shape, Key>::cast(obj)->
10047 AddEntry(key, value, details, Shape::Hash(key));
10048}
10049
10050
10051// Add a key, value pair to the dictionary.
10052template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010053MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
10054 Object* value,
10055 PropertyDetails details,
10056 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010057 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070010058 Object* k;
10059 { MaybeObject* maybe_k = Shape::AsObject(key);
10060 if (!maybe_k->ToObject(&k)) return maybe_k;
10061 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010062
10063 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
10064 // Insert element at empty or deleted entry
10065 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
10066 // Assign an enumeration index to the property and update
10067 // SetNextEnumerationIndex.
10068 int index = NextEnumerationIndex();
10069 details = PropertyDetails(details.attributes(), details.type(), index);
10070 SetNextEnumerationIndex(index + 1);
10071 }
10072 SetEntry(entry, k, value, details);
10073 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
10074 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
10075 HashTable<Shape, Key>::ElementAdded();
10076 return this;
10077}
10078
10079
10080void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
10081 // If the dictionary requires slow elements an element has already
10082 // been added at a high index.
10083 if (requires_slow_elements()) return;
10084 // Check if this index is high enough that we should require slow
10085 // elements.
10086 if (key > kRequiresSlowElementsLimit) {
10087 set_requires_slow_elements();
10088 return;
10089 }
10090 // Update max key value.
10091 Object* max_index_object = get(kMaxNumberKeyIndex);
10092 if (!max_index_object->IsSmi() || max_number_key() < key) {
10093 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000010094 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000010095 }
10096}
10097
10098
John Reck59135872010-11-02 12:39:01 -070010099MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
10100 Object* value,
10101 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010102 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010103 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000010104 return Add(key, value, details);
10105}
10106
10107
John Reck59135872010-11-02 12:39:01 -070010108MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010109 UpdateMaxNumberKey(key);
10110 return AtPut(key, value);
10111}
10112
10113
John Reck59135872010-11-02 12:39:01 -070010114MaybeObject* NumberDictionary::Set(uint32_t key,
10115 Object* value,
10116 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010117 int entry = FindEntry(key);
10118 if (entry == kNotFound) return AddNumberEntry(key, value, details);
10119 // Preserve enumeration index.
10120 details = PropertyDetails(details.attributes(),
10121 details.type(),
10122 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -070010123 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
10124 Object* object_key;
10125 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010010126 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000010127 return this;
10128}
10129
10130
10131
10132template<typename Shape, typename Key>
10133int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
10134 PropertyAttributes filter) {
10135 int capacity = HashTable<Shape, Key>::Capacity();
10136 int result = 0;
10137 for (int i = 0; i < capacity; i++) {
10138 Object* k = HashTable<Shape, Key>::KeyAt(i);
10139 if (HashTable<Shape, Key>::IsKey(k)) {
10140 PropertyDetails details = DetailsAt(i);
10141 if (details.IsDeleted()) continue;
10142 PropertyAttributes attr = details.attributes();
10143 if ((attr & filter) == 0) result++;
10144 }
10145 }
10146 return result;
10147}
10148
10149
10150template<typename Shape, typename Key>
10151int Dictionary<Shape, Key>::NumberOfEnumElements() {
10152 return NumberOfElementsFilterAttributes(
10153 static_cast<PropertyAttributes>(DONT_ENUM));
10154}
10155
10156
10157template<typename Shape, typename Key>
10158void Dictionary<Shape, Key>::CopyKeysTo(FixedArray* storage,
10159 PropertyAttributes filter) {
10160 ASSERT(storage->length() >= NumberOfEnumElements());
10161 int capacity = HashTable<Shape, Key>::Capacity();
10162 int index = 0;
10163 for (int i = 0; i < capacity; i++) {
10164 Object* k = HashTable<Shape, Key>::KeyAt(i);
10165 if (HashTable<Shape, Key>::IsKey(k)) {
10166 PropertyDetails details = DetailsAt(i);
10167 if (details.IsDeleted()) continue;
10168 PropertyAttributes attr = details.attributes();
10169 if ((attr & filter) == 0) storage->set(index++, k);
10170 }
10171 }
10172 storage->SortPairs(storage, index);
10173 ASSERT(storage->length() >= index);
10174}
10175
10176
10177void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
10178 FixedArray* sort_array) {
10179 ASSERT(storage->length() >= NumberOfEnumElements());
10180 int capacity = Capacity();
10181 int index = 0;
10182 for (int i = 0; i < capacity; i++) {
10183 Object* k = KeyAt(i);
10184 if (IsKey(k)) {
10185 PropertyDetails details = DetailsAt(i);
10186 if (details.IsDeleted() || details.IsDontEnum()) continue;
10187 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000010188 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010189 index++;
10190 }
10191 }
10192 storage->SortPairs(sort_array, sort_array->length());
10193 ASSERT(storage->length() >= index);
10194}
10195
10196
10197template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010010198void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000010199 FixedArray* storage,
10200 int index) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010201 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
10202 static_cast<PropertyAttributes>(NONE)));
10203 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000010204 for (int i = 0; i < capacity; i++) {
10205 Object* k = HashTable<Shape, Key>::KeyAt(i);
10206 if (HashTable<Shape, Key>::IsKey(k)) {
10207 PropertyDetails details = DetailsAt(i);
10208 if (details.IsDeleted()) continue;
10209 storage->set(index++, k);
10210 }
10211 }
10212 ASSERT(storage->length() >= index);
10213}
10214
10215
10216// Backwards lookup (slow).
10217template<typename Shape, typename Key>
10218Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
10219 int capacity = HashTable<Shape, Key>::Capacity();
10220 for (int i = 0; i < capacity; i++) {
10221 Object* k = HashTable<Shape, Key>::KeyAt(i);
10222 if (Dictionary<Shape, Key>::IsKey(k)) {
10223 Object* e = ValueAt(i);
10224 if (e->IsJSGlobalPropertyCell()) {
10225 e = JSGlobalPropertyCell::cast(e)->value();
10226 }
10227 if (e == value) return k;
10228 }
10229 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010230 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010010231 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010232}
10233
10234
John Reck59135872010-11-02 12:39:01 -070010235MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000010236 JSObject* obj, int unused_property_fields) {
10237 // Make sure we preserve dictionary representation if there are too many
10238 // descriptors.
10239 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
10240
10241 // Figure out if it is necessary to generate new enumeration indices.
10242 int max_enumeration_index =
10243 NextEnumerationIndex() +
10244 (DescriptorArray::kMaxNumberOfDescriptors -
10245 NumberOfElements());
10246 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070010247 Object* result;
10248 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10249 if (!maybe_result->ToObject(&result)) return maybe_result;
10250 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010251 }
10252
10253 int instance_descriptor_length = 0;
10254 int number_of_fields = 0;
10255
Ben Murdoch8b112d22011-06-08 16:22:53 +010010256 Heap* heap = GetHeap();
10257
Steve Blocka7e24c12009-10-30 11:49:00 +000010258 // Compute the length of the instance descriptor.
10259 int capacity = Capacity();
10260 for (int i = 0; i < capacity; i++) {
10261 Object* k = KeyAt(i);
10262 if (IsKey(k)) {
10263 Object* value = ValueAt(i);
10264 PropertyType type = DetailsAt(i).type();
10265 ASSERT(type != FIELD);
10266 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000010267 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010010268 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000010269 number_of_fields += 1;
10270 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010271 }
10272 }
10273
10274 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070010275 Object* descriptors_unchecked;
10276 { MaybeObject* maybe_descriptors_unchecked =
10277 DescriptorArray::Allocate(instance_descriptor_length);
10278 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
10279 return maybe_descriptors_unchecked;
10280 }
10281 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010282 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
10283
10284 int inobject_props = obj->map()->inobject_properties();
10285 int number_of_allocated_fields =
10286 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010010287 if (number_of_allocated_fields < 0) {
10288 // There is enough inobject space for all fields (including unused).
10289 number_of_allocated_fields = 0;
10290 unused_property_fields = inobject_props - number_of_fields;
10291 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010292
10293 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070010294 Object* fields;
10295 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010010296 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070010297 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
10298 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010299
10300 // Fill in the instance descriptor and the fields.
10301 int next_descriptor = 0;
10302 int current_offset = 0;
10303 for (int i = 0; i < capacity; i++) {
10304 Object* k = KeyAt(i);
10305 if (IsKey(k)) {
10306 Object* value = ValueAt(i);
10307 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070010308 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010010309 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070010310 if (!maybe_key->ToObject(&key)) return maybe_key;
10311 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010312 PropertyDetails details = DetailsAt(i);
10313 PropertyType type = details.type();
10314
Steve Block44f0eee2011-05-26 01:26:41 +010010315 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010316 ConstantFunctionDescriptor d(String::cast(key),
10317 JSFunction::cast(value),
10318 details.attributes(),
10319 details.index());
10320 descriptors->Set(next_descriptor++, &d);
10321 } else if (type == NORMAL) {
10322 if (current_offset < inobject_props) {
10323 obj->InObjectPropertyAtPut(current_offset,
10324 value,
10325 UPDATE_WRITE_BARRIER);
10326 } else {
10327 int offset = current_offset - inobject_props;
10328 FixedArray::cast(fields)->set(offset, value);
10329 }
10330 FieldDescriptor d(String::cast(key),
10331 current_offset++,
10332 details.attributes(),
10333 details.index());
10334 descriptors->Set(next_descriptor++, &d);
10335 } else if (type == CALLBACKS) {
10336 CallbacksDescriptor d(String::cast(key),
10337 value,
10338 details.attributes(),
10339 details.index());
10340 descriptors->Set(next_descriptor++, &d);
10341 } else {
10342 UNREACHABLE();
10343 }
10344 }
10345 }
10346 ASSERT(current_offset == number_of_fields);
10347
10348 descriptors->Sort();
10349 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070010350 Object* new_map;
10351 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
10352 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
10353 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010354
10355 // Transform the object.
10356 obj->set_map(Map::cast(new_map));
10357 obj->map()->set_instance_descriptors(descriptors);
10358 obj->map()->set_unused_property_fields(unused_property_fields);
10359
10360 obj->set_properties(FixedArray::cast(fields));
10361 ASSERT(obj->IsJSObject());
10362
10363 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
10364 // Check that it really works.
10365 ASSERT(obj->HasFastProperties());
10366
10367 return obj;
10368}
10369
10370
10371#ifdef ENABLE_DEBUGGER_SUPPORT
10372// Check if there is a break point at this code position.
10373bool DebugInfo::HasBreakPoint(int code_position) {
10374 // Get the break point info object for this code position.
10375 Object* break_point_info = GetBreakPointInfo(code_position);
10376
10377 // If there is no break point info object or no break points in the break
10378 // point info object there is no break point at this code position.
10379 if (break_point_info->IsUndefined()) return false;
10380 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
10381}
10382
10383
10384// Get the break point info object for this code position.
10385Object* DebugInfo::GetBreakPointInfo(int code_position) {
10386 // Find the index of the break point info object for this code position.
10387 int index = GetBreakPointInfoIndex(code_position);
10388
10389 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010010390 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010391 return BreakPointInfo::cast(break_points()->get(index));
10392}
10393
10394
10395// Clear a break point at the specified code position.
10396void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
10397 int code_position,
10398 Handle<Object> break_point_object) {
10399 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10400 if (break_point_info->IsUndefined()) return;
10401 BreakPointInfo::ClearBreakPoint(
10402 Handle<BreakPointInfo>::cast(break_point_info),
10403 break_point_object);
10404}
10405
10406
10407void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
10408 int code_position,
10409 int source_position,
10410 int statement_position,
10411 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010412 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010413 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
10414 if (!break_point_info->IsUndefined()) {
10415 BreakPointInfo::SetBreakPoint(
10416 Handle<BreakPointInfo>::cast(break_point_info),
10417 break_point_object);
10418 return;
10419 }
10420
10421 // Adding a new break point for a code position which did not have any
10422 // break points before. Try to find a free slot.
10423 int index = kNoBreakPointInfo;
10424 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10425 if (debug_info->break_points()->get(i)->IsUndefined()) {
10426 index = i;
10427 break;
10428 }
10429 }
10430 if (index == kNoBreakPointInfo) {
10431 // No free slot - extend break point info array.
10432 Handle<FixedArray> old_break_points =
10433 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010434 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010010435 isolate->factory()->NewFixedArray(
10436 old_break_points->length() +
10437 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010010438
10439 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000010440 for (int i = 0; i < old_break_points->length(); i++) {
10441 new_break_points->set(i, old_break_points->get(i));
10442 }
10443 index = old_break_points->length();
10444 }
10445 ASSERT(index != kNoBreakPointInfo);
10446
10447 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010010448 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
10449 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000010450 new_break_point_info->set_code_position(Smi::FromInt(code_position));
10451 new_break_point_info->set_source_position(Smi::FromInt(source_position));
10452 new_break_point_info->
10453 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010010454 new_break_point_info->set_break_point_objects(
10455 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010456 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
10457 debug_info->break_points()->set(index, *new_break_point_info);
10458}
10459
10460
10461// Get the break point objects for a code position.
10462Object* DebugInfo::GetBreakPointObjects(int code_position) {
10463 Object* break_point_info = GetBreakPointInfo(code_position);
10464 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010465 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010466 }
10467 return BreakPointInfo::cast(break_point_info)->break_point_objects();
10468}
10469
10470
10471// Get the total number of break points.
10472int DebugInfo::GetBreakPointCount() {
10473 if (break_points()->IsUndefined()) return 0;
10474 int count = 0;
10475 for (int i = 0; i < break_points()->length(); i++) {
10476 if (!break_points()->get(i)->IsUndefined()) {
10477 BreakPointInfo* break_point_info =
10478 BreakPointInfo::cast(break_points()->get(i));
10479 count += break_point_info->GetBreakPointCount();
10480 }
10481 }
10482 return count;
10483}
10484
10485
10486Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
10487 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010488 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010010489 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010490 for (int i = 0; i < debug_info->break_points()->length(); i++) {
10491 if (!debug_info->break_points()->get(i)->IsUndefined()) {
10492 Handle<BreakPointInfo> break_point_info =
10493 Handle<BreakPointInfo>(BreakPointInfo::cast(
10494 debug_info->break_points()->get(i)));
10495 if (BreakPointInfo::HasBreakPointObject(break_point_info,
10496 break_point_object)) {
10497 return *break_point_info;
10498 }
10499 }
10500 }
Steve Block44f0eee2011-05-26 01:26:41 +010010501 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010502}
10503
10504
10505// Find the index of the break point info object for the specified code
10506// position.
10507int DebugInfo::GetBreakPointInfoIndex(int code_position) {
10508 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
10509 for (int i = 0; i < break_points()->length(); i++) {
10510 if (!break_points()->get(i)->IsUndefined()) {
10511 BreakPointInfo* break_point_info =
10512 BreakPointInfo::cast(break_points()->get(i));
10513 if (break_point_info->code_position()->value() == code_position) {
10514 return i;
10515 }
10516 }
10517 }
10518 return kNoBreakPointInfo;
10519}
10520
10521
10522// Remove the specified break point object.
10523void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
10524 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010525 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000010526 // If there are no break points just ignore.
10527 if (break_point_info->break_point_objects()->IsUndefined()) return;
10528 // If there is a single break point clear it if it is the same.
10529 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10530 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010010531 break_point_info->set_break_point_objects(
10532 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010533 }
10534 return;
10535 }
10536 // If there are multiple break points shrink the array
10537 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
10538 Handle<FixedArray> old_array =
10539 Handle<FixedArray>(
10540 FixedArray::cast(break_point_info->break_point_objects()));
10541 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010542 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010543 int found_count = 0;
10544 for (int i = 0; i < old_array->length(); i++) {
10545 if (old_array->get(i) == *break_point_object) {
10546 ASSERT(found_count == 0);
10547 found_count++;
10548 } else {
10549 new_array->set(i - found_count, old_array->get(i));
10550 }
10551 }
10552 // If the break point was found in the list change it.
10553 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
10554}
10555
10556
10557// Add the specified break point object.
10558void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
10559 Handle<Object> break_point_object) {
10560 // If there was no break point objects before just set it.
10561 if (break_point_info->break_point_objects()->IsUndefined()) {
10562 break_point_info->set_break_point_objects(*break_point_object);
10563 return;
10564 }
10565 // If the break point object is the same as before just ignore.
10566 if (break_point_info->break_point_objects() == *break_point_object) return;
10567 // If there was one break point object before replace with array.
10568 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010010569 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000010570 array->set(0, break_point_info->break_point_objects());
10571 array->set(1, *break_point_object);
10572 break_point_info->set_break_point_objects(*array);
10573 return;
10574 }
10575 // If there was more than one break point before extend array.
10576 Handle<FixedArray> old_array =
10577 Handle<FixedArray>(
10578 FixedArray::cast(break_point_info->break_point_objects()));
10579 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010580 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000010581 for (int i = 0; i < old_array->length(); i++) {
10582 // If the break point was there before just ignore.
10583 if (old_array->get(i) == *break_point_object) return;
10584 new_array->set(i, old_array->get(i));
10585 }
10586 // Add the new break point.
10587 new_array->set(old_array->length(), *break_point_object);
10588 break_point_info->set_break_point_objects(*new_array);
10589}
10590
10591
10592bool BreakPointInfo::HasBreakPointObject(
10593 Handle<BreakPointInfo> break_point_info,
10594 Handle<Object> break_point_object) {
10595 // No break point.
10596 if (break_point_info->break_point_objects()->IsUndefined()) return false;
10597 // Single beak point.
10598 if (!break_point_info->break_point_objects()->IsFixedArray()) {
10599 return break_point_info->break_point_objects() == *break_point_object;
10600 }
10601 // Multiple break points.
10602 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
10603 for (int i = 0; i < array->length(); i++) {
10604 if (array->get(i) == *break_point_object) {
10605 return true;
10606 }
10607 }
10608 return false;
10609}
10610
10611
10612// Get the number of break points.
10613int BreakPointInfo::GetBreakPointCount() {
10614 // No break point.
10615 if (break_point_objects()->IsUndefined()) return 0;
10616 // Single beak point.
10617 if (!break_point_objects()->IsFixedArray()) return 1;
10618 // Multiple break points.
10619 return FixedArray::cast(break_point_objects())->length();
10620}
10621#endif
10622
10623
10624} } // namespace v8::internal