blob: 1ab5dd2b835cbf3f7294f1afed59912d55e8ac5c [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
John Reck59135872010-11-02 12:39:01 -070061MUST_USE_RESULT static MaybeObject* CreateJSValue(JSFunction* constructor,
62 Object* value) {
63 Object* result;
Steve Block44f0eee2011-05-26 01:26:41 +010064 { MaybeObject* maybe_result =
65 constructor->GetHeap()->AllocateJSObject(constructor);
John Reck59135872010-11-02 12:39:01 -070066 if (!maybe_result->ToObject(&result)) return maybe_result;
67 }
Steve Blocka7e24c12009-10-30 11:49:00 +000068 JSValue::cast(result)->set_value(value);
69 return result;
70}
71
72
John Reck59135872010-11-02 12:39:01 -070073MaybeObject* Object::ToObject(Context* global_context) {
Steve Blocka7e24c12009-10-30 11:49:00 +000074 if (IsNumber()) {
75 return CreateJSValue(global_context->number_function(), this);
76 } else if (IsBoolean()) {
77 return CreateJSValue(global_context->boolean_function(), this);
78 } else if (IsString()) {
79 return CreateJSValue(global_context->string_function(), this);
80 }
81 ASSERT(IsJSObject());
82 return this;
83}
84
85
John Reck59135872010-11-02 12:39:01 -070086MaybeObject* Object::ToObject() {
Steve Blocka7e24c12009-10-30 11:49:00 +000087 if (IsJSObject()) {
88 return this;
89 } else if (IsNumber()) {
Steve Block44f0eee2011-05-26 01:26:41 +010090 Isolate* isolate = Isolate::Current();
91 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000092 return CreateJSValue(global_context->number_function(), this);
93 } else if (IsBoolean()) {
Steve Block44f0eee2011-05-26 01:26:41 +010094 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
95 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +000096 return CreateJSValue(global_context->boolean_function(), this);
97 } else if (IsString()) {
Steve Block44f0eee2011-05-26 01:26:41 +010098 Isolate* isolate = HeapObject::cast(this)->GetIsolate();
99 Context* global_context = isolate->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000100 return CreateJSValue(global_context->string_function(), this);
101 }
102
103 // Throw a type error.
104 return Failure::InternalError();
105}
106
107
108Object* Object::ToBoolean() {
Steve Block44f0eee2011-05-26 01:26:41 +0100109 if (IsTrue()) return this;
110 if (IsFalse()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000111 if (IsSmi()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100112 return Isolate::Current()->heap()->ToBoolean(Smi::cast(this)->value() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100114 HeapObject* heap_object = HeapObject::cast(this);
115 if (heap_object->IsUndefined() || heap_object->IsNull()) {
116 return heap_object->GetHeap()->false_value();
Steve Block44f0eee2011-05-26 01:26:41 +0100117 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 // Undetectable object is false
Ben Murdoch8b112d22011-06-08 16:22:53 +0100119 if (heap_object->IsUndetectableObject()) {
120 return heap_object->GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100122 if (heap_object->IsString()) {
123 return heap_object->GetHeap()->ToBoolean(
Steve Block44f0eee2011-05-26 01:26:41 +0100124 String::cast(this)->length() != 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000125 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100126 if (heap_object->IsHeapNumber()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000127 return HeapNumber::cast(this)->HeapNumberToBoolean();
128 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100129 return heap_object->GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000130}
131
132
133void Object::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 Object* holder = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100135 if (IsSmi()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000136 Context* global_context = Isolate::Current()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 holder = global_context->number_function()->instance_prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100138 } else {
139 HeapObject* heap_object = HeapObject::cast(this);
140 if (heap_object->IsJSObject()) {
141 return JSObject::cast(this)->Lookup(name, result);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000142 } else if (heap_object->IsJSProxy()) {
143 return result->HandlerResult();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100144 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000145 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100146 if (heap_object->IsString()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100147 holder = global_context->string_function()->instance_prototype();
148 } else if (heap_object->IsHeapNumber()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100149 holder = global_context->number_function()->instance_prototype();
150 } else if (heap_object->IsBoolean()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100151 holder = global_context->boolean_function()->instance_prototype();
152 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 }
154 ASSERT(holder != NULL); // Cannot handle null or undefined.
155 JSObject::cast(holder)->Lookup(name, result);
156}
157
158
John Reck59135872010-11-02 12:39:01 -0700159MaybeObject* Object::GetPropertyWithReceiver(Object* receiver,
160 String* name,
161 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 LookupResult result;
163 Lookup(name, &result);
John Reck59135872010-11-02 12:39:01 -0700164 MaybeObject* value = GetProperty(receiver, &result, name, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 ASSERT(*attributes <= ABSENT);
166 return value;
167}
168
169
John Reck59135872010-11-02 12:39:01 -0700170MaybeObject* Object::GetPropertyWithCallback(Object* receiver,
171 Object* structure,
172 String* name,
173 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +0100174 Isolate* isolate = name->GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000175 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +0000176 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +0000178 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000179 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +0000180 reinterpret_cast<AccessorDescriptor*>(
181 Foreign::cast(structure)->address());
John Reck59135872010-11-02 12:39:01 -0700182 MaybeObject* value = (callback->getter)(receiver, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +0100183 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000184 return value;
185 }
186
187 // api style callbacks.
188 if (structure->IsAccessorInfo()) {
189 AccessorInfo* data = AccessorInfo::cast(structure);
190 Object* fun_obj = data->getter();
191 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000192 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000193 JSObject* self = JSObject::cast(receiver);
194 JSObject* holder_handle = JSObject::cast(holder);
195 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +0100196 LOG(isolate, ApiNamedPropertyAccess("load", self, name));
197 CustomArguments args(isolate, data->data(), self, holder_handle);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198 v8::AccessorInfo info(args.end());
199 v8::Handle<v8::Value> result;
200 {
201 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +0100202 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 result = call_fun(v8::Utils::ToLocal(key), info);
204 }
Steve Block44f0eee2011-05-26 01:26:41 +0100205 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
206 if (result.IsEmpty()) {
207 return isolate->heap()->undefined_value();
208 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000209 return *v8::Utils::OpenHandle(*result);
210 }
211
212 // __defineGetter__ callback
213 if (structure->IsFixedArray()) {
214 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
215 if (getter->IsJSFunction()) {
216 return Object::GetPropertyWithDefinedGetter(receiver,
217 JSFunction::cast(getter));
218 }
219 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +0100220 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 }
222
223 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +0100224 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000225}
226
227
Ben Murdoch257744e2011-11-30 15:57:28 +0000228MaybeObject* Object::GetPropertyWithHandler(Object* receiver_raw,
229 String* name_raw,
230 Object* handler_raw) {
231 Isolate* isolate = name_raw->GetIsolate();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000232 HandleScope scope(isolate);
Ben Murdoch257744e2011-11-30 15:57:28 +0000233 Handle<Object> receiver(receiver_raw);
234 Handle<Object> name(name_raw);
235 Handle<Object> handler(handler_raw);
236
237 // Extract trap function.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000238 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("get");
239 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
240 if (trap->IsUndefined()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000241 // Get the derived `get' property.
242 trap = isolate->derived_get_trap();
243 }
244
245 // Call trap function.
246 Object** args[] = { receiver.location(), name.location() };
247 bool has_exception;
248 Handle<Object> result =
249 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
250 if (has_exception) return Failure::Exception();
251
252 return *result;
253}
254
255
John Reck59135872010-11-02 12:39:01 -0700256MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
257 JSFunction* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000258 HandleScope scope;
259 Handle<JSFunction> fun(JSFunction::cast(getter));
260 Handle<Object> self(receiver);
261#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100262 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000263 // Handle stepping into a getter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +0100264 if (debug->StepInActive()) {
265 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000266 }
267#endif
268 bool has_pending_exception;
269 Handle<Object> result =
270 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
271 // Check for pending exception and return the result.
272 if (has_pending_exception) return Failure::Exception();
273 return *result;
274}
275
276
277// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700278MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 Object* receiver,
280 LookupResult* result,
281 String* name,
282 PropertyAttributes* attributes) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000283 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000284 switch (result->type()) {
285 case CALLBACKS: {
286 // Only allow API accessors.
287 Object* obj = result->GetCallbackObject();
288 if (obj->IsAccessorInfo()) {
289 AccessorInfo* info = AccessorInfo::cast(obj);
290 if (info->all_can_read()) {
291 *attributes = result->GetAttributes();
292 return GetPropertyWithCallback(receiver,
293 result->GetCallbackObject(),
294 name,
295 result->holder());
296 }
297 }
298 break;
299 }
300 case NORMAL:
301 case FIELD:
302 case CONSTANT_FUNCTION: {
303 // Search ALL_CAN_READ accessors in prototype chain.
304 LookupResult r;
305 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000306 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000307 return GetPropertyWithFailedAccessCheck(receiver,
308 &r,
309 name,
310 attributes);
311 }
312 break;
313 }
314 case INTERCEPTOR: {
315 // If the object has an interceptor, try real named properties.
316 // No access check in GetPropertyAttributeWithInterceptor.
317 LookupResult r;
318 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000319 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000320 return GetPropertyWithFailedAccessCheck(receiver,
321 &r,
322 name,
323 attributes);
324 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000325 break;
326 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000327 default:
328 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000329 }
330 }
331
332 // No accessible property found.
333 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100334 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100335 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
336 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000337}
338
339
340PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
341 Object* receiver,
342 LookupResult* result,
343 String* name,
344 bool continue_search) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000345 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 switch (result->type()) {
347 case CALLBACKS: {
348 // Only allow API accessors.
349 Object* obj = result->GetCallbackObject();
350 if (obj->IsAccessorInfo()) {
351 AccessorInfo* info = AccessorInfo::cast(obj);
352 if (info->all_can_read()) {
353 return result->GetAttributes();
354 }
355 }
356 break;
357 }
358
359 case NORMAL:
360 case FIELD:
361 case CONSTANT_FUNCTION: {
362 if (!continue_search) break;
363 // Search ALL_CAN_READ accessors in prototype chain.
364 LookupResult r;
365 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000366 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000367 return GetPropertyAttributeWithFailedAccessCheck(receiver,
368 &r,
369 name,
370 continue_search);
371 }
372 break;
373 }
374
375 case INTERCEPTOR: {
376 // If the object has an interceptor, try real named properties.
377 // No access check in GetPropertyAttributeWithInterceptor.
378 LookupResult r;
379 if (continue_search) {
380 result->holder()->LookupRealNamedProperty(name, &r);
381 } else {
382 result->holder()->LocalLookupRealNamedProperty(name, &r);
383 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000384 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000385 return GetPropertyAttributeWithFailedAccessCheck(receiver,
386 &r,
387 name,
388 continue_search);
389 }
390 break;
391 }
392
Andrei Popescu402d9372010-02-26 13:31:12 +0000393 default:
394 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 }
396 }
397
Ben Murdoch8b112d22011-06-08 16:22:53 +0100398 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 return ABSENT;
400}
401
402
Steve Blocka7e24c12009-10-30 11:49:00 +0000403Object* JSObject::GetNormalizedProperty(LookupResult* result) {
404 ASSERT(!HasFastProperties());
405 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
406 if (IsGlobalObject()) {
407 value = JSGlobalPropertyCell::cast(value)->value();
408 }
409 ASSERT(!value->IsJSGlobalPropertyCell());
410 return value;
411}
412
413
414Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
415 ASSERT(!HasFastProperties());
416 if (IsGlobalObject()) {
417 JSGlobalPropertyCell* cell =
418 JSGlobalPropertyCell::cast(
419 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
420 cell->set_value(value);
421 } else {
422 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
423 }
424 return value;
425}
426
427
John Reck59135872010-11-02 12:39:01 -0700428MaybeObject* JSObject::SetNormalizedProperty(String* name,
429 Object* value,
430 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000431 ASSERT(!HasFastProperties());
432 int entry = property_dictionary()->FindEntry(name);
433 if (entry == StringDictionary::kNotFound) {
434 Object* store_value = value;
435 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100436 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100437 MaybeObject* maybe_store_value =
438 heap->AllocateJSGlobalPropertyCell(value);
439 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000440 }
John Reck59135872010-11-02 12:39:01 -0700441 Object* dict;
442 { MaybeObject* maybe_dict =
443 property_dictionary()->Add(name, store_value, details);
444 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
445 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 set_properties(StringDictionary::cast(dict));
447 return value;
448 }
449 // Preserve enumeration index.
450 details = PropertyDetails(details.attributes(),
451 details.type(),
452 property_dictionary()->DetailsAt(entry).index());
453 if (IsGlobalObject()) {
454 JSGlobalPropertyCell* cell =
455 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
456 cell->set_value(value);
457 // Please note we have to update the property details.
458 property_dictionary()->DetailsAtPut(entry, details);
459 } else {
460 property_dictionary()->SetEntry(entry, name, value, details);
461 }
462 return value;
463}
464
465
John Reck59135872010-11-02 12:39:01 -0700466MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000467 ASSERT(!HasFastProperties());
468 StringDictionary* dictionary = property_dictionary();
469 int entry = dictionary->FindEntry(name);
470 if (entry != StringDictionary::kNotFound) {
471 // If we have a global object set the cell to the hole.
472 if (IsGlobalObject()) {
473 PropertyDetails details = dictionary->DetailsAt(entry);
474 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100475 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000476 // When forced to delete global properties, we have to make a
477 // map change to invalidate any ICs that think they can load
478 // from the DontDelete cell without checking if it contains
479 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700480 Object* new_map;
481 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
482 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
483 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000484 set_map(Map::cast(new_map));
485 }
486 JSGlobalPropertyCell* cell =
487 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100488 cell->set_value(cell->heap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000489 dictionary->DetailsAtPut(entry, details.AsDeleted());
490 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000491 Object* deleted = dictionary->DeleteProperty(entry, mode);
492 if (deleted == GetHeap()->true_value()) {
493 FixedArray* new_properties = NULL;
494 MaybeObject* maybe_properties = dictionary->Shrink(name);
495 if (!maybe_properties->To(&new_properties)) {
496 return maybe_properties;
497 }
498 set_properties(new_properties);
499 }
500 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000501 }
502 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100503 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000504}
505
506
507bool JSObject::IsDirty() {
508 Object* cons_obj = map()->constructor();
509 if (!cons_obj->IsJSFunction())
510 return true;
511 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100512 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000513 return true;
514 // If the object is fully fast case and has the same map it was
515 // created with then no changes can have been made to it.
516 return map() != fun->initial_map()
517 || !HasFastElements()
518 || !HasFastProperties();
519}
520
521
John Reck59135872010-11-02 12:39:01 -0700522MaybeObject* Object::GetProperty(Object* receiver,
523 LookupResult* result,
524 String* name,
525 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000526 // Make sure that the top context does not change when doing
527 // callbacks or interceptor calls.
528 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100529 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000530
531 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000532 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000533 // objects more than once in case of interceptors, because the
534 // holder will always be the interceptor holder and the search may
535 // only continue with a current object just after the interceptor
536 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000537 // Proxy handlers do not use the proxy's prototype, so we can skip this.
538 if (!result->IsHandler()) {
539 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
540 ASSERT(this != this->GetPrototype());
541 for (Object* current = this; true; current = current->GetPrototype()) {
542 if (current->IsAccessCheckNeeded()) {
543 // Check if we're allowed to read from the current object. Note
544 // that even though we may not actually end up loading the named
545 // property from the current object, we still check that we have
546 // access to it.
547 JSObject* checked = JSObject::cast(current);
548 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
549 return checked->GetPropertyWithFailedAccessCheck(receiver,
550 result,
551 name,
552 attributes);
553 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000554 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000555 // Stop traversing the chain once we reach the last object in the
556 // chain; either the holder of the result or null in case of an
557 // absent property.
558 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000559 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 }
561
562 if (!result->IsProperty()) {
563 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100564 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000565 }
566 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000567 Object* value;
568 JSObject* holder = result->holder();
569 switch (result->type()) {
570 case NORMAL:
571 value = holder->GetNormalizedProperty(result);
572 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100573 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000574 case FIELD:
575 value = holder->FastPropertyAt(result->GetFieldIndex());
576 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100577 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000578 case CONSTANT_FUNCTION:
579 return result->GetConstantFunction();
580 case CALLBACKS:
581 return GetPropertyWithCallback(receiver,
582 result->GetCallbackObject(),
583 name,
584 holder);
Ben Murdoch257744e2011-11-30 15:57:28 +0000585 case HANDLER: {
586 JSProxy* proxy = JSProxy::cast(this);
587 return GetPropertyWithHandler(receiver, name, proxy->handler());
588 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 case INTERCEPTOR: {
590 JSObject* recvr = JSObject::cast(receiver);
591 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
592 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000593 case MAP_TRANSITION:
594 case EXTERNAL_ARRAY_TRANSITION:
595 case CONSTANT_TRANSITION:
596 case NULL_DESCRIPTOR:
597 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000599 UNREACHABLE();
600 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000601}
602
603
John Reck59135872010-11-02 12:39:01 -0700604MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100605 Object* holder = NULL;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100606 if (IsSmi()) {
607 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100608 holder = global_context->number_function()->instance_prototype();
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100609 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100610 HeapObject* heap_object = HeapObject::cast(this);
611
612 if (heap_object->IsJSObject()) {
613 return JSObject::cast(this)->GetElementWithReceiver(receiver, index);
614 }
615 Heap* heap = heap_object->GetHeap();
616 Isolate* isolate = heap->isolate();
617
618 Context* global_context = isolate->context()->global_context();
619 if (heap_object->IsString()) {
620 holder = global_context->string_function()->instance_prototype();
621 } else if (heap_object->IsHeapNumber()) {
622 holder = global_context->number_function()->instance_prototype();
623 } else if (heap_object->IsBoolean()) {
624 holder = global_context->boolean_function()->instance_prototype();
Ben Murdoch257744e2011-11-30 15:57:28 +0000625 } else if (heap_object->IsJSProxy()) {
626 return heap->undefined_value(); // For now...
Ben Murdoch8b112d22011-06-08 16:22:53 +0100627 } else {
628 // Undefined and null have no indexed properties.
629 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
630 return heap->undefined_value();
631 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100632 }
633
634 return JSObject::cast(holder)->GetElementWithReceiver(receiver, index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000635}
636
637
638Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100639 if (IsSmi()) {
640 Heap* heap = Isolate::Current()->heap();
641 Context* context = heap->isolate()->context()->global_context();
642 return context->number_function()->instance_prototype();
643 }
644
645 HeapObject* heap_object = HeapObject::cast(this);
646
Ben Murdoch257744e2011-11-30 15:57:28 +0000647 // The object is either a number, a string, a boolean,
648 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000649 if (heap_object->IsJSReceiver()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000650 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100651 }
652 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100653 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000654
Ben Murdoch8b112d22011-06-08 16:22:53 +0100655 if (heap_object->IsHeapNumber()) {
656 return context->number_function()->instance_prototype();
657 }
658 if (heap_object->IsString()) {
659 return context->string_function()->instance_prototype();
660 }
661 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 return context->boolean_function()->instance_prototype();
663 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100664 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000665 }
666}
667
668
Ben Murdochb0fe1622011-05-05 13:52:32 +0100669void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000670 HeapStringAllocator allocator;
671 StringStream accumulator(&allocator);
672 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100673 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000674}
675
676
677void Object::ShortPrint(StringStream* accumulator) {
678 if (IsSmi()) {
679 Smi::cast(this)->SmiPrint(accumulator);
680 } else if (IsFailure()) {
681 Failure::cast(this)->FailurePrint(accumulator);
682 } else {
683 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
684 }
685}
686
687
Ben Murdochb0fe1622011-05-05 13:52:32 +0100688void Smi::SmiPrint(FILE* out) {
689 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000690}
691
692
693void Smi::SmiPrint(StringStream* accumulator) {
694 accumulator->Add("%d", value());
695}
696
697
698void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000699 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000700}
701
702
Ben Murdochb0fe1622011-05-05 13:52:32 +0100703void Failure::FailurePrint(FILE* out) {
704 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000705}
706
707
Steve Blocka7e24c12009-10-30 11:49:00 +0000708// Should a word be prefixed by 'a' or 'an' in order to read naturally in
709// English? Returns false for non-ASCII or words that don't start with
710// a capital letter. The a/an rule follows pronunciation in English.
711// We don't use the BBC's overcorrect "an historic occasion" though if
712// you speak a dialect you may well say "an 'istoric occasion".
713static bool AnWord(String* str) {
714 if (str->length() == 0) return false; // A nothing.
715 int c0 = str->Get(0);
716 int c1 = str->length() > 1 ? str->Get(1) : 0;
717 if (c0 == 'U') {
718 if (c1 > 'Z') {
719 return true; // An Umpire, but a UTF8String, a U.
720 }
721 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
722 return true; // An Ape, an ABCBook.
723 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
724 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
725 c0 == 'S' || c0 == 'X')) {
726 return true; // An MP3File, an M.
727 }
728 return false;
729}
730
731
John Reck59135872010-11-02 12:39:01 -0700732MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000733#ifdef DEBUG
734 // Do not attempt to flatten in debug mode when allocation is not
735 // allowed. This is to avoid an assertion failure when allocating.
736 // Flattening strings is the only case where we always allow
737 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100738 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000739#endif
740
Steve Block44f0eee2011-05-26 01:26:41 +0100741 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 case kConsStringTag: {
744 ConsString* cs = ConsString::cast(this);
745 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100746 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000747 }
748 // There's little point in putting the flat string in new space if the
749 // cons string is in old space. It can never get GCed until there is
750 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100751 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 int len = length();
753 Object* object;
754 String* result;
755 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100756 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700757 if (!maybe_object->ToObject(&object)) return maybe_object;
758 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000759 result = String::cast(object);
760 String* first = cs->first();
761 int first_length = first->length();
762 char* dest = SeqAsciiString::cast(result)->GetChars();
763 WriteToFlat(first, dest, 0, first_length);
764 String* second = cs->second();
765 WriteToFlat(second,
766 dest + first_length,
767 0,
768 len - first_length);
769 } else {
John Reck59135872010-11-02 12:39:01 -0700770 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100771 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700772 if (!maybe_object->ToObject(&object)) return maybe_object;
773 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000774 result = String::cast(object);
775 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
776 String* first = cs->first();
777 int first_length = first->length();
778 WriteToFlat(first, dest, 0, first_length);
779 String* second = cs->second();
780 WriteToFlat(second,
781 dest + first_length,
782 0,
783 len - first_length);
784 }
785 cs->set_first(result);
Steve Block44f0eee2011-05-26 01:26:41 +0100786 cs->set_second(heap->empty_string());
Leon Clarkef7060e22010-06-03 12:02:55 +0100787 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000788 }
789 default:
790 return this;
791 }
792}
793
794
795bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100796 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100797 // prohibited by the API.
798 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000799#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000800 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000801 // Assert that the resource and the string are equivalent.
802 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100803 ScopedVector<uc16> smart_chars(this->length());
804 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
805 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100807 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 }
809#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100810 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 int size = this->Size(); // Byte size of the original string.
812 if (size < ExternalString::kSize) {
813 // The string is too small to fit an external String in its place. This can
814 // only happen for zero length strings.
815 return false;
816 }
817 ASSERT(size >= ExternalString::kSize);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100818 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000819 bool is_symbol = this->IsSymbol();
820 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000821 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000822
823 // Morph the object to an external string by adjusting the map and
824 // reinitializing the fields.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100825 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100826 heap->external_string_with_ascii_data_map() :
827 heap->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000828 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
829 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000830 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000831 self->set_resource(resource);
832 // Additionally make the object into an external symbol if the original string
833 // was a symbol to start with.
834 if (is_symbol) {
835 self->Hash(); // Force regeneration of the hash value.
836 // Now morph this external string into a external symbol.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100837 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100838 heap->external_symbol_with_ascii_data_map() :
839 heap->external_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000840 }
841
842 // Fill the remainder of the string with dead wood.
843 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100844 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 return true;
846}
847
848
849bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
850#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000851 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000852 // Assert that the resource and the string are equivalent.
853 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100854 ScopedVector<char> smart_chars(this->length());
855 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
856 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000857 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100858 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000859 }
860#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100861 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000862 int size = this->Size(); // Byte size of the original string.
863 if (size < ExternalString::kSize) {
864 // The string is too small to fit an external String in its place. This can
865 // only happen for zero length strings.
866 return false;
867 }
868 ASSERT(size >= ExternalString::kSize);
869 bool is_symbol = this->IsSymbol();
870 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000871 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000872
873 // Morph the object to an external string by adjusting the map and
874 // reinitializing the fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100875 this->set_map(heap->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000876 ExternalAsciiString* self = ExternalAsciiString::cast(this);
877 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000878 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000879 self->set_resource(resource);
880 // Additionally make the object into an external symbol if the original string
881 // was a symbol to start with.
882 if (is_symbol) {
883 self->Hash(); // Force regeneration of the hash value.
884 // Now morph this external string into a external symbol.
Steve Block44f0eee2011-05-26 01:26:41 +0100885 this->set_map(heap->external_ascii_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000886 }
887
888 // Fill the remainder of the string with dead wood.
889 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100890 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000891 return true;
892}
893
894
895void String::StringShortPrint(StringStream* accumulator) {
896 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +0000897 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000898 accumulator->Add("<Very long string[%u]>", len);
899 return;
900 }
901
902 if (!LooksValid()) {
903 accumulator->Add("<Invalid String>");
904 return;
905 }
906
907 StringInputBuffer buf(this);
908
909 bool truncated = false;
910 if (len > kMaxShortPrintLength) {
911 len = kMaxShortPrintLength;
912 truncated = true;
913 }
914 bool ascii = true;
915 for (int i = 0; i < len; i++) {
916 int c = buf.GetNext();
917
918 if (c < 32 || c >= 127) {
919 ascii = false;
920 }
921 }
922 buf.Reset(this);
923 if (ascii) {
924 accumulator->Add("<String[%u]: ", length());
925 for (int i = 0; i < len; i++) {
926 accumulator->Put(buf.GetNext());
927 }
928 accumulator->Put('>');
929 } else {
930 // Backslash indicates that the string contains control
931 // characters and that backslashes are therefore escaped.
932 accumulator->Add("<String[%u]\\: ", length());
933 for (int i = 0; i < len; i++) {
934 int c = buf.GetNext();
935 if (c == '\n') {
936 accumulator->Add("\\n");
937 } else if (c == '\r') {
938 accumulator->Add("\\r");
939 } else if (c == '\\') {
940 accumulator->Add("\\\\");
941 } else if (c < 32 || c > 126) {
942 accumulator->Add("\\x%02x", c);
943 } else {
944 accumulator->Put(c);
945 }
946 }
947 if (truncated) {
948 accumulator->Put('.');
949 accumulator->Put('.');
950 accumulator->Put('.');
951 }
952 accumulator->Put('>');
953 }
954 return;
955}
956
957
958void JSObject::JSObjectShortPrint(StringStream* accumulator) {
959 switch (map()->instance_type()) {
960 case JS_ARRAY_TYPE: {
961 double length = JSArray::cast(this)->length()->Number();
962 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
963 break;
964 }
965 case JS_REGEXP_TYPE: {
966 accumulator->Add("<JS RegExp>");
967 break;
968 }
969 case JS_FUNCTION_TYPE: {
970 Object* fun_name = JSFunction::cast(this)->shared()->name();
971 bool printed = false;
972 if (fun_name->IsString()) {
973 String* str = String::cast(fun_name);
974 if (str->length() > 0) {
975 accumulator->Add("<JS Function ");
976 accumulator->Put(str);
977 accumulator->Put('>');
978 printed = true;
979 }
980 }
981 if (!printed) {
982 accumulator->Add("<JS Function>");
983 }
984 break;
985 }
986 // All other JSObjects are rather similar to each other (JSObject,
987 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
988 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100989 Map* map_of_this = map();
990 Heap* heap = map_of_this->heap();
991 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 bool printed = false;
993 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +0100994 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000995 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
996 } else {
997 bool global_object = IsJSGlobalProxy();
998 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100999 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001000 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1001 } else {
1002 Object* constructor_name =
1003 JSFunction::cast(constructor)->shared()->name();
1004 if (constructor_name->IsString()) {
1005 String* str = String::cast(constructor_name);
1006 if (str->length() > 0) {
1007 bool vowel = AnWord(str);
1008 accumulator->Add("<%sa%s ",
1009 global_object ? "Global Object: " : "",
1010 vowel ? "n" : "");
1011 accumulator->Put(str);
Steve Blocka7e24c12009-10-30 11:49:00 +00001012 printed = true;
1013 }
1014 }
1015 }
1016 }
1017 if (!printed) {
1018 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1019 }
1020 }
1021 if (IsJSValue()) {
1022 accumulator->Add(" value = ");
1023 JSValue::cast(this)->value()->ShortPrint(accumulator);
1024 }
1025 accumulator->Put('>');
1026 break;
1027 }
1028 }
1029}
1030
1031
1032void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001033 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1034 Heap* heap = GetHeap();
1035 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001036 accumulator->Add("!!!INVALID POINTER!!!");
1037 return;
1038 }
Steve Block44f0eee2011-05-26 01:26:41 +01001039 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001040 accumulator->Add("!!!INVALID MAP!!!");
1041 return;
1042 }
1043
1044 accumulator->Add("%p ", this);
1045
1046 if (IsString()) {
1047 String::cast(this)->StringShortPrint(accumulator);
1048 return;
1049 }
1050 if (IsJSObject()) {
1051 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1052 return;
1053 }
1054 switch (map()->instance_type()) {
1055 case MAP_TYPE:
1056 accumulator->Add("<Map>");
1057 break;
1058 case FIXED_ARRAY_TYPE:
1059 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1060 break;
1061 case BYTE_ARRAY_TYPE:
1062 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1063 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001064 case EXTERNAL_PIXEL_ARRAY_TYPE:
1065 accumulator->Add("<ExternalPixelArray[%u]>",
1066 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001067 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001068 case EXTERNAL_BYTE_ARRAY_TYPE:
1069 accumulator->Add("<ExternalByteArray[%u]>",
1070 ExternalByteArray::cast(this)->length());
1071 break;
1072 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1073 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1074 ExternalUnsignedByteArray::cast(this)->length());
1075 break;
1076 case EXTERNAL_SHORT_ARRAY_TYPE:
1077 accumulator->Add("<ExternalShortArray[%u]>",
1078 ExternalShortArray::cast(this)->length());
1079 break;
1080 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1081 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1082 ExternalUnsignedShortArray::cast(this)->length());
1083 break;
1084 case EXTERNAL_INT_ARRAY_TYPE:
1085 accumulator->Add("<ExternalIntArray[%u]>",
1086 ExternalIntArray::cast(this)->length());
1087 break;
1088 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1089 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1090 ExternalUnsignedIntArray::cast(this)->length());
1091 break;
1092 case EXTERNAL_FLOAT_ARRAY_TYPE:
1093 accumulator->Add("<ExternalFloatArray[%u]>",
1094 ExternalFloatArray::cast(this)->length());
1095 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001096 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1097 accumulator->Add("<ExternalDoubleArray[%u]>",
1098 ExternalDoubleArray::cast(this)->length());
1099 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001100 case SHARED_FUNCTION_INFO_TYPE:
1101 accumulator->Add("<SharedFunctionInfo>");
1102 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001103 case JS_MESSAGE_OBJECT_TYPE:
1104 accumulator->Add("<JSMessageObject>");
1105 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001106#define MAKE_STRUCT_CASE(NAME, Name, name) \
1107 case NAME##_TYPE: \
1108 accumulator->Put('<'); \
1109 accumulator->Add(#Name); \
1110 accumulator->Put('>'); \
1111 break;
1112 STRUCT_LIST(MAKE_STRUCT_CASE)
1113#undef MAKE_STRUCT_CASE
1114 case CODE_TYPE:
1115 accumulator->Add("<Code>");
1116 break;
1117 case ODDBALL_TYPE: {
1118 if (IsUndefined())
1119 accumulator->Add("<undefined>");
1120 else if (IsTheHole())
1121 accumulator->Add("<the hole>");
1122 else if (IsNull())
1123 accumulator->Add("<null>");
1124 else if (IsTrue())
1125 accumulator->Add("<true>");
1126 else if (IsFalse())
1127 accumulator->Add("<false>");
1128 else
1129 accumulator->Add("<Odd Oddball>");
1130 break;
1131 }
1132 case HEAP_NUMBER_TYPE:
1133 accumulator->Add("<Number: ");
1134 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1135 accumulator->Put('>');
1136 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001137 case FOREIGN_TYPE:
1138 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001139 break;
1140 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1141 accumulator->Add("Cell for ");
1142 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1143 break;
1144 default:
1145 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1146 break;
1147 }
1148}
1149
1150
Steve Blocka7e24c12009-10-30 11:49:00 +00001151void HeapObject::Iterate(ObjectVisitor* v) {
1152 // Handle header
1153 IteratePointer(v, kMapOffset);
1154 // Handle object body
1155 Map* m = map();
1156 IterateBody(m->instance_type(), SizeFromMap(m), v);
1157}
1158
1159
1160void HeapObject::IterateBody(InstanceType type, int object_size,
1161 ObjectVisitor* v) {
1162 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1163 // During GC, the map pointer field is encoded.
1164 if (type < FIRST_NONSTRING_TYPE) {
1165 switch (type & kStringRepresentationMask) {
1166 case kSeqStringTag:
1167 break;
1168 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001169 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001170 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001171 case kExternalStringTag:
1172 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1173 reinterpret_cast<ExternalAsciiString*>(this)->
1174 ExternalAsciiStringIterateBody(v);
1175 } else {
1176 reinterpret_cast<ExternalTwoByteString*>(this)->
1177 ExternalTwoByteStringIterateBody(v);
1178 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001179 break;
1180 }
1181 return;
1182 }
1183
1184 switch (type) {
1185 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001186 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001187 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001188 case FIXED_DOUBLE_ARRAY_TYPE:
1189 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001190 case JS_OBJECT_TYPE:
1191 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1192 case JS_VALUE_TYPE:
1193 case JS_ARRAY_TYPE:
1194 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001195 case JS_GLOBAL_PROXY_TYPE:
1196 case JS_GLOBAL_OBJECT_TYPE:
1197 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001198 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001199 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001200 break;
Steve Block791712a2010-08-27 10:21:07 +01001201 case JS_FUNCTION_TYPE:
1202 reinterpret_cast<JSFunction*>(this)
1203 ->JSFunctionIterateBody(object_size, v);
1204 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001205 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001206 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001207 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001208 case JS_PROXY_TYPE:
1209 JSProxy::BodyDescriptor::IterateBody(this, v);
1210 break;
1211 case FOREIGN_TYPE:
1212 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001213 break;
1214 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001215 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001216 break;
1217 case CODE_TYPE:
1218 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1219 break;
1220 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001221 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001222 break;
1223 case HEAP_NUMBER_TYPE:
1224 case FILLER_TYPE:
1225 case BYTE_ARRAY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001226 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001227 case EXTERNAL_BYTE_ARRAY_TYPE:
1228 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1229 case EXTERNAL_SHORT_ARRAY_TYPE:
1230 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1231 case EXTERNAL_INT_ARRAY_TYPE:
1232 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1233 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001234 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001235 break;
Iain Merrick75681382010-08-19 15:07:18 +01001236 case SHARED_FUNCTION_INFO_TYPE:
1237 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001238 break;
Iain Merrick75681382010-08-19 15:07:18 +01001239
Steve Blocka7e24c12009-10-30 11:49:00 +00001240#define MAKE_STRUCT_CASE(NAME, Name, name) \
1241 case NAME##_TYPE:
1242 STRUCT_LIST(MAKE_STRUCT_CASE)
1243#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001244 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001245 break;
1246 default:
1247 PrintF("Unknown type: %d\n", type);
1248 UNREACHABLE();
1249 }
1250}
1251
1252
Steve Blocka7e24c12009-10-30 11:49:00 +00001253Object* HeapNumber::HeapNumberToBoolean() {
1254 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001255#if __BYTE_ORDER == __LITTLE_ENDIAN
1256 union IeeeDoubleLittleEndianArchType u;
1257#elif __BYTE_ORDER == __BIG_ENDIAN
1258 union IeeeDoubleBigEndianArchType u;
1259#endif
1260 u.d = value();
1261 if (u.bits.exp == 2047) {
1262 // Detect NaN for IEEE double precision floating point.
1263 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001264 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001265 }
Iain Merrick75681382010-08-19 15:07:18 +01001266 if (u.bits.exp == 0) {
1267 // Detect +0, and -0 for IEEE double precision floating point.
1268 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001269 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001270 }
Steve Block44f0eee2011-05-26 01:26:41 +01001271 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001272}
1273
1274
Ben Murdochb0fe1622011-05-05 13:52:32 +01001275void HeapNumber::HeapNumberPrint(FILE* out) {
1276 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001277}
1278
1279
1280void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1281 // The Windows version of vsnprintf can allocate when printing a %g string
1282 // into a buffer that may not be big enough. We don't want random memory
1283 // allocation when producing post-crash stack traces, so we print into a
1284 // buffer that is plenty big enough for any floating point number, then
1285 // print that using vsnprintf (which may truncate but never allocate if
1286 // there is no more space in the buffer).
1287 EmbeddedVector<char, 100> buffer;
1288 OS::SNPrintF(buffer, "%.16g", Number());
1289 accumulator->Add("%s", buffer.start());
1290}
1291
1292
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001293String* JSReceiver::class_name() {
1294 if (IsJSFunction() && IsJSFunctionProxy()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001295 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001296 }
1297 if (map()->constructor()->IsJSFunction()) {
1298 JSFunction* constructor = JSFunction::cast(map()->constructor());
1299 return String::cast(constructor->shared()->instance_class_name());
1300 }
1301 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001302 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001303}
1304
1305
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001306String* JSReceiver::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 if (map()->constructor()->IsJSFunction()) {
1308 JSFunction* constructor = JSFunction::cast(map()->constructor());
1309 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001310 if (name->length() > 0) return name;
1311 String* inferred_name = constructor->shared()->inferred_name();
1312 if (inferred_name->length() > 0) return inferred_name;
1313 Object* proto = GetPrototype();
1314 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001315 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001316 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001317 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001318 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001319}
1320
1321
John Reck59135872010-11-02 12:39:01 -07001322MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1323 String* name,
1324 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001325 int index = new_map->PropertyIndexFor(name);
1326 if (map()->unused_property_fields() == 0) {
1327 ASSERT(map()->unused_property_fields() == 0);
1328 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001329 Object* values;
1330 { MaybeObject* maybe_values =
1331 properties()->CopySize(properties()->length() + new_unused + 1);
1332 if (!maybe_values->ToObject(&values)) return maybe_values;
1333 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001334 set_properties(FixedArray::cast(values));
1335 }
1336 set_map(new_map);
1337 return FastPropertyAtPut(index, value);
1338}
1339
1340
Ben Murdoch8b112d22011-06-08 16:22:53 +01001341static bool IsIdentifier(UnicodeCache* cache,
1342 unibrow::CharacterStream* buffer) {
1343 // Checks whether the buffer contains an identifier (no escape).
1344 if (!buffer->has_more()) return false;
1345 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1346 return false;
1347 }
1348 while (buffer->has_more()) {
1349 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1350 return false;
1351 }
1352 }
1353 return true;
1354}
1355
1356
John Reck59135872010-11-02 12:39:01 -07001357MaybeObject* JSObject::AddFastProperty(String* name,
1358 Object* value,
1359 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001360 ASSERT(!IsJSGlobalProxy());
1361
Steve Blocka7e24c12009-10-30 11:49:00 +00001362 // Normalize the object if the name is an actual string (not the
1363 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001364 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001365 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001366 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001367 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001368 Object* obj;
1369 { MaybeObject* maybe_obj =
1370 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1371 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1372 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001373 return AddSlowProperty(name, value, attributes);
1374 }
1375
1376 DescriptorArray* old_descriptors = map()->instance_descriptors();
1377 // Compute the new index for new field.
1378 int index = map()->NextFreePropertyIndex();
1379
1380 // Allocate new instance descriptors with (name, index) added
1381 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001382 Object* new_descriptors;
1383 { MaybeObject* maybe_new_descriptors =
1384 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1385 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1386 return maybe_new_descriptors;
1387 }
1388 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001389
Steve Block44f0eee2011-05-26 01:26:41 +01001390 // Only allow map transition if the object isn't the global object and there
1391 // is not a transition for the name, or there's a transition for the name but
1392 // it's unrelated to properties.
1393 int descriptor_index = old_descriptors->Search(name);
1394
1395 // External array transitions are stored in the descriptor for property "",
1396 // which is not a identifier and should have forced a switch to slow
1397 // properties above.
1398 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
1399 old_descriptors->GetType(descriptor_index) != EXTERNAL_ARRAY_TRANSITION);
1400 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
1401 old_descriptors->GetType(descriptor_index) == EXTERNAL_ARRAY_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001402 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001403 can_insert_transition &&
1404 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001405
1406 ASSERT(index < map()->inobject_properties() ||
1407 (index - map()->inobject_properties()) < properties()->length() ||
1408 map()->unused_property_fields() == 0);
1409 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001410 Object* r;
1411 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1412 if (!maybe_r->ToObject(&r)) return maybe_r;
1413 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001414 Map* new_map = Map::cast(r);
1415 if (allow_map_transition) {
1416 // Allocate new instance descriptors for the old map with map transition.
1417 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001418 Object* r;
1419 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1420 if (!maybe_r->ToObject(&r)) return maybe_r;
1421 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 old_descriptors = DescriptorArray::cast(r);
1423 }
1424
1425 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001426 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001427 Object* obj;
1428 { MaybeObject* maybe_obj =
1429 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1430 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1431 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001432 return AddSlowProperty(name, value, attributes);
1433 }
1434 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001435 Object* values;
1436 { MaybeObject* maybe_values =
1437 properties()->CopySize(properties()->length() + kFieldsAdded);
1438 if (!maybe_values->ToObject(&values)) return maybe_values;
1439 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001440 set_properties(FixedArray::cast(values));
1441 new_map->set_unused_property_fields(kFieldsAdded - 1);
1442 } else {
1443 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1444 }
1445 // We have now allocated all the necessary objects.
1446 // All the changes can be applied at once, so they are atomic.
1447 map()->set_instance_descriptors(old_descriptors);
1448 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1449 set_map(new_map);
1450 return FastPropertyAtPut(index, value);
1451}
1452
1453
John Reck59135872010-11-02 12:39:01 -07001454MaybeObject* JSObject::AddConstantFunctionProperty(
1455 String* name,
1456 JSFunction* function,
1457 PropertyAttributes attributes) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001458 ASSERT(!GetHeap()->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001459
Steve Blocka7e24c12009-10-30 11:49:00 +00001460 // Allocate new instance descriptors with (name, function) added
1461 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001462 Object* new_descriptors;
1463 { MaybeObject* maybe_new_descriptors =
1464 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1465 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1466 return maybe_new_descriptors;
1467 }
1468 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001469
1470 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001471 Object* new_map;
1472 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1473 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1474 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001475
1476 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1477 Map::cast(new_map)->set_instance_descriptors(descriptors);
1478 Map* old_map = map();
1479 set_map(Map::cast(new_map));
1480
1481 // If the old map is the global object map (from new Object()),
1482 // then transitions are not added to it, so we are done.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001483 Heap* heap = old_map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001484 if (old_map == heap->isolate()->context()->global_context()->
1485 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001486 return function;
1487 }
1488
1489 // Do not add CONSTANT_TRANSITIONS to global objects
1490 if (IsGlobalObject()) {
1491 return function;
1492 }
1493
1494 // Add a CONSTANT_TRANSITION descriptor to the old map,
1495 // so future assignments to this property on other objects
1496 // of the same type will create a normal field, not a constant function.
1497 // Don't do this for special properties, with non-trival attributes.
1498 if (attributes != NONE) {
1499 return function;
1500 }
Iain Merrick75681382010-08-19 15:07:18 +01001501 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001502 { MaybeObject* maybe_new_descriptors =
1503 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1504 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1505 // We have accomplished the main goal, so return success.
1506 return function;
1507 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 }
1509 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1510
1511 return function;
1512}
1513
1514
1515// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001516MaybeObject* JSObject::AddSlowProperty(String* name,
1517 Object* value,
1518 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001519 ASSERT(!HasFastProperties());
1520 StringDictionary* dict = property_dictionary();
1521 Object* store_value = value;
1522 if (IsGlobalObject()) {
1523 // In case name is an orphaned property reuse the cell.
1524 int entry = dict->FindEntry(name);
1525 if (entry != StringDictionary::kNotFound) {
1526 store_value = dict->ValueAt(entry);
1527 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1528 // Assign an enumeration index to the property and update
1529 // SetNextEnumerationIndex.
1530 int index = dict->NextEnumerationIndex();
1531 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1532 dict->SetNextEnumerationIndex(index + 1);
1533 dict->SetEntry(entry, name, store_value, details);
1534 return value;
1535 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001536 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001537 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001538 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001539 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1540 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001541 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1542 }
1543 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001544 Object* result;
1545 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1546 if (!maybe_result->ToObject(&result)) return maybe_result;
1547 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 if (dict != result) set_properties(StringDictionary::cast(result));
1549 return value;
1550}
1551
1552
John Reck59135872010-11-02 12:39:01 -07001553MaybeObject* JSObject::AddProperty(String* name,
1554 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001555 PropertyAttributes attributes,
1556 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001557 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001558 Map* map_of_this = map();
1559 Heap* heap = map_of_this->heap();
1560 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001561 if (strict_mode == kNonStrictMode) {
1562 return heap->undefined_value();
1563 } else {
1564 Handle<Object> args[1] = {Handle<String>(name)};
1565 return heap->isolate()->Throw(
1566 *FACTORY->NewTypeError("object_not_extensible",
1567 HandleVector(args, 1)));
1568 }
Steve Block8defd9f2010-07-08 12:39:36 +01001569 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001570 if (HasFastProperties()) {
1571 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001572 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001573 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001574 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001575 return AddConstantFunctionProperty(name,
1576 JSFunction::cast(value),
1577 attributes);
1578 } else {
1579 return AddFastProperty(name, value, attributes);
1580 }
1581 } else {
1582 // Normalize the object to prevent very large instance descriptors.
1583 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001584 Object* obj;
1585 { MaybeObject* maybe_obj =
1586 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1587 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1588 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001589 }
1590 }
1591 return AddSlowProperty(name, value, attributes);
1592}
1593
1594
John Reck59135872010-11-02 12:39:01 -07001595MaybeObject* JSObject::SetPropertyPostInterceptor(
1596 String* name,
1597 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001598 PropertyAttributes attributes,
1599 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001600 // Check local property, ignore interceptor.
1601 LookupResult result;
1602 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001603 if (result.IsFound()) {
1604 // An existing property, a map transition or a null descriptor was
1605 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001606 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001607 }
1608 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001609 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001610}
1611
1612
John Reck59135872010-11-02 12:39:01 -07001613MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1614 Object* value,
1615 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001616 StringDictionary* dictionary = property_dictionary();
1617 int old_index = dictionary->FindEntry(name);
1618 int new_enumeration_index = 0; // 0 means "Use the next available index."
1619 if (old_index != -1) {
1620 // All calls to ReplaceSlowProperty have had all transitions removed.
1621 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1622 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1623 }
1624
1625 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1626 return SetNormalizedProperty(name, value, new_details);
1627}
1628
Steve Blockd0582a62009-12-15 09:54:21 +00001629
John Reck59135872010-11-02 12:39:01 -07001630MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001631 String* name,
1632 Object* new_value,
1633 PropertyAttributes attributes) {
1634 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001635 Object* result;
1636 { MaybeObject* maybe_result =
1637 ConvertDescriptorToField(name, new_value, attributes);
1638 if (!maybe_result->ToObject(&result)) return maybe_result;
1639 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001640 // If we get to this point we have succeeded - do not return failure
1641 // after this point. Later stuff is optional.
1642 if (!HasFastProperties()) {
1643 return result;
1644 }
1645 // Do not add transitions to the map of "new Object()".
Ben Murdoch8b112d22011-06-08 16:22:53 +01001646 if (map() == old_map->heap()->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001647 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001648 return result;
1649 }
1650
1651 MapTransitionDescriptor transition(name,
1652 map(),
1653 attributes);
John Reck59135872010-11-02 12:39:01 -07001654 Object* new_descriptors;
1655 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1656 CopyInsert(&transition, KEEP_TRANSITIONS);
1657 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1658 return result; // Yes, return _result_.
1659 }
1660 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001661 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1662 return result;
1663}
1664
1665
John Reck59135872010-11-02 12:39:01 -07001666MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1667 Object* new_value,
1668 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001670 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001671 Object* obj;
1672 { MaybeObject* maybe_obj =
1673 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1674 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1675 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001676 return ReplaceSlowProperty(name, new_value, attributes);
1677 }
1678
1679 int index = map()->NextFreePropertyIndex();
1680 FieldDescriptor new_field(name, index, attributes);
1681 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001682 Object* descriptors_unchecked;
1683 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1684 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1685 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1686 return maybe_descriptors_unchecked;
1687 }
1688 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001689 DescriptorArray* new_descriptors =
1690 DescriptorArray::cast(descriptors_unchecked);
1691
1692 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001693 Object* new_map_unchecked;
1694 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1695 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1696 return maybe_new_map_unchecked;
1697 }
1698 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001699 Map* new_map = Map::cast(new_map_unchecked);
1700 new_map->set_instance_descriptors(new_descriptors);
1701
1702 // Make new properties array if necessary.
1703 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1704 int new_unused_property_fields = map()->unused_property_fields() - 1;
1705 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001706 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001707 Object* new_properties_object;
1708 { MaybeObject* maybe_new_properties_object =
1709 properties()->CopySize(properties()->length() + kFieldsAdded);
1710 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1711 return maybe_new_properties_object;
1712 }
1713 }
1714 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001715 }
1716
1717 // Update pointers to commit changes.
1718 // Object points to the new map.
1719 new_map->set_unused_property_fields(new_unused_property_fields);
1720 set_map(new_map);
1721 if (new_properties) {
1722 set_properties(FixedArray::cast(new_properties));
1723 }
1724 return FastPropertyAtPut(index, new_value);
1725}
1726
1727
1728
John Reck59135872010-11-02 12:39:01 -07001729MaybeObject* JSObject::SetPropertyWithInterceptor(
1730 String* name,
1731 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001732 PropertyAttributes attributes,
1733 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001734 Isolate* isolate = GetIsolate();
1735 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001736 Handle<JSObject> this_handle(this);
1737 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001738 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001739 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1740 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001741 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1742 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001743 v8::AccessorInfo info(args.end());
1744 v8::NamedPropertySetter setter =
1745 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1746 v8::Handle<v8::Value> result;
1747 {
1748 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001749 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001750 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001751 isolate->heap()->undefined_value() :
1752 value,
1753 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001754 result = setter(v8::Utils::ToLocal(name_handle),
1755 v8::Utils::ToLocal(value_unhole),
1756 info);
1757 }
Steve Block44f0eee2011-05-26 01:26:41 +01001758 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001759 if (!result.IsEmpty()) return *value_handle;
1760 }
John Reck59135872010-11-02 12:39:01 -07001761 MaybeObject* raw_result =
1762 this_handle->SetPropertyPostInterceptor(*name_handle,
1763 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001764 attributes,
1765 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001766 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001767 return raw_result;
1768}
1769
1770
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001771MaybeObject* JSReceiver::SetProperty(String* name,
1772 Object* value,
1773 PropertyAttributes attributes,
1774 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001775 LookupResult result;
1776 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001777 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001778}
1779
1780
John Reck59135872010-11-02 12:39:01 -07001781MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1782 String* name,
1783 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001784 JSObject* holder,
1785 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001786 Isolate* isolate = GetIsolate();
1787 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001788
1789 // We should never get here to initialize a const with the hole
1790 // value since a const declaration would conflict with the setter.
1791 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001792 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001793
1794 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00001795 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00001796 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00001797 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001798 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00001799 reinterpret_cast<AccessorDescriptor*>(
1800 Foreign::cast(structure)->address());
John Reck59135872010-11-02 12:39:01 -07001801 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001802 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001803 if (obj->IsFailure()) return obj;
1804 return *value_handle;
1805 }
1806
1807 if (structure->IsAccessorInfo()) {
1808 // api style callbacks
1809 AccessorInfo* data = AccessorInfo::cast(structure);
1810 Object* call_obj = data->setter();
1811 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1812 if (call_fun == NULL) return value;
1813 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001814 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1815 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001816 v8::AccessorInfo info(args.end());
1817 {
1818 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001819 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001820 call_fun(v8::Utils::ToLocal(key),
1821 v8::Utils::ToLocal(value_handle),
1822 info);
1823 }
Steve Block44f0eee2011-05-26 01:26:41 +01001824 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001825 return *value_handle;
1826 }
1827
1828 if (structure->IsFixedArray()) {
1829 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1830 if (setter->IsJSFunction()) {
1831 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1832 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001833 if (strict_mode == kNonStrictMode) {
1834 return value;
1835 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001836 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001837 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001838 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01001839 return isolate->Throw(
1840 *isolate->factory()->NewTypeError("no_setter_in_callback",
1841 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001842 }
1843 }
1844
1845 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01001846 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001847}
1848
1849
John Reck59135872010-11-02 12:39:01 -07001850MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1851 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01001852 Isolate* isolate = GetIsolate();
1853 Handle<Object> value_handle(value, isolate);
1854 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1855 Handle<JSObject> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001856#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01001857 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00001858 // Handle stepping into a setter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01001859 if (debug->StepInActive()) {
1860 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001861 }
1862#endif
1863 bool has_pending_exception;
1864 Object** argv[] = { value_handle.location() };
1865 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1866 // Check for pending exception and return the result.
1867 if (has_pending_exception) return Failure::Exception();
1868 return *value_handle;
1869}
1870
1871
1872void JSObject::LookupCallbackSetterInPrototypes(String* name,
1873 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001874 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001876 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 pt = pt->GetPrototype()) {
1878 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001879 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01001880 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
1881 // Found non-callback or read-only callback, stop looking.
1882 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001883 }
1884 }
1885 result->NotFound();
1886}
1887
1888
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001889MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1890 uint32_t index,
1891 Object* value,
1892 bool* found,
1893 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001894 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001895 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001896 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001897 pt = pt->GetPrototype()) {
1898 if (!JSObject::cast(pt)->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001899 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00001900 }
1901 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1902 int entry = dictionary->FindEntry(index);
1903 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001904 PropertyDetails details = dictionary->DetailsAt(entry);
1905 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001906 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001907 return SetElementWithCallback(dictionary->ValueAt(entry),
1908 index,
1909 value,
1910 JSObject::cast(pt),
1911 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001912 }
1913 }
1914 }
Steve Block1e0659c2011-05-24 12:43:12 +01001915 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001916 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001917}
1918
1919
1920void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1921 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001922 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001923 if (number != DescriptorArray::kNotFound) {
1924 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1925 } else {
1926 result->NotFound();
1927 }
1928}
1929
1930
Ben Murdochb0fe1622011-05-05 13:52:32 +01001931void Map::LookupInDescriptors(JSObject* holder,
1932 String* name,
1933 LookupResult* result) {
1934 DescriptorArray* descriptors = instance_descriptors();
Steve Block44f0eee2011-05-26 01:26:41 +01001935 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1936 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001937 if (number == DescriptorLookupCache::kAbsent) {
1938 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001939 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001940 }
1941 if (number != DescriptorArray::kNotFound) {
1942 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1943 } else {
1944 result->NotFound();
1945 }
1946}
1947
1948
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001949static JSObject::ElementsKind GetElementsKindFromExternalArrayType(
1950 ExternalArrayType array_type) {
1951 switch (array_type) {
1952 case kExternalByteArray:
1953 return JSObject::EXTERNAL_BYTE_ELEMENTS;
1954 break;
1955 case kExternalUnsignedByteArray:
1956 return JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS;
1957 break;
1958 case kExternalShortArray:
1959 return JSObject::EXTERNAL_SHORT_ELEMENTS;
1960 break;
1961 case kExternalUnsignedShortArray:
1962 return JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS;
1963 break;
1964 case kExternalIntArray:
1965 return JSObject::EXTERNAL_INT_ELEMENTS;
1966 break;
1967 case kExternalUnsignedIntArray:
1968 return JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS;
1969 break;
1970 case kExternalFloatArray:
1971 return JSObject::EXTERNAL_FLOAT_ELEMENTS;
1972 break;
1973 case kExternalDoubleArray:
1974 return JSObject::EXTERNAL_DOUBLE_ELEMENTS;
1975 break;
1976 case kExternalPixelArray:
1977 return JSObject::EXTERNAL_PIXEL_ELEMENTS;
1978 break;
1979 }
1980 UNREACHABLE();
1981 return JSObject::DICTIONARY_ELEMENTS;
1982}
1983
1984
Steve Block44f0eee2011-05-26 01:26:41 +01001985MaybeObject* Map::GetExternalArrayElementsMap(ExternalArrayType array_type,
1986 bool safe_to_add_transition) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001987 Heap* current_heap = heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001988 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch8b112d22011-06-08 16:22:53 +01001989 String* external_array_sentinel_name = current_heap->empty_symbol();
Steve Block44f0eee2011-05-26 01:26:41 +01001990
1991 if (safe_to_add_transition) {
1992 // It's only safe to manipulate the descriptor array if it would be
1993 // safe to add a transition.
1994
1995 ASSERT(!is_shared()); // no transitions can be added to shared maps.
1996 // Check if the external array transition already exists.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001997 DescriptorLookupCache* cache =
1998 current_heap->isolate()->descriptor_lookup_cache();
Steve Block44f0eee2011-05-26 01:26:41 +01001999 int index = cache->Lookup(descriptors, external_array_sentinel_name);
2000 if (index == DescriptorLookupCache::kAbsent) {
2001 index = descriptors->Search(external_array_sentinel_name);
2002 cache->Update(descriptors,
2003 external_array_sentinel_name,
2004 index);
2005 }
2006
2007 // If the transition already exists, check the type. If there is a match,
2008 // return it.
2009 if (index != DescriptorArray::kNotFound) {
2010 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
2011 if (details.type() == EXTERNAL_ARRAY_TRANSITION &&
2012 details.array_type() == array_type) {
2013 return descriptors->GetValue(index);
2014 } else {
2015 safe_to_add_transition = false;
2016 }
2017 }
2018 }
2019
2020 // No transition to an existing external array map. Make a new one.
2021 Object* obj;
2022 { MaybeObject* maybe_map = CopyDropTransitions();
2023 if (!maybe_map->ToObject(&obj)) return maybe_map;
2024 }
2025 Map* new_map = Map::cast(obj);
2026
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002027 new_map->set_elements_kind(GetElementsKindFromExternalArrayType(array_type));
Steve Block44f0eee2011-05-26 01:26:41 +01002028 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
2029
2030 // Only remember the map transition if the object's map is NOT equal to the
2031 // global object_function's map and there is not an already existing
2032 // non-matching external array transition.
2033 bool allow_map_transition =
2034 safe_to_add_transition &&
2035 (GetIsolate()->context()->global_context()->object_function()->map() !=
2036 map());
2037 if (allow_map_transition) {
2038 // Allocate new instance descriptors for the old map with map transition.
2039 ExternalArrayTransitionDescriptor desc(external_array_sentinel_name,
2040 Map::cast(new_map),
2041 array_type);
2042 Object* new_descriptors;
2043 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2044 &desc,
2045 KEEP_TRANSITIONS);
2046 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2047 return maybe_new_descriptors;
2048 }
2049 descriptors = DescriptorArray::cast(new_descriptors);
2050 set_instance_descriptors(descriptors);
2051 }
2052
2053 return new_map;
2054}
2055
2056
Steve Blocka7e24c12009-10-30 11:49:00 +00002057void JSObject::LocalLookupRealNamedProperty(String* name,
2058 LookupResult* result) {
2059 if (IsJSGlobalProxy()) {
2060 Object* proto = GetPrototype();
2061 if (proto->IsNull()) return result->NotFound();
2062 ASSERT(proto->IsJSGlobalObject());
2063 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2064 }
2065
2066 if (HasFastProperties()) {
2067 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002068 if (result->IsFound()) {
2069 // A property, a map transition or a null descriptor was found.
2070 // We return all of these result types because
2071 // LocalLookupRealNamedProperty is used when setting properties
2072 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002073 ASSERT(result->holder() == this && result->type() != NORMAL);
2074 // Disallow caching for uninitialized constants. These can only
2075 // occur as fields.
2076 if (result->IsReadOnly() && result->type() == FIELD &&
2077 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2078 result->DisallowCaching();
2079 }
2080 return;
2081 }
2082 } else {
2083 int entry = property_dictionary()->FindEntry(name);
2084 if (entry != StringDictionary::kNotFound) {
2085 Object* value = property_dictionary()->ValueAt(entry);
2086 if (IsGlobalObject()) {
2087 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2088 if (d.IsDeleted()) {
2089 result->NotFound();
2090 return;
2091 }
2092 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002093 }
2094 // Make sure to disallow caching for uninitialized constants
2095 // found in the dictionary-mode objects.
2096 if (value->IsTheHole()) result->DisallowCaching();
2097 result->DictionaryResult(this, entry);
2098 return;
2099 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002100 }
2101 result->NotFound();
2102}
2103
2104
2105void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2106 LocalLookupRealNamedProperty(name, result);
2107 if (result->IsProperty()) return;
2108
2109 LookupRealNamedPropertyInPrototypes(name, result);
2110}
2111
2112
2113void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2114 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002115 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002116 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002117 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002118 pt = JSObject::cast(pt)->GetPrototype()) {
2119 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002120 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002121 }
2122 result->NotFound();
2123}
2124
2125
2126// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002127MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2128 LookupResult* result,
2129 String* name,
2130 Object* value,
2131 bool check_prototype,
2132 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002133 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002134 LookupCallbackSetterInPrototypes(name, result);
2135 }
2136
2137 if (result->IsProperty()) {
2138 if (!result->IsReadOnly()) {
2139 switch (result->type()) {
2140 case CALLBACKS: {
2141 Object* obj = result->GetCallbackObject();
2142 if (obj->IsAccessorInfo()) {
2143 AccessorInfo* info = AccessorInfo::cast(obj);
2144 if (info->all_can_write()) {
2145 return SetPropertyWithCallback(result->GetCallbackObject(),
2146 name,
2147 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002148 result->holder(),
2149 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002150 }
2151 }
2152 break;
2153 }
2154 case INTERCEPTOR: {
2155 // Try lookup real named properties. Note that only property can be
2156 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2157 LookupResult r;
2158 LookupRealNamedProperty(name, &r);
2159 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002160 return SetPropertyWithFailedAccessCheck(&r,
2161 name,
2162 value,
2163 check_prototype,
2164 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002165 }
2166 break;
2167 }
2168 default: {
2169 break;
2170 }
2171 }
2172 }
2173 }
2174
Ben Murdoch8b112d22011-06-08 16:22:53 +01002175 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002176 HandleScope scope(heap->isolate());
2177 Handle<Object> value_handle(value);
Steve Block44f0eee2011-05-26 01:26:41 +01002178 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002179 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002180}
2181
2182
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002183MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2184 String* key,
2185 Object* value,
2186 PropertyAttributes attributes,
2187 StrictModeFlag strict_mode) {
2188 if (result->IsFound() && result->type() == HANDLER) {
2189 return JSProxy::cast(this)->SetPropertyWithHandler(
2190 key, value, attributes, strict_mode);
2191 } else {
2192 return JSObject::cast(this)->SetPropertyForResult(
2193 result, key, value, attributes, strict_mode);
2194 }
2195}
2196
2197
2198bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2199 Isolate* isolate = GetIsolate();
2200 HandleScope scope(isolate);
2201 Handle<Object> receiver(this);
2202 Handle<Object> name(name_raw);
2203 Handle<Object> handler(this->handler());
2204
2205 // Extract trap function.
2206 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
2207 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2208 if (trap->IsUndefined()) {
2209 trap = isolate->derived_has_trap();
2210 }
2211
2212 // Call trap function.
2213 Object** args[] = { name.location() };
2214 bool has_exception;
2215 Handle<Object> result =
2216 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2217 if (has_exception) return Failure::Exception();
2218
2219 return result->ToBoolean()->IsTrue();
2220}
2221
2222
2223MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2224 String* name_raw,
2225 Object* value_raw,
2226 PropertyAttributes attributes,
2227 StrictModeFlag strict_mode) {
2228 Isolate* isolate = GetIsolate();
2229 HandleScope scope(isolate);
2230 Handle<Object> receiver(this);
2231 Handle<Object> name(name_raw);
2232 Handle<Object> value(value_raw);
2233 Handle<Object> handler(this->handler());
2234
2235 // Extract trap function.
2236 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2237 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2238 if (trap->IsUndefined()) {
2239 trap = isolate->derived_set_trap();
2240 }
2241
2242 // Call trap function.
2243 Object** args[] = {
2244 receiver.location(), name.location(), value.location()
2245 };
2246 bool has_exception;
2247 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2248 if (has_exception) return Failure::Exception();
2249
2250 return *value;
2251}
2252
2253
2254MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2255 String* name_raw, DeleteMode mode) {
2256 Isolate* isolate = GetIsolate();
2257 HandleScope scope(isolate);
2258 Handle<Object> receiver(this);
2259 Handle<Object> name(name_raw);
2260 Handle<Object> handler(this->handler());
2261
2262 // Extract trap function.
2263 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2264 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2265 if (trap->IsUndefined()) {
2266 Handle<Object> args[] = { handler, trap_name };
2267 Handle<Object> error = isolate->factory()->NewTypeError(
2268 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2269 isolate->Throw(*error);
2270 return Failure::Exception();
2271 }
2272
2273 // Call trap function.
2274 Object** args[] = { name.location() };
2275 bool has_exception;
2276 Handle<Object> result =
2277 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2278 if (has_exception) return Failure::Exception();
2279
2280 Object* bool_result = result->ToBoolean();
2281 if (mode == STRICT_DELETION && bool_result == GetHeap()->false_value()) {
2282 Handle<Object> args[] = { handler, trap_name };
2283 Handle<Object> error = isolate->factory()->NewTypeError(
2284 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2285 isolate->Throw(*error);
2286 return Failure::Exception();
2287 }
2288 return bool_result;
2289}
2290
2291
2292MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2293 JSReceiver* receiver_raw,
2294 String* name_raw,
2295 bool* has_exception) {
2296 Isolate* isolate = GetIsolate();
2297 HandleScope scope(isolate);
2298 Handle<JSReceiver> receiver(receiver_raw);
2299 Handle<Object> name(name_raw);
2300 Handle<Object> handler(this->handler());
2301
2302 // Extract trap function.
2303 Handle<String> trap_name =
2304 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2305 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
2306 if (trap->IsUndefined()) {
2307 Handle<Object> args[] = { handler, trap_name };
2308 Handle<Object> error = isolate->factory()->NewTypeError(
2309 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2310 isolate->Throw(*error);
2311 *has_exception = true;
2312 return NONE;
2313 }
2314
2315 // Call trap function.
2316 Object** args[] = { name.location() };
2317 Handle<Object> result =
2318 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2319 if (has_exception) return NONE;
2320
2321 // TODO(rossberg): convert result to PropertyAttributes
2322 USE(result);
2323 return NONE;
2324}
2325
2326
2327void JSProxy::Fix() {
2328 Isolate* isolate = GetIsolate();
2329 HandleScope scope(isolate);
2330 Handle<JSProxy> self(this);
2331
2332 isolate->factory()->BecomeJSObject(self);
2333 ASSERT(IsJSObject());
2334 // TODO(rossberg): recognize function proxies.
2335}
2336
2337
2338
2339MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2340 String* name,
2341 Object* value,
2342 PropertyAttributes attributes,
2343 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002344 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002345 // Make sure that the top context does not change when doing callbacks or
2346 // interceptor calls.
2347 AssertNoContextChange ncc;
2348
Steve Blockd0582a62009-12-15 09:54:21 +00002349 // Optimization for 2-byte strings often used as keys in a decompression
2350 // dictionary. We make these short keys into symbols to avoid constantly
2351 // reallocating them.
2352 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002353 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002354 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002355 if (maybe_symbol_version->ToObject(&symbol_version)) {
2356 name = String::cast(symbol_version);
2357 }
2358 }
Steve Blockd0582a62009-12-15 09:54:21 +00002359 }
2360
Steve Blocka7e24c12009-10-30 11:49:00 +00002361 // Check access rights if needed.
2362 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002363 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002364 return SetPropertyWithFailedAccessCheck(result,
2365 name,
2366 value,
2367 true,
2368 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002369 }
2370
2371 if (IsJSGlobalProxy()) {
2372 Object* proto = GetPrototype();
2373 if (proto->IsNull()) return value;
2374 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002375 return JSObject::cast(proto)->SetProperty(
2376 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002377 }
2378
2379 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2380 // We could not find a local property so let's check whether there is an
2381 // accessor that wants to handle the property.
2382 LookupResult accessor_result;
2383 LookupCallbackSetterInPrototypes(name, &accessor_result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002384 if (accessor_result.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002385 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2386 name,
2387 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002388 accessor_result.holder(),
2389 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002390 }
2391 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002392 if (!result->IsFound()) {
2393 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002394 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002395 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002396 if (result->IsReadOnly() && result->IsProperty()) {
2397 if (strict_mode == kStrictMode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002398 HandleScope scope(heap->isolate());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002399 Handle<String> key(name);
2400 Handle<Object> holder(this);
2401 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002402 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2403 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002404 } else {
2405 return value;
2406 }
2407 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002408 // This is a real property that is not read-only, or it is a
2409 // transition or null descriptor and there are no setters in the prototypes.
2410 switch (result->type()) {
2411 case NORMAL:
2412 return SetNormalizedProperty(result, value);
2413 case FIELD:
2414 return FastPropertyAtPut(result->GetFieldIndex(), value);
2415 case MAP_TRANSITION:
2416 if (attributes == result->GetAttributes()) {
2417 // Only use map transition if the attributes match.
2418 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2419 name,
2420 value);
2421 }
2422 return ConvertDescriptorToField(name, value, attributes);
2423 case CONSTANT_FUNCTION:
2424 // Only replace the function if necessary.
2425 if (value == result->GetConstantFunction()) return value;
2426 // Preserve the attributes of this existing property.
2427 attributes = result->GetAttributes();
2428 return ConvertDescriptorToField(name, value, attributes);
2429 case CALLBACKS:
2430 return SetPropertyWithCallback(result->GetCallbackObject(),
2431 name,
2432 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002433 result->holder(),
2434 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002435 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002436 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002437 case CONSTANT_TRANSITION: {
2438 // If the same constant function is being added we can simply
2439 // transition to the target map.
2440 Map* target_map = result->GetTransitionMap();
2441 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2442 int number = target_descriptors->SearchWithCache(name);
2443 ASSERT(number != DescriptorArray::kNotFound);
2444 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2445 JSFunction* function =
2446 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002447 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002448 if (value == function) {
2449 set_map(target_map);
2450 return value;
2451 }
2452 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2453 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002454 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002455 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002456 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002457 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002458 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2459 default:
2460 UNREACHABLE();
2461 }
2462 UNREACHABLE();
2463 return value;
2464}
2465
2466
2467// Set a real local property, even if it is READ_ONLY. If the property is not
2468// present, add it with attributes NONE. This code is an exact clone of
2469// SetProperty, with the check for IsReadOnly and the check for a
2470// callback setter removed. The two lines looking up the LookupResult
2471// result are also added. If one of the functions is changed, the other
2472// should be.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002473MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002474 String* name,
2475 Object* value,
2476 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002477
Steve Blocka7e24c12009-10-30 11:49:00 +00002478 // Make sure that the top context does not change when doing callbacks or
2479 // interceptor calls.
2480 AssertNoContextChange ncc;
Andrei Popescu402d9372010-02-26 13:31:12 +00002481 LookupResult result;
2482 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002483 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002484 if (IsAccessCheckNeeded()) {
2485 Heap* heap = GetHeap();
2486 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002487 return SetPropertyWithFailedAccessCheck(&result,
2488 name,
2489 value,
2490 false,
2491 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002493 }
2494
2495 if (IsJSGlobalProxy()) {
2496 Object* proto = GetPrototype();
2497 if (proto->IsNull()) return value;
2498 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002499 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002500 name,
2501 value,
2502 attributes);
2503 }
2504
2505 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002506 if (!result.IsFound()) {
2507 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002508 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002509 }
Steve Block6ded16b2010-05-10 14:33:55 +01002510
Andrei Popescu402d9372010-02-26 13:31:12 +00002511 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2512
Steve Blocka7e24c12009-10-30 11:49:00 +00002513 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002514 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002515 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002516 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002517 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002518 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002519 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002520 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002521 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002522 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002523 name,
2524 value);
2525 }
2526 return ConvertDescriptorToField(name, value, attributes);
2527 case CONSTANT_FUNCTION:
2528 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002529 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002530 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002531 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002532 return ConvertDescriptorToField(name, value, attributes);
2533 case CALLBACKS:
2534 case INTERCEPTOR:
2535 // Override callback in clone
2536 return ConvertDescriptorToField(name, value, attributes);
2537 case CONSTANT_TRANSITION:
2538 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2539 // if the value is a function.
2540 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2541 case NULL_DESCRIPTOR:
Steve Block44f0eee2011-05-26 01:26:41 +01002542 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002543 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2544 default:
2545 UNREACHABLE();
2546 }
2547 UNREACHABLE();
2548 return value;
2549}
2550
2551
2552PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2553 JSObject* receiver,
2554 String* name,
2555 bool continue_search) {
2556 // Check local property, ignore interceptor.
2557 LookupResult result;
2558 LocalLookupRealNamedProperty(name, &result);
2559 if (result.IsProperty()) return result.GetAttributes();
2560
2561 if (continue_search) {
2562 // Continue searching via the prototype chain.
2563 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002564 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002565 return JSObject::cast(pt)->
2566 GetPropertyAttributeWithReceiver(receiver, name);
2567 }
2568 }
2569 return ABSENT;
2570}
2571
2572
2573PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2574 JSObject* receiver,
2575 String* name,
2576 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002577 Isolate* isolate = GetIsolate();
2578
Steve Blocka7e24c12009-10-30 11:49:00 +00002579 // Make sure that the top context does not change when doing
2580 // callbacks or interceptor calls.
2581 AssertNoContextChange ncc;
2582
Steve Block44f0eee2011-05-26 01:26:41 +01002583 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002584 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2585 Handle<JSObject> receiver_handle(receiver);
2586 Handle<JSObject> holder_handle(this);
2587 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002588 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002589 v8::AccessorInfo info(args.end());
2590 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002591 v8::NamedPropertyQuery query =
2592 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002593 LOG(isolate,
2594 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002595 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002596 {
2597 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002598 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002599 result = query(v8::Utils::ToLocal(name_handle), info);
2600 }
2601 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002602 ASSERT(result->IsInt32());
2603 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002604 }
2605 } else if (!interceptor->getter()->IsUndefined()) {
2606 v8::NamedPropertyGetter getter =
2607 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002608 LOG(isolate,
2609 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002610 v8::Handle<v8::Value> result;
2611 {
2612 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002613 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002614 result = getter(v8::Utils::ToLocal(name_handle), info);
2615 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002616 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002617 }
2618 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2619 *name_handle,
2620 continue_search);
2621}
2622
2623
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002624PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2625 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00002626 String* key) {
2627 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002628 if (IsJSObject() && key->AsArrayIndex(&index)) {
2629 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2630 return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002631 return ABSENT;
2632 }
2633 // Named property.
2634 LookupResult result;
2635 Lookup(key, &result);
2636 return GetPropertyAttribute(receiver, &result, key, true);
2637}
2638
2639
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002640PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2641 LookupResult* result,
2642 String* name,
2643 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002644 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002645 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002646 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002647 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002648 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2649 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2650 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002651 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002652 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002653 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002654 switch (result->type()) {
2655 case NORMAL: // fall through
2656 case FIELD:
2657 case CONSTANT_FUNCTION:
2658 case CALLBACKS:
2659 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002660 case HANDLER: {
2661 // TODO(rossberg): propagate exceptions properly.
2662 bool has_exception = false;
2663 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2664 receiver, name, &has_exception);
2665 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002666 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002667 return result->holder()->GetPropertyAttributeWithInterceptor(
2668 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002669 default:
2670 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002671 }
2672 }
2673 return ABSENT;
2674}
2675
2676
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002677PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002678 // Check whether the name is an array index.
2679 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002680 if (IsJSObject() && name->AsArrayIndex(&index)) {
2681 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002682 return ABSENT;
2683 }
2684 // Named property.
2685 LookupResult result;
2686 LocalLookup(name, &result);
2687 return GetPropertyAttribute(this, &result, name, false);
2688}
2689
2690
John Reck59135872010-11-02 12:39:01 -07002691MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2692 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002693 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002694 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002695 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002696 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002697 if (result->IsMap() &&
2698 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002699#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002700 Map::cast(result)->SharedMapVerify();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002701 if (FLAG_enable_slow_asserts) {
2702 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002703 Object* fresh;
2704 { MaybeObject* maybe_fresh =
2705 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2706 if (maybe_fresh->ToObject(&fresh)) {
2707 ASSERT(memcmp(Map::cast(fresh)->address(),
2708 Map::cast(result)->address(),
2709 Map::kSize) == 0);
2710 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002711 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002712 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002713#endif
2714 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002715 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002716
John Reck59135872010-11-02 12:39:01 -07002717 { MaybeObject* maybe_result =
2718 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2719 if (!maybe_result->ToObject(&result)) return maybe_result;
2720 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002721 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002722 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002723
2724 return result;
2725}
2726
2727
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002728void NormalizedMapCache::Clear() {
2729 int entries = length();
2730 for (int i = 0; i != entries; i++) {
2731 set_undefined(i);
2732 }
2733}
2734
2735
John Reck59135872010-11-02 12:39:01 -07002736MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002737 if (map()->is_shared()) {
2738 // Fast case maps are never marked as shared.
2739 ASSERT(!HasFastProperties());
2740 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002741 Object* obj;
2742 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2743 UNIQUE_NORMALIZED_MAP);
2744 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2745 }
Steve Block44f0eee2011-05-26 01:26:41 +01002746 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002747
2748 set_map(Map::cast(obj));
2749 }
2750 return map()->UpdateCodeCache(name, code);
2751}
2752
2753
John Reck59135872010-11-02 12:39:01 -07002754MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2755 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002756 if (!HasFastProperties()) return this;
2757
2758 // The global object is always normalized.
2759 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002760 // JSGlobalProxy must never be normalized
2761 ASSERT(!IsJSGlobalProxy());
2762
Ben Murdoch8b112d22011-06-08 16:22:53 +01002763 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01002764
Steve Blocka7e24c12009-10-30 11:49:00 +00002765 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002766 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00002767 if (expected_additional_properties > 0) {
2768 property_count += expected_additional_properties;
2769 } else {
2770 property_count += 2; // Make space for two more properties.
2771 }
John Reck59135872010-11-02 12:39:01 -07002772 Object* obj;
2773 { MaybeObject* maybe_obj =
2774 StringDictionary::Allocate(property_count);
2775 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2776 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002777 StringDictionary* dictionary = StringDictionary::cast(obj);
2778
Ben Murdoch8b112d22011-06-08 16:22:53 +01002779 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002780 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002781 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00002782 switch (details.type()) {
2783 case CONSTANT_FUNCTION: {
2784 PropertyDetails d =
2785 PropertyDetails(details.attributes(), NORMAL, details.index());
2786 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07002787 Object* result;
2788 { MaybeObject* maybe_result =
2789 dictionary->Add(descs->GetKey(i), value, d);
2790 if (!maybe_result->ToObject(&result)) return maybe_result;
2791 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002792 dictionary = StringDictionary::cast(result);
2793 break;
2794 }
2795 case FIELD: {
2796 PropertyDetails d =
2797 PropertyDetails(details.attributes(), NORMAL, details.index());
2798 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07002799 Object* result;
2800 { MaybeObject* maybe_result =
2801 dictionary->Add(descs->GetKey(i), value, d);
2802 if (!maybe_result->ToObject(&result)) return maybe_result;
2803 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002804 dictionary = StringDictionary::cast(result);
2805 break;
2806 }
2807 case CALLBACKS: {
2808 PropertyDetails d =
2809 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2810 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07002811 Object* result;
2812 { MaybeObject* maybe_result =
2813 dictionary->Add(descs->GetKey(i), value, d);
2814 if (!maybe_result->ToObject(&result)) return maybe_result;
2815 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002816 dictionary = StringDictionary::cast(result);
2817 break;
2818 }
2819 case MAP_TRANSITION:
2820 case CONSTANT_TRANSITION:
2821 case NULL_DESCRIPTOR:
2822 case INTERCEPTOR:
Ben Murdoch257744e2011-11-30 15:57:28 +00002823 case EXTERNAL_ARRAY_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002824 break;
2825 default:
2826 UNREACHABLE();
2827 }
2828 }
2829
Ben Murdoch8b112d22011-06-08 16:22:53 +01002830 Heap* current_heap = map_of_this->heap();
2831
Steve Blocka7e24c12009-10-30 11:49:00 +00002832 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002833 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002834 dictionary->SetNextEnumerationIndex(index);
2835
Ben Murdoch8b112d22011-06-08 16:22:53 +01002836 { MaybeObject* maybe_obj =
2837 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01002838 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07002839 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2840 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002841 Map* new_map = Map::cast(obj);
2842
Steve Blocka7e24c12009-10-30 11:49:00 +00002843 // We have now successfully allocated all the necessary objects.
2844 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002845
2846 // Resize the object in the heap if necessary.
2847 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002848 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002849 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002850 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2851 instance_size_delta);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002852
Steve Blocka7e24c12009-10-30 11:49:00 +00002853 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00002854 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002855
2856 set_properties(dictionary);
2857
Ben Murdoch8b112d22011-06-08 16:22:53 +01002858 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002859
2860#ifdef DEBUG
2861 if (FLAG_trace_normalization) {
2862 PrintF("Object properties have been normalized:\n");
2863 Print();
2864 }
2865#endif
2866 return this;
2867}
2868
2869
John Reck59135872010-11-02 12:39:01 -07002870MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002871 if (HasFastProperties()) return this;
2872 ASSERT(!IsGlobalObject());
2873 return property_dictionary()->
2874 TransformPropertiesToFastFor(this, unused_property_fields);
2875}
2876
2877
John Reck59135872010-11-02 12:39:01 -07002878MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002879 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01002880
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002881 // Find the backing store.
2882 FixedArrayBase* array = FixedArrayBase::cast(elements());
2883 Map* old_map = array->map();
2884 bool is_arguments =
2885 (old_map == old_map->heap()->non_strict_arguments_elements_map());
2886 if (is_arguments) {
2887 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07002888 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002889 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00002890
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002891 ASSERT(HasFastElements() ||
2892 HasFastDoubleElements() ||
2893 HasFastArgumentsElements());
2894 // Compute the effective length and allocate a new backing store.
2895 int length = IsJSArray()
2896 ? Smi::cast(JSArray::cast(this)->length())->value()
2897 : array->length();
2898 NumberDictionary* dictionary = NULL;
2899 { Object* object;
2900 MaybeObject* maybe = NumberDictionary::Allocate(length);
2901 if (!maybe->ToObject(&object)) return maybe;
2902 dictionary = NumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07002903 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002904
2905 // Copy the elements to the new backing store.
2906 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00002907 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002908 Object* value = NULL;
2909 if (has_double_elements) {
2910 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
2911 if (double_array->is_the_hole(i)) {
2912 value = GetIsolate()->heap()->the_hole_value();
2913 } else {
2914 // Objects must be allocated in the old object space, since the
2915 // overall number of HeapNumbers needed for the conversion might
2916 // exceed the capacity of new space, and we would fail repeatedly
2917 // trying to convert the FixedDoubleArray.
2918 MaybeObject* maybe_value_object =
2919 GetHeap()->AllocateHeapNumber(double_array->get(i), TENURED);
2920 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07002921 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002922 } else {
2923 ASSERT(old_map->has_fast_elements());
2924 value = FixedArray::cast(array)->get(i);
2925 }
2926 PropertyDetails details = PropertyDetails(NONE, NORMAL);
2927 if (!value->IsTheHole()) {
2928 Object* result;
2929 MaybeObject* maybe_result =
2930 dictionary->AddNumberEntry(i, value, details);
2931 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002932 dictionary = NumberDictionary::cast(result);
2933 }
2934 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002935
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002936 // Switch to using the dictionary as the backing storage for elements.
2937 if (is_arguments) {
2938 FixedArray::cast(elements())->set(1, dictionary);
2939 } else {
2940 // Set the new map first to satify the elements type assert in
2941 // set_elements().
2942 Object* new_map;
2943 MaybeObject* maybe = map()->GetSlowElementsMap();
2944 if (!maybe->ToObject(&new_map)) return maybe;
2945 set_map(Map::cast(new_map));
2946 set_elements(dictionary);
2947 }
2948
2949 old_map->isolate()->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002950
2951#ifdef DEBUG
2952 if (FLAG_trace_normalization) {
2953 PrintF("Object elements have been normalized:\n");
2954 Print();
2955 }
2956#endif
2957
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002958 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
2959 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00002960}
2961
2962
John Reck59135872010-11-02 12:39:01 -07002963MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
2964 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002965 // Check local property, ignore interceptor.
2966 LookupResult result;
2967 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002968 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002969
2970 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07002971 Object* obj;
2972 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
2973 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2974 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002975
2976 return DeleteNormalizedProperty(name, mode);
2977}
2978
2979
John Reck59135872010-11-02 12:39:01 -07002980MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01002981 Isolate* isolate = GetIsolate();
2982 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002983 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2984 Handle<String> name_handle(name);
2985 Handle<JSObject> this_handle(this);
2986 if (!interceptor->deleter()->IsUndefined()) {
2987 v8::NamedPropertyDeleter deleter =
2988 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01002989 LOG(isolate,
2990 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
2991 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002992 v8::AccessorInfo info(args.end());
2993 v8::Handle<v8::Boolean> result;
2994 {
2995 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002996 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002997 result = deleter(v8::Utils::ToLocal(name_handle), info);
2998 }
Steve Block44f0eee2011-05-26 01:26:41 +01002999 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003000 if (!result.IsEmpty()) {
3001 ASSERT(result->IsBoolean());
3002 return *v8::Utils::OpenHandle(*result);
3003 }
3004 }
John Reck59135872010-11-02 12:39:01 -07003005 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003006 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003007 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003008 return raw_result;
3009}
3010
3011
John Reck59135872010-11-02 12:39:01 -07003012MaybeObject* JSObject::DeleteElementPostInterceptor(uint32_t index,
3013 DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003014 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00003015 switch (GetElementsKind()) {
3016 case FAST_ELEMENTS: {
John Reck59135872010-11-02 12:39:01 -07003017 Object* obj;
3018 { MaybeObject* maybe_obj = EnsureWritableFastElements();
3019 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3020 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003021 uint32_t length = IsJSArray() ?
3022 static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) :
3023 static_cast<uint32_t>(FixedArray::cast(elements())->length());
3024 if (index < length) {
3025 FixedArray::cast(elements())->set_the_hole(index);
3026 }
3027 break;
3028 }
3029 case DICTIONARY_ELEMENTS: {
3030 NumberDictionary* dictionary = element_dictionary();
3031 int entry = dictionary->FindEntry(index);
3032 if (entry != NumberDictionary::kNotFound) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003033 Object* deleted = dictionary->DeleteProperty(entry, mode);
3034 if (deleted == GetHeap()->true_value()) {
3035 MaybeObject* maybe_elements = dictionary->Shrink(index);
3036 FixedArray* new_elements = NULL;
3037 if (!maybe_elements->To(&new_elements)) {
3038 return maybe_elements;
3039 }
3040 set_elements(new_elements);
3041 }
3042 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +00003043 }
3044 break;
3045 }
3046 default:
3047 UNREACHABLE();
3048 break;
3049 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003050 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003051}
3052
3053
John Reck59135872010-11-02 12:39:01 -07003054MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003055 Isolate* isolate = GetIsolate();
3056 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003057 // Make sure that the top context does not change when doing
3058 // callbacks or interceptor calls.
3059 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003060 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003061 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003062 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003063 v8::IndexedPropertyDeleter deleter =
3064 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3065 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003066 LOG(isolate,
3067 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3068 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003069 v8::AccessorInfo info(args.end());
3070 v8::Handle<v8::Boolean> result;
3071 {
3072 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003073 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003074 result = deleter(index, info);
3075 }
Steve Block44f0eee2011-05-26 01:26:41 +01003076 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003077 if (!result.IsEmpty()) {
3078 ASSERT(result->IsBoolean());
3079 return *v8::Utils::OpenHandle(*result);
3080 }
John Reck59135872010-11-02 12:39:01 -07003081 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003082 this_handle->DeleteElementPostInterceptor(index, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003083 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003084 return raw_result;
3085}
3086
3087
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003088MaybeObject* JSObject::DeleteFastElement(uint32_t index) {
3089 ASSERT(HasFastElements() || HasFastArgumentsElements());
3090 Heap* heap = GetHeap();
3091 FixedArray* backing_store = FixedArray::cast(elements());
3092 if (backing_store->map() == heap->non_strict_arguments_elements_map()) {
3093 backing_store = FixedArray::cast(backing_store->get(1));
3094 } else {
3095 Object* writable;
3096 MaybeObject* maybe = EnsureWritableFastElements();
3097 if (!maybe->ToObject(&writable)) return maybe;
3098 backing_store = FixedArray::cast(writable);
3099 }
3100 uint32_t length = static_cast<uint32_t>(
3101 IsJSArray()
3102 ? Smi::cast(JSArray::cast(this)->length())->value()
3103 : backing_store->length());
3104 if (index < length) {
3105 backing_store->set_the_hole(index);
3106 // If an old space backing store is larger than a certain size and
3107 // has too few used values, normalize it.
3108 // To avoid doing the check on every delete we require at least
3109 // one adjacent hole to the value being deleted.
3110 Object* hole = heap->the_hole_value();
3111 const int kMinLengthForSparsenessCheck = 64;
3112 if (backing_store->length() >= kMinLengthForSparsenessCheck &&
3113 !heap->InNewSpace(backing_store) &&
3114 ((index > 0 && backing_store->get(index - 1) == hole) ||
3115 (index + 1 < length && backing_store->get(index + 1) == hole))) {
3116 int num_used = 0;
3117 for (int i = 0; i < backing_store->length(); ++i) {
3118 if (backing_store->get(i) != hole) ++num_used;
3119 // Bail out early if more than 1/4 is used.
3120 if (4 * num_used > backing_store->length()) break;
3121 }
3122 if (4 * num_used <= backing_store->length()) {
3123 MaybeObject* result = NormalizeElements();
3124 if (result->IsFailure()) return result;
3125 }
3126 }
3127 }
3128 return heap->true_value();
3129}
3130
3131
3132MaybeObject* JSObject::DeleteDictionaryElement(uint32_t index,
3133 DeleteMode mode) {
3134 Isolate* isolate = GetIsolate();
3135 Heap* heap = isolate->heap();
3136 FixedArray* backing_store = FixedArray::cast(elements());
3137 bool is_arguments =
3138 (GetElementsKind() == JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
3139 if (is_arguments) {
3140 backing_store = FixedArray::cast(backing_store->get(1));
3141 }
3142 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
3143 int entry = dictionary->FindEntry(index);
3144 if (entry != NumberDictionary::kNotFound) {
3145 Object* result = dictionary->DeleteProperty(entry, mode);
3146 if (result == heap->true_value()) {
3147 MaybeObject* maybe_elements = dictionary->Shrink(index);
3148 FixedArray* new_elements = NULL;
3149 if (!maybe_elements->To(&new_elements)) {
3150 return maybe_elements;
3151 }
3152 if (is_arguments) {
3153 FixedArray::cast(elements())->set(1, new_elements);
3154 } else {
3155 set_elements(new_elements);
3156 }
3157 }
3158 if (mode == STRICT_DELETION && result == heap->false_value()) {
3159 // In strict mode, attempting to delete a non-configurable property
3160 // throws an exception.
3161 HandleScope scope(isolate);
3162 Handle<Object> holder(this);
3163 Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
3164 Handle<Object> args[2] = { name, holder };
3165 Handle<Object> error =
3166 isolate->factory()->NewTypeError("strict_delete_property",
3167 HandleVector(args, 2));
3168 return isolate->Throw(*error);
3169 }
3170 }
3171 return heap->true_value();
3172}
3173
3174
John Reck59135872010-11-02 12:39:01 -07003175MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003176 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003177 // Check access rights if needed.
3178 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003179 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3180 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3181 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003182 }
3183
3184 if (IsJSGlobalProxy()) {
3185 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003186 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003187 ASSERT(proto->IsJSGlobalObject());
3188 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3189 }
3190
3191 if (HasIndexedInterceptor()) {
3192 // Skip interceptor if forcing deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003193 return (mode == FORCE_DELETION)
3194 ? DeleteElementPostInterceptor(index, FORCE_DELETION)
3195 : DeleteElementWithInterceptor(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003196 }
3197
3198 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003199 case FAST_ELEMENTS:
3200 return DeleteFastElement(index);
3201
3202 case DICTIONARY_ELEMENTS:
3203 return DeleteDictionaryElement(index, mode);
3204
3205 case FAST_DOUBLE_ELEMENTS: {
3206 int length = IsJSArray()
3207 ? Smi::cast(JSArray::cast(this)->length())->value()
3208 : FixedDoubleArray::cast(elements())->length();
3209 if (index < static_cast<uint32_t>(length)) {
3210 FixedDoubleArray::cast(elements())->set_the_hole(index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003211 }
3212 break;
3213 }
Steve Block44f0eee2011-05-26 01:26:41 +01003214 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003215 case EXTERNAL_BYTE_ELEMENTS:
3216 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3217 case EXTERNAL_SHORT_ELEMENTS:
3218 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3219 case EXTERNAL_INT_ELEMENTS:
3220 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3221 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003222 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003223 // Pixel and external array elements cannot be deleted. Just
3224 // silently ignore here.
Steve Blocka7e24c12009-10-30 11:49:00 +00003225 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003226
3227 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3228 FixedArray* parameter_map = FixedArray::cast(elements());
3229 uint32_t length = parameter_map->length();
3230 Object* probe =
3231 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
3232 if (probe != NULL && !probe->IsTheHole()) {
3233 // TODO(kmillikin): We could check if this was the last aliased
3234 // parameter, and revert to normal elements in that case. That
3235 // would enable GC of the context.
3236 parameter_map->set_the_hole(index + 2);
3237 } else {
3238 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3239 if (arguments->IsDictionary()) {
3240 return DeleteDictionaryElement(index, mode);
3241 } else {
3242 return DeleteFastElement(index);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003243 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003244 }
3245 break;
3246 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003247 }
Steve Block44f0eee2011-05-26 01:26:41 +01003248 return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003249}
3250
3251
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003252MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3253 if (IsJSProxy()) {
3254 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3255 } else {
3256 return JSObject::cast(this)->DeleteProperty(name, mode);
3257 }
3258}
3259
3260
John Reck59135872010-11-02 12:39:01 -07003261MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003262 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003263 // ECMA-262, 3rd, 8.6.2.5
3264 ASSERT(name->IsString());
3265
3266 // Check access rights if needed.
3267 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003268 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3269 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3270 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003271 }
3272
3273 if (IsJSGlobalProxy()) {
3274 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003275 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003276 ASSERT(proto->IsJSGlobalObject());
3277 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3278 }
3279
3280 uint32_t index = 0;
3281 if (name->AsArrayIndex(&index)) {
3282 return DeleteElement(index, mode);
3283 } else {
3284 LookupResult result;
3285 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003286 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003287 // Ignore attributes if forcing a deletion.
3288 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003289 if (mode == STRICT_DELETION) {
3290 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003291 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003292 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003293 return isolate->Throw(*isolate->factory()->NewTypeError(
3294 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003295 }
Steve Block44f0eee2011-05-26 01:26:41 +01003296 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003297 }
3298 // Check for interceptor.
3299 if (result.type() == INTERCEPTOR) {
3300 // Skip interceptor if forcing a deletion.
3301 if (mode == FORCE_DELETION) {
3302 return DeletePropertyPostInterceptor(name, mode);
3303 }
3304 return DeletePropertyWithInterceptor(name);
3305 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003306 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003307 Object* obj;
3308 { MaybeObject* maybe_obj =
3309 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3310 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3311 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003312 // Make sure the properties are normalized before removing the entry.
3313 return DeleteNormalizedProperty(name, mode);
3314 }
3315}
3316
3317
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003318bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3319 ElementsKind kind,
3320 Object* object) {
3321 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
3322 if (kind == FAST_ELEMENTS) {
3323 int length = IsJSArray()
3324 ? Smi::cast(JSArray::cast(this)->length())->value()
3325 : elements->length();
3326 for (int i = 0; i < length; ++i) {
3327 Object* element = elements->get(i);
3328 if (!element->IsTheHole() && element == object) return true;
3329 }
3330 } else {
3331 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
3332 if (!key->IsUndefined()) return true;
3333 }
3334 return false;
3335}
3336
3337
Steve Blocka7e24c12009-10-30 11:49:00 +00003338// Check whether this object references another object.
3339bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003340 Map* map_of_this = map();
3341 Heap* heap = map_of_this->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003342 AssertNoAllocation no_alloc;
3343
3344 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003345 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003346 return true;
3347 }
3348
3349 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003350 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003351 return true;
3352 }
3353
3354 // Check if the object is among the named properties.
3355 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003356 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003357 return true;
3358 }
3359
3360 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003361 ElementsKind kind = GetElementsKind();
3362 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01003363 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003364 case EXTERNAL_BYTE_ELEMENTS:
3365 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3366 case EXTERNAL_SHORT_ELEMENTS:
3367 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3368 case EXTERNAL_INT_ELEMENTS:
3369 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3370 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003371 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003372 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003373 // Raw pixels and external arrays do not reference other
3374 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00003375 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003376 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00003377 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003378 FixedArray* elements = FixedArray::cast(this->elements());
3379 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003380 break;
3381 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003382 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3383 FixedArray* parameter_map = FixedArray::cast(elements());
3384 // Check the mapped parameters.
3385 int length = parameter_map->length();
3386 for (int i = 2; i < length; ++i) {
3387 Object* value = parameter_map->get(i);
3388 if (!value->IsTheHole() && value == obj) return true;
3389 }
3390 // Check the arguments.
3391 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3392 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
3393 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003394 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003395 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003396 }
3397
Steve Block6ded16b2010-05-10 14:33:55 +01003398 // For functions check the context.
3399 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003400 // Get the constructor function for arguments array.
3401 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01003402 heap->isolate()->context()->global_context()->
3403 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003404 JSFunction* arguments_function =
3405 JSFunction::cast(arguments_boilerplate->map()->constructor());
3406
3407 // Get the context and don't check if it is the global context.
3408 JSFunction* f = JSFunction::cast(this);
3409 Context* context = f->context();
3410 if (context->IsGlobalContext()) {
3411 return false;
3412 }
3413
3414 // Check the non-special context slots.
3415 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3416 // Only check JS objects.
3417 if (context->get(i)->IsJSObject()) {
3418 JSObject* ctxobj = JSObject::cast(context->get(i));
3419 // If it is an arguments array check the content.
3420 if (ctxobj->map()->constructor() == arguments_function) {
3421 if (ctxobj->ReferencesObject(obj)) {
3422 return true;
3423 }
3424 } else if (ctxobj == obj) {
3425 return true;
3426 }
3427 }
3428 }
3429
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003430 // Check the context extension (if any) if it can have references.
3431 if (context->has_extension() && !context->IsCatchContext()) {
3432 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00003433 }
3434 }
3435
3436 // No references to object.
3437 return false;
3438}
3439
3440
John Reck59135872010-11-02 12:39:01 -07003441MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01003442 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003443 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003444 !isolate->MayNamedAccess(this,
3445 isolate->heap()->undefined_value(),
3446 v8::ACCESS_KEYS)) {
3447 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3448 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003449 }
3450
Steve Block1e0659c2011-05-24 12:43:12 +01003451 if (IsJSGlobalProxy()) {
3452 Object* proto = GetPrototype();
3453 if (proto->IsNull()) return this;
3454 ASSERT(proto->IsJSGlobalObject());
3455 return JSObject::cast(proto)->PreventExtensions();
3456 }
3457
Ben Murdoch257744e2011-11-30 15:57:28 +00003458 // It's not possible to seal objects with external array elements
3459 if (HasExternalArrayElements()) {
3460 HandleScope scope(isolate);
3461 Handle<Object> object(this);
3462 Handle<Object> error =
3463 isolate->factory()->NewTypeError(
3464 "cant_prevent_ext_external_array_elements",
3465 HandleVector(&object, 1));
3466 return isolate->Throw(*error);
3467 }
3468
Steve Block8defd9f2010-07-08 12:39:36 +01003469 // If there are fast elements we normalize.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003470 NumberDictionary* dictionary = NULL;
3471 { MaybeObject* maybe = NormalizeElements();
3472 if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01003473 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003474 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003475 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003476 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01003477
3478 // Do a map transition, other objects with this map may still
3479 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003480 Map* new_map;
3481 { MaybeObject* maybe = map()->CopyDropTransitions();
3482 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07003483 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003484 new_map->set_is_extensible(false);
3485 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01003486 ASSERT(!map()->is_extensible());
3487 return new_map;
3488}
3489
3490
Steve Blocka7e24c12009-10-30 11:49:00 +00003491// Tests for the fast common case for property enumeration:
Steve Blockd0582a62009-12-15 09:54:21 +00003492// - This object and all prototypes has an enum cache (which means that it has
3493// no interceptors and needs no access checks).
3494// - This object has no elements.
3495// - No prototype has enumerable properties/elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00003496bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003497 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003498 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003499 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003500 o = JSObject::cast(o)->GetPrototype()) {
3501 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003502 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003503 ASSERT(!curr->HasNamedInterceptor());
3504 ASSERT(!curr->HasIndexedInterceptor());
3505 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003506 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003507 if (curr != this) {
3508 FixedArray* curr_fixed_array =
3509 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003510 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003511 }
3512 }
3513 return true;
3514}
3515
3516
3517int Map::NumberOfDescribedProperties() {
3518 int result = 0;
3519 DescriptorArray* descs = instance_descriptors();
3520 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3521 if (descs->IsProperty(i)) result++;
3522 }
3523 return result;
3524}
3525
3526
3527int Map::PropertyIndexFor(String* name) {
3528 DescriptorArray* descs = instance_descriptors();
3529 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3530 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3531 return descs->GetFieldIndex(i);
3532 }
3533 }
3534 return -1;
3535}
3536
3537
3538int Map::NextFreePropertyIndex() {
3539 int max_index = -1;
3540 DescriptorArray* descs = instance_descriptors();
3541 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3542 if (descs->GetType(i) == FIELD) {
3543 int current_index = descs->GetFieldIndex(i);
3544 if (current_index > max_index) max_index = current_index;
3545 }
3546 }
3547 return max_index + 1;
3548}
3549
3550
3551AccessorDescriptor* Map::FindAccessor(String* name) {
3552 DescriptorArray* descs = instance_descriptors();
3553 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3554 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3555 return descs->GetCallbacks(i);
3556 }
3557 }
3558 return NULL;
3559}
3560
3561
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003562void JSReceiver::LocalLookup(String* name, LookupResult* result) {
3563 if (IsJSProxy()) {
3564 result->HandlerResult();
3565 } else {
3566 JSObject::cast(this)->LocalLookup(name, result);
3567 }
3568}
3569
3570
Steve Blocka7e24c12009-10-30 11:49:00 +00003571void JSObject::LocalLookup(String* name, LookupResult* result) {
3572 ASSERT(name->IsString());
3573
Steve Block44f0eee2011-05-26 01:26:41 +01003574 Heap* heap = GetHeap();
3575
Steve Blocka7e24c12009-10-30 11:49:00 +00003576 if (IsJSGlobalProxy()) {
3577 Object* proto = GetPrototype();
3578 if (proto->IsNull()) return result->NotFound();
3579 ASSERT(proto->IsJSGlobalObject());
3580 return JSObject::cast(proto)->LocalLookup(name, result);
3581 }
3582
3583 // Do not use inline caching if the object is a non-global object
3584 // that requires access checks.
3585 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
3586 result->DisallowCaching();
3587 }
3588
3589 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003590 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003591 result->ConstantResult(this);
3592 return;
3593 }
3594
3595 // Check for lookup interceptor except when bootstrapping.
Steve Block44f0eee2011-05-26 01:26:41 +01003596 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003597 result->InterceptorResult(this);
3598 return;
3599 }
3600
3601 LocalLookupRealNamedProperty(name, result);
3602}
3603
3604
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003605void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003606 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003607 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003608 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003609 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003610 current = JSObject::cast(current)->GetPrototype()) {
3611 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003612 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003613 }
3614 result->NotFound();
3615}
3616
3617
3618// Search object and it's prototype chain for callback properties.
3619void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003620 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003621 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003622 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003623 current = JSObject::cast(current)->GetPrototype()) {
3624 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003625 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003626 }
3627 result->NotFound();
3628}
3629
3630
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003631// Search for a getter or setter in an elements dictionary. Returns either
3632// undefined if the element is read-only, or the getter/setter pair (fixed
3633// array) if there is an existing one, or the hole value if the element does
3634// not exist or is a normal non-getter/setter data element.
3635static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary,
3636 uint32_t index,
3637 Heap* heap) {
3638 int entry = dictionary->FindEntry(index);
3639 if (entry != NumberDictionary::kNotFound) {
3640 Object* result = dictionary->ValueAt(entry);
3641 PropertyDetails details = dictionary->DetailsAt(entry);
3642 if (details.IsReadOnly()) return heap->undefined_value();
3643 if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
3644 }
3645 return heap->the_hole_value();
3646}
3647
3648
John Reck59135872010-11-02 12:39:01 -07003649MaybeObject* JSObject::DefineGetterSetter(String* name,
3650 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003651 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003652 // Make sure that the top context does not change when doing callbacks or
3653 // interceptor calls.
3654 AssertNoContextChange ncc;
3655
Steve Blocka7e24c12009-10-30 11:49:00 +00003656 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01003657 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003658
Leon Clarkef7060e22010-06-03 12:02:55 +01003659 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003660 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003661 }
3662
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003663 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003664 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003665
3666 if (is_element) {
3667 switch (GetElementsKind()) {
3668 case FAST_ELEMENTS:
3669 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003670 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003671 case EXTERNAL_BYTE_ELEMENTS:
3672 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3673 case EXTERNAL_SHORT_ELEMENTS:
3674 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3675 case EXTERNAL_INT_ELEMENTS:
3676 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3677 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003678 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003679 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003680 // Ignore getters and setters on pixel and external array
3681 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003682 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003683 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003684 Object* probe =
3685 FindGetterSetterInDictionary(element_dictionary(), index, heap);
3686 if (!probe->IsTheHole()) return probe;
3687 // Otherwise allow to override it.
3688 break;
3689 }
3690 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3691 // Ascertain whether we have read-only properties or an existing
3692 // getter/setter pair in an arguments elements dictionary backing
3693 // store.
3694 FixedArray* parameter_map = FixedArray::cast(elements());
3695 uint32_t length = parameter_map->length();
3696 Object* probe =
3697 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
3698 if (probe == NULL || probe->IsTheHole()) {
3699 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3700 if (arguments->IsDictionary()) {
3701 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
3702 probe = FindGetterSetterInDictionary(dictionary, index, heap);
3703 if (!probe->IsTheHole()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00003704 }
3705 }
3706 break;
3707 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003708 }
3709 } else {
3710 // Lookup the name.
3711 LookupResult result;
3712 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003713 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003714 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003715 if (result.type() == CALLBACKS) {
3716 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01003717 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00003718 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003719 // Use set to update attributes.
3720 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003721 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003722 }
3723 }
3724 }
3725
3726 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07003727 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01003728 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07003729 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3730 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003731
3732 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003733 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003734 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003735 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003736 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003737}
3738
3739
3740bool JSObject::CanSetCallback(String* name) {
3741 ASSERT(!IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01003742 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003743
3744 // Check if there is an API defined callback object which prohibits
3745 // callback overwriting in this object or it's prototype chain.
3746 // This mechanism is needed for instance in a browser setting, where
3747 // certain accessors such as window.location should not be allowed
3748 // to be overwritten because allowing overwriting could potentially
3749 // cause security problems.
3750 LookupResult callback_result;
3751 LookupCallback(name, &callback_result);
3752 if (callback_result.IsProperty()) {
3753 Object* obj = callback_result.GetCallbackObject();
3754 if (obj->IsAccessorInfo() &&
3755 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3756 return false;
3757 }
3758 }
3759
3760 return true;
3761}
3762
3763
John Reck59135872010-11-02 12:39:01 -07003764MaybeObject* JSObject::SetElementCallback(uint32_t index,
3765 Object* structure,
3766 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003767 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3768
3769 // Normalize elements to make this operation simple.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003770 NumberDictionary* dictionary = NULL;
3771 { Object* result;
3772 MaybeObject* maybe = NormalizeElements();
3773 if (!maybe->ToObject(&result)) return maybe;
3774 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003775 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003776 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01003777
3778 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003779 { Object* result;
3780 MaybeObject* maybe = dictionary->Set(index, structure, details);
3781 if (!maybe->ToObject(&result)) return maybe;
3782 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003783 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003784
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003785 dictionary->set_requires_slow_elements();
3786 // Update the dictionary backing store on the object.
3787 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
3788 // Also delete any parameter alias.
3789 //
3790 // TODO(kmillikin): when deleting the last parameter alias we could
3791 // switch to a direct backing store without the parameter map. This
3792 // would allow GC of the context.
3793 FixedArray* parameter_map = FixedArray::cast(elements());
3794 uint32_t length = parameter_map->length();
3795 if (index < length - 2) {
3796 parameter_map->set(index + 2, GetHeap()->the_hole_value());
3797 }
3798 parameter_map->set(1, dictionary);
3799 } else {
3800 set_elements(dictionary);
3801 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003802
3803 return structure;
3804}
3805
3806
John Reck59135872010-11-02 12:39:01 -07003807MaybeObject* JSObject::SetPropertyCallback(String* name,
3808 Object* structure,
3809 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003810 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3811
3812 bool convert_back_to_fast = HasFastProperties() &&
3813 (map()->instance_descriptors()->number_of_descriptors()
3814 < DescriptorArray::kMaxNumberOfDescriptors);
3815
3816 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003817 Object* ok;
3818 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3819 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3820 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003821
3822 // For the global object allocate a new map to invalidate the global inline
3823 // caches which have a global property cell reference directly in the code.
3824 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07003825 Object* new_map;
3826 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3827 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3828 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003829 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003830 // When running crankshaft, changing the map is not enough. We
3831 // need to deoptimize all functions that rely on this global
3832 // object.
3833 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003834 }
3835
3836 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003837 Object* result;
3838 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3839 if (!maybe_result->ToObject(&result)) return maybe_result;
3840 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003841
3842 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07003843 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3844 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3845 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003846 }
3847 return result;
3848}
3849
John Reck59135872010-11-02 12:39:01 -07003850MaybeObject* JSObject::DefineAccessor(String* name,
3851 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01003852 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003853 PropertyAttributes attributes) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003854 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003855 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003856 // Check access rights if needed.
3857 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003858 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3859 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3860 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003861 }
3862
3863 if (IsJSGlobalProxy()) {
3864 Object* proto = GetPrototype();
3865 if (proto->IsNull()) return this;
3866 ASSERT(proto->IsJSGlobalObject());
3867 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3868 fun, attributes);
3869 }
3870
John Reck59135872010-11-02 12:39:01 -07003871 Object* array;
3872 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3873 if (!maybe_array->ToObject(&array)) return maybe_array;
3874 }
3875 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003876 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3877 return this;
3878}
3879
3880
John Reck59135872010-11-02 12:39:01 -07003881MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003882 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003883 String* name = String::cast(info->name());
3884 // Check access rights if needed.
3885 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003886 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3887 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3888 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003889 }
3890
3891 if (IsJSGlobalProxy()) {
3892 Object* proto = GetPrototype();
3893 if (proto->IsNull()) return this;
3894 ASSERT(proto->IsJSGlobalObject());
3895 return JSObject::cast(proto)->DefineAccessor(info);
3896 }
3897
3898 // Make sure that the top context does not change when doing callbacks or
3899 // interceptor calls.
3900 AssertNoContextChange ncc;
3901
3902 // Try to flatten before operating on the string.
3903 name->TryFlatten();
3904
3905 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003906 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003907 }
3908
3909 uint32_t index = 0;
3910 bool is_element = name->AsArrayIndex(&index);
3911
3912 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003913 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003914
3915 // Accessors overwrite previous callbacks (cf. with getters/setters).
3916 switch (GetElementsKind()) {
3917 case FAST_ELEMENTS:
3918 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003919 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003920 case EXTERNAL_BYTE_ELEMENTS:
3921 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3922 case EXTERNAL_SHORT_ELEMENTS:
3923 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3924 case EXTERNAL_INT_ELEMENTS:
3925 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3926 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003927 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003928 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003929 // Ignore getters and setters on pixel and external array
3930 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003931 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003932 case DICTIONARY_ELEMENTS:
3933 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003934 case NON_STRICT_ARGUMENTS_ELEMENTS:
3935 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01003936 break;
3937 }
3938
John Reck59135872010-11-02 12:39:01 -07003939 Object* ok;
3940 { MaybeObject* maybe_ok =
3941 SetElementCallback(index, info, info->property_attributes());
3942 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3943 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003944 } else {
3945 // Lookup the name.
3946 LookupResult result;
3947 LocalLookup(name, &result);
3948 // ES5 forbids turning a property into an accessor if it's not
3949 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3950 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003951 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003952 }
John Reck59135872010-11-02 12:39:01 -07003953 Object* ok;
3954 { MaybeObject* maybe_ok =
3955 SetPropertyCallback(name, info, info->property_attributes());
3956 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3957 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003958 }
3959
3960 return this;
3961}
3962
3963
Steve Blocka7e24c12009-10-30 11:49:00 +00003964Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003965 Heap* heap = GetHeap();
3966
Steve Blocka7e24c12009-10-30 11:49:00 +00003967 // Make sure that the top context does not change when doing callbacks or
3968 // interceptor calls.
3969 AssertNoContextChange ncc;
3970
3971 // Check access rights if needed.
3972 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003973 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3974 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3975 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003976 }
3977
3978 // Make the lookup and include prototypes.
3979 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003980 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003981 if (name->AsArrayIndex(&index)) {
3982 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003983 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003984 obj = JSObject::cast(obj)->GetPrototype()) {
3985 JSObject* js_object = JSObject::cast(obj);
3986 if (js_object->HasDictionaryElements()) {
3987 NumberDictionary* dictionary = js_object->element_dictionary();
3988 int entry = dictionary->FindEntry(index);
3989 if (entry != NumberDictionary::kNotFound) {
3990 Object* element = dictionary->ValueAt(entry);
3991 PropertyDetails details = dictionary->DetailsAt(entry);
3992 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003993 if (element->IsFixedArray()) {
3994 return FixedArray::cast(element)->get(accessor_index);
3995 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003996 }
3997 }
3998 }
3999 }
4000 } else {
4001 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004002 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004003 obj = JSObject::cast(obj)->GetPrototype()) {
4004 LookupResult result;
4005 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00004006 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01004007 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004008 if (result.type() == CALLBACKS) {
4009 Object* obj = result.GetCallbackObject();
4010 if (obj->IsFixedArray()) {
4011 return FixedArray::cast(obj)->get(accessor_index);
4012 }
4013 }
4014 }
4015 }
4016 }
Steve Block44f0eee2011-05-26 01:26:41 +01004017 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004018}
4019
4020
4021Object* JSObject::SlowReverseLookup(Object* value) {
4022 if (HasFastProperties()) {
4023 DescriptorArray* descs = map()->instance_descriptors();
4024 for (int i = 0; i < descs->number_of_descriptors(); i++) {
4025 if (descs->GetType(i) == FIELD) {
4026 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
4027 return descs->GetKey(i);
4028 }
4029 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
4030 if (descs->GetConstantFunction(i) == value) {
4031 return descs->GetKey(i);
4032 }
4033 }
4034 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004035 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004036 } else {
4037 return property_dictionary()->SlowReverseLookup(value);
4038 }
4039}
4040
4041
John Reck59135872010-11-02 12:39:01 -07004042MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01004043 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07004044 Object* result;
4045 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004046 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07004047 if (!maybe_result->ToObject(&result)) return maybe_result;
4048 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004049 Map::cast(result)->set_prototype(prototype());
4050 Map::cast(result)->set_constructor(constructor());
4051 // Don't copy descriptors, so map transitions always remain a forest.
4052 // If we retained the same descriptors we would have two maps
4053 // pointing to the same transition which is bad because the garbage
4054 // collector relies on being able to reverse pointers from transitions
4055 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004056 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004057 // Please note instance_type and instance_size are set when allocated.
4058 Map::cast(result)->set_inobject_properties(inobject_properties());
4059 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4060
4061 // If the map has pre-allocated properties always start out with a descriptor
4062 // array describing these properties.
4063 if (pre_allocated_property_fields() > 0) {
4064 ASSERT(constructor()->IsJSFunction());
4065 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004066 Object* descriptors;
4067 { MaybeObject* maybe_descriptors =
4068 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4069 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4070 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004071 Map::cast(result)->set_instance_descriptors(
4072 DescriptorArray::cast(descriptors));
4073 Map::cast(result)->set_pre_allocated_property_fields(
4074 pre_allocated_property_fields());
4075 }
4076 Map::cast(result)->set_bit_field(bit_field());
4077 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004078 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004079 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004080 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004081 return result;
4082}
4083
4084
John Reck59135872010-11-02 12:39:01 -07004085MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4086 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004087 int new_instance_size = instance_size();
4088 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4089 new_instance_size -= inobject_properties() * kPointerSize;
4090 }
4091
John Reck59135872010-11-02 12:39:01 -07004092 Object* result;
4093 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004094 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004095 if (!maybe_result->ToObject(&result)) return maybe_result;
4096 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004097
4098 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4099 Map::cast(result)->set_inobject_properties(inobject_properties());
4100 }
4101
4102 Map::cast(result)->set_prototype(prototype());
4103 Map::cast(result)->set_constructor(constructor());
4104
4105 Map::cast(result)->set_bit_field(bit_field());
4106 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004107 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004108
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004109 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4110
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004111#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004112 if (Map::cast(result)->is_shared()) {
4113 Map::cast(result)->SharedMapVerify();
4114 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004115#endif
4116
4117 return result;
4118}
4119
4120
John Reck59135872010-11-02 12:39:01 -07004121MaybeObject* Map::CopyDropTransitions() {
4122 Object* new_map;
4123 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4124 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4125 }
4126 Object* descriptors;
4127 { MaybeObject* maybe_descriptors =
4128 instance_descriptors()->RemoveTransitions();
4129 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4130 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004131 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004132 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004133}
4134
4135
John Reck59135872010-11-02 12:39:01 -07004136MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004137 // Allocate the code cache if not present.
4138 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004139 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004140 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004141 if (!maybe_result->ToObject(&result)) return maybe_result;
4142 }
Steve Block6ded16b2010-05-10 14:33:55 +01004143 set_code_cache(result);
4144 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004145
Steve Block6ded16b2010-05-10 14:33:55 +01004146 // Update the code cache.
4147 return CodeCache::cast(code_cache())->Update(name, code);
4148}
4149
4150
4151Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4152 // Do a lookup if a code cache exists.
4153 if (!code_cache()->IsFixedArray()) {
4154 return CodeCache::cast(code_cache())->Lookup(name, flags);
4155 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004156 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004157 }
4158}
4159
4160
4161int Map::IndexInCodeCache(Object* name, Code* code) {
4162 // Get the internal index if a code cache exists.
4163 if (!code_cache()->IsFixedArray()) {
4164 return CodeCache::cast(code_cache())->GetIndex(name, code);
4165 }
4166 return -1;
4167}
4168
4169
4170void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4171 // No GC is supposed to happen between a call to IndexInCodeCache and
4172 // RemoveFromCodeCache so the code cache must be there.
4173 ASSERT(!code_cache()->IsFixedArray());
4174 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4175}
4176
4177
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004178void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Steve Block053d10c2011-06-13 19:13:29 +01004179 // Traverse the transition tree without using a stack. We do this by
4180 // reversing the pointers in the maps and descriptor arrays.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004181 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004182 Map* meta_map = heap()->meta_map();
Steve Block053d10c2011-06-13 19:13:29 +01004183 Object** map_or_index_field = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01004184 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004185 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00004186 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
Steve Block053d10c2011-06-13 19:13:29 +01004187 if (!d->IsEmpty()) {
4188 FixedArray* contents = reinterpret_cast<FixedArray*>(
4189 d->get(DescriptorArray::kContentArrayIndex));
4190 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
4191 Object* map_or_index = *map_or_index_field;
4192 bool map_done = true; // Controls a nested continue statement.
4193 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
4194 i < contents->length();
4195 i += 2) {
4196 PropertyDetails details(Smi::cast(contents->get(i + 1)));
4197 if (details.IsTransition()) {
4198 // Found a map in the transition array. We record our progress in
4199 // the transition array by recording the current map in the map field
4200 // of the next map and recording the index in the transition array in
4201 // the map field of the array.
4202 Map* next = Map::cast(contents->get(i));
4203 next->set_map(current);
4204 *map_or_index_field = Smi::FromInt(i + 2);
4205 current = next;
4206 map_done = false;
4207 break;
4208 }
4209 }
4210 if (!map_done) continue;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004211 } else {
4212 map_or_index_field = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004213 }
Steve Block053d10c2011-06-13 19:13:29 +01004214 // That was the regular transitions, now for the prototype transitions.
4215 FixedArray* prototype_transitions =
4216 current->unchecked_prototype_transitions();
4217 Object** proto_map_or_index_field =
4218 RawField(prototype_transitions, HeapObject::kMapOffset);
4219 Object* map_or_index = *proto_map_or_index_field;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004220 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
Steve Block053d10c2011-06-13 19:13:29 +01004221 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
4222 if (i < prototype_transitions->length()) {
4223 // Found a map in the prototype transition array. Record progress in
4224 // an analogous way to the regular transitions array above.
4225 Object* perhaps_map = prototype_transitions->get(i);
4226 if (perhaps_map->IsMap()) {
4227 Map* next = Map::cast(perhaps_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004228 next->set_map(current);
Steve Block053d10c2011-06-13 19:13:29 +01004229 *proto_map_or_index_field =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004230 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004231 current = next;
Steve Block053d10c2011-06-13 19:13:29 +01004232 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004233 }
4234 }
Steve Block053d10c2011-06-13 19:13:29 +01004235 *proto_map_or_index_field = heap()->fixed_array_map();
4236 if (map_or_index_field != NULL) {
4237 *map_or_index_field = heap()->fixed_array_map();
4238 }
4239
4240 // The callback expects a map to have a real map as its map, so we save
4241 // the map field, which is being used to track the traversal and put the
4242 // correct map (the meta_map) in place while we do the callback.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004243 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01004244 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004245 callback(current, data);
4246 current = prev;
4247 }
4248}
4249
4250
John Reck59135872010-11-02 12:39:01 -07004251MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004252 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4253 // a large number and therefore they need to go into a hash table. They are
4254 // used to load global properties from cells.
4255 if (code->type() == NORMAL) {
4256 // Make sure that a hash table is allocated for the normal load code cache.
4257 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07004258 Object* result;
4259 { MaybeObject* maybe_result =
4260 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4261 if (!maybe_result->ToObject(&result)) return maybe_result;
4262 }
Steve Block6ded16b2010-05-10 14:33:55 +01004263 set_normal_type_cache(result);
4264 }
4265 return UpdateNormalTypeCache(name, code);
4266 } else {
4267 ASSERT(default_cache()->IsFixedArray());
4268 return UpdateDefaultCache(name, code);
4269 }
4270}
4271
4272
John Reck59135872010-11-02 12:39:01 -07004273MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004274 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00004275 // flags. This allows call constant stubs to overwrite call field
4276 // stubs, etc.
4277 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4278
4279 // First check whether we can update existing code cache without
4280 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01004281 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004282 int length = cache->length();
4283 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01004284 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004285 Object* key = cache->get(i);
4286 if (key->IsNull()) {
4287 if (deleted_index < 0) deleted_index = i;
4288 continue;
4289 }
4290 if (key->IsUndefined()) {
4291 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01004292 cache->set(i + kCodeCacheEntryNameOffset, name);
4293 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004294 return this;
4295 }
4296 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004297 Code::Flags found =
4298 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00004299 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01004300 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004301 return this;
4302 }
4303 }
4304 }
4305
4306 // Reached the end of the code cache. If there were deleted
4307 // elements, reuse the space for the first of them.
4308 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01004309 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4310 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004311 return this;
4312 }
4313
Steve Block6ded16b2010-05-10 14:33:55 +01004314 // Extend the code cache with some new entries (at least one). Must be a
4315 // multiple of the entry size.
4316 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4317 new_length = new_length - new_length % kCodeCacheEntrySize;
4318 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07004319 Object* result;
4320 { MaybeObject* maybe_result = cache->CopySize(new_length);
4321 if (!maybe_result->ToObject(&result)) return maybe_result;
4322 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004323
4324 // Add the (name, code) pair to the new cache.
4325 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01004326 cache->set(length + kCodeCacheEntryNameOffset, name);
4327 cache->set(length + kCodeCacheEntryCodeOffset, code);
4328 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00004329 return this;
4330}
4331
4332
John Reck59135872010-11-02 12:39:01 -07004333MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004334 // Adding a new entry can cause a new cache to be allocated.
4335 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07004336 Object* new_cache;
4337 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4338 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4339 }
Steve Block6ded16b2010-05-10 14:33:55 +01004340 set_normal_type_cache(new_cache);
4341 return this;
4342}
4343
4344
4345Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4346 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4347 return LookupNormalTypeCache(name, flags);
4348 } else {
4349 return LookupDefaultCache(name, flags);
4350 }
4351}
4352
4353
4354Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4355 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004356 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004357 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4358 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00004359 // Skip deleted elements.
4360 if (key->IsNull()) continue;
4361 if (key->IsUndefined()) return key;
4362 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004363 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4364 if (code->flags() == flags) {
4365 return code;
4366 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004367 }
4368 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004369 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004370}
4371
4372
Steve Block6ded16b2010-05-10 14:33:55 +01004373Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4374 if (!normal_type_cache()->IsUndefined()) {
4375 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4376 return cache->Lookup(name, flags);
4377 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004378 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004379 }
4380}
4381
4382
4383int CodeCache::GetIndex(Object* name, Code* code) {
4384 if (code->type() == NORMAL) {
4385 if (normal_type_cache()->IsUndefined()) return -1;
4386 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4387 return cache->GetIndex(String::cast(name), code->flags());
4388 }
4389
4390 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004391 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004392 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4393 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004394 }
4395 return -1;
4396}
4397
4398
Steve Block6ded16b2010-05-10 14:33:55 +01004399void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
4400 if (code->type() == NORMAL) {
4401 ASSERT(!normal_type_cache()->IsUndefined());
4402 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4403 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
4404 cache->RemoveByIndex(index);
4405 } else {
4406 FixedArray* array = default_cache();
4407 ASSERT(array->length() >= index && array->get(index)->IsCode());
4408 // Use null instead of undefined for deleted elements to distinguish
4409 // deleted elements from unused elements. This distinction is used
4410 // when looking up in the cache and when updating the cache.
4411 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4412 array->set_null(index - 1); // Name.
4413 array->set_null(index); // Code.
4414 }
4415}
4416
4417
4418// The key in the code cache hash table consists of the property name and the
4419// code object. The actual match is on the name and the code flags. If a key
4420// is created using the flags and not a code object it can only be used for
4421// lookup not to create a new entry.
4422class CodeCacheHashTableKey : public HashTableKey {
4423 public:
4424 CodeCacheHashTableKey(String* name, Code::Flags flags)
4425 : name_(name), flags_(flags), code_(NULL) { }
4426
4427 CodeCacheHashTableKey(String* name, Code* code)
4428 : name_(name),
4429 flags_(code->flags()),
4430 code_(code) { }
4431
4432
4433 bool IsMatch(Object* other) {
4434 if (!other->IsFixedArray()) return false;
4435 FixedArray* pair = FixedArray::cast(other);
4436 String* name = String::cast(pair->get(0));
4437 Code::Flags flags = Code::cast(pair->get(1))->flags();
4438 if (flags != flags_) {
4439 return false;
4440 }
4441 return name_->Equals(name);
4442 }
4443
4444 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4445 return name->Hash() ^ flags;
4446 }
4447
4448 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4449
4450 uint32_t HashForObject(Object* obj) {
4451 FixedArray* pair = FixedArray::cast(obj);
4452 String* name = String::cast(pair->get(0));
4453 Code* code = Code::cast(pair->get(1));
4454 return NameFlagsHashHelper(name, code->flags());
4455 }
4456
John Reck59135872010-11-02 12:39:01 -07004457 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01004458 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07004459 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004460 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07004461 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4462 }
Steve Block6ded16b2010-05-10 14:33:55 +01004463 FixedArray* pair = FixedArray::cast(obj);
4464 pair->set(0, name_);
4465 pair->set(1, code_);
4466 return pair;
4467 }
4468
4469 private:
4470 String* name_;
4471 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004472 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01004473 Code* code_;
4474};
4475
4476
4477Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4478 CodeCacheHashTableKey key(name, flags);
4479 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01004480 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004481 return get(EntryToIndex(entry) + 1);
4482}
4483
4484
John Reck59135872010-11-02 12:39:01 -07004485MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004486 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07004487 Object* obj;
4488 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4489 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4490 }
Steve Block6ded16b2010-05-10 14:33:55 +01004491
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004492 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01004493 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4494
4495 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004496 Object* k;
4497 { MaybeObject* maybe_k = key.AsObject();
4498 if (!maybe_k->ToObject(&k)) return maybe_k;
4499 }
Steve Block6ded16b2010-05-10 14:33:55 +01004500
4501 cache->set(EntryToIndex(entry), k);
4502 cache->set(EntryToIndex(entry) + 1, code);
4503 cache->ElementAdded();
4504 return cache;
4505}
4506
4507
4508int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4509 CodeCacheHashTableKey key(name, flags);
4510 int entry = FindEntry(&key);
4511 return (entry == kNotFound) ? -1 : entry;
4512}
4513
4514
4515void CodeCacheHashTable::RemoveByIndex(int index) {
4516 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004517 Heap* heap = GetHeap();
4518 set(EntryToIndex(index), heap->null_value());
4519 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004520 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004521}
4522
4523
Steve Blocka7e24c12009-10-30 11:49:00 +00004524static bool HasKey(FixedArray* array, Object* key) {
4525 int len0 = array->length();
4526 for (int i = 0; i < len0; i++) {
4527 Object* element = array->get(i);
4528 if (element->IsSmi() && key->IsSmi() && (element == key)) return true;
4529 if (element->IsString() &&
4530 key->IsString() && String::cast(element)->Equals(String::cast(key))) {
4531 return true;
4532 }
4533 }
4534 return false;
4535}
4536
4537
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004538MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4539 Code::Flags flags,
4540 Code* code) {
4541 // Initialize cache if necessary.
4542 if (cache()->IsUndefined()) {
4543 Object* result;
4544 { MaybeObject* maybe_result =
4545 PolymorphicCodeCacheHashTable::Allocate(
4546 PolymorphicCodeCacheHashTable::kInitialSize);
4547 if (!maybe_result->ToObject(&result)) return maybe_result;
4548 }
4549 set_cache(result);
4550 } else {
4551 // This entry shouldn't be contained in the cache yet.
4552 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4553 ->Lookup(maps, flags)->IsUndefined());
4554 }
4555 PolymorphicCodeCacheHashTable* hash_table =
4556 PolymorphicCodeCacheHashTable::cast(cache());
4557 Object* new_cache;
4558 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4559 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4560 }
4561 set_cache(new_cache);
4562 return this;
4563}
4564
4565
4566Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4567 if (!cache()->IsUndefined()) {
4568 PolymorphicCodeCacheHashTable* hash_table =
4569 PolymorphicCodeCacheHashTable::cast(cache());
4570 return hash_table->Lookup(maps, flags);
4571 } else {
4572 return GetHeap()->undefined_value();
4573 }
4574}
4575
4576
4577// Despite their name, object of this class are not stored in the actual
4578// hash table; instead they're temporarily used for lookups. It is therefore
4579// safe to have a weak (non-owning) pointer to a MapList as a member field.
4580class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4581 public:
4582 // Callers must ensure that |maps| outlives the newly constructed object.
4583 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4584 : maps_(maps),
4585 code_flags_(code_flags) {}
4586
4587 bool IsMatch(Object* other) {
4588 MapList other_maps(kDefaultListAllocationSize);
4589 int other_flags;
4590 FromObject(other, &other_flags, &other_maps);
4591 if (code_flags_ != other_flags) return false;
4592 if (maps_->length() != other_maps.length()) return false;
4593 // Compare just the hashes first because it's faster.
4594 int this_hash = MapsHashHelper(maps_, code_flags_);
4595 int other_hash = MapsHashHelper(&other_maps, other_flags);
4596 if (this_hash != other_hash) return false;
4597
4598 // Full comparison: for each map in maps_, look for an equivalent map in
4599 // other_maps. This implementation is slow, but probably good enough for
4600 // now because the lists are short (<= 4 elements currently).
4601 for (int i = 0; i < maps_->length(); ++i) {
4602 bool match_found = false;
4603 for (int j = 0; j < other_maps.length(); ++j) {
4604 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
4605 match_found = true;
4606 break;
4607 }
4608 }
4609 if (!match_found) return false;
4610 }
4611 return true;
4612 }
4613
4614 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4615 uint32_t hash = code_flags;
4616 for (int i = 0; i < maps->length(); ++i) {
4617 hash ^= maps->at(i)->Hash();
4618 }
4619 return hash;
4620 }
4621
4622 uint32_t Hash() {
4623 return MapsHashHelper(maps_, code_flags_);
4624 }
4625
4626 uint32_t HashForObject(Object* obj) {
4627 MapList other_maps(kDefaultListAllocationSize);
4628 int other_flags;
4629 FromObject(obj, &other_flags, &other_maps);
4630 return MapsHashHelper(&other_maps, other_flags);
4631 }
4632
4633 MUST_USE_RESULT MaybeObject* AsObject() {
4634 Object* obj;
4635 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4636 // both because the referenced MapList is short-lived, and because C++
4637 // objects can't be stored in the heap anyway.
4638 { MaybeObject* maybe_obj =
4639 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4640 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4641 }
4642 FixedArray* list = FixedArray::cast(obj);
4643 list->set(0, Smi::FromInt(code_flags_));
4644 for (int i = 0; i < maps_->length(); ++i) {
4645 list->set(i + 1, maps_->at(i));
4646 }
4647 return list;
4648 }
4649
4650 private:
4651 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4652 FixedArray* list = FixedArray::cast(obj);
4653 maps->Rewind(0);
4654 *code_flags = Smi::cast(list->get(0))->value();
4655 for (int i = 1; i < list->length(); ++i) {
4656 maps->Add(Map::cast(list->get(i)));
4657 }
4658 return maps;
4659 }
4660
4661 MapList* maps_; // weak.
4662 int code_flags_;
4663 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
4664};
4665
4666
4667Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4668 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4669 int entry = FindEntry(&key);
4670 if (entry == kNotFound) return GetHeap()->undefined_value();
4671 return get(EntryToIndex(entry) + 1);
4672}
4673
4674
4675MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4676 int code_flags,
4677 Code* code) {
4678 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4679 Object* obj;
4680 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4681 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4682 }
4683 PolymorphicCodeCacheHashTable* cache =
4684 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4685 int entry = cache->FindInsertionEntry(key.Hash());
4686 { MaybeObject* maybe_obj = key.AsObject();
4687 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4688 }
4689 cache->set(EntryToIndex(entry), obj);
4690 cache->set(EntryToIndex(entry) + 1, code);
4691 cache->ElementAdded();
4692 return cache;
4693}
4694
4695
John Reck59135872010-11-02 12:39:01 -07004696MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Steve Block44f0eee2011-05-26 01:26:41 +01004697 ASSERT(!array->HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00004698 switch (array->GetElementsKind()) {
4699 case JSObject::FAST_ELEMENTS:
4700 return UnionOfKeys(FixedArray::cast(array->elements()));
4701 case JSObject::DICTIONARY_ELEMENTS: {
4702 NumberDictionary* dict = array->element_dictionary();
4703 int size = dict->NumberOfElements();
4704
4705 // Allocate a temporary fixed array.
John Reck59135872010-11-02 12:39:01 -07004706 Object* object;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004707 { MaybeObject* maybe_object = GetHeap()->AllocateFixedArray(size);
John Reck59135872010-11-02 12:39:01 -07004708 if (!maybe_object->ToObject(&object)) return maybe_object;
4709 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004710 FixedArray* key_array = FixedArray::cast(object);
4711
4712 int capacity = dict->Capacity();
4713 int pos = 0;
4714 // Copy the elements from the JSArray to the temporary fixed array.
4715 for (int i = 0; i < capacity; i++) {
4716 if (dict->IsKey(dict->KeyAt(i))) {
4717 key_array->set(pos++, dict->ValueAt(i));
4718 }
4719 }
4720 // Compute the union of this and the temporary fixed array.
4721 return UnionOfKeys(key_array);
4722 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004723 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
4724 UNIMPLEMENTED();
4725 break;
4726 case JSObject::EXTERNAL_BYTE_ELEMENTS:
4727 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
4728 case JSObject::EXTERNAL_SHORT_ELEMENTS:
4729 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
4730 case JSObject::EXTERNAL_INT_ELEMENTS:
4731 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
4732 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
4733 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
4734 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
4735 case JSObject::FAST_DOUBLE_ELEMENTS:
4736 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00004737 }
4738 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01004739 return GetHeap()->null_value(); // Failure case needs to "return" a value.
Steve Blocka7e24c12009-10-30 11:49:00 +00004740}
4741
4742
John Reck59135872010-11-02 12:39:01 -07004743MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004744 int len0 = length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004745#ifdef DEBUG
4746 if (FLAG_enable_slow_asserts) {
4747 for (int i = 0; i < len0; i++) {
4748 ASSERT(get(i)->IsString() || get(i)->IsNumber());
4749 }
4750 }
4751#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004752 int len1 = other->length();
Ben Murdochf87a2032010-10-22 12:50:53 +01004753 // Optimize if 'other' is empty.
4754 // We cannot optimize if 'this' is empty, as other may have holes
4755 // or non keys.
Steve Blocka7e24c12009-10-30 11:49:00 +00004756 if (len1 == 0) return this;
4757
4758 // Compute how many elements are not in this.
4759 int extra = 0;
4760 for (int y = 0; y < len1; y++) {
4761 Object* value = other->get(y);
4762 if (!value->IsTheHole() && !HasKey(this, value)) extra++;
4763 }
4764
4765 if (extra == 0) return this;
4766
4767 // Allocate the result
John Reck59135872010-11-02 12:39:01 -07004768 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004769 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(len0 + extra);
John Reck59135872010-11-02 12:39:01 -07004770 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4771 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004772 // Fill in the content
Leon Clarke4515c472010-02-03 11:58:03 +00004773 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004774 FixedArray* result = FixedArray::cast(obj);
Leon Clarke4515c472010-02-03 11:58:03 +00004775 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004776 for (int i = 0; i < len0; i++) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004777 Object* e = get(i);
4778 ASSERT(e->IsString() || e->IsNumber());
4779 result->set(i, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004780 }
4781 // Fill in the extra keys.
4782 int index = 0;
4783 for (int y = 0; y < len1; y++) {
4784 Object* value = other->get(y);
4785 if (!value->IsTheHole() && !HasKey(this, value)) {
Ben Murdochf87a2032010-10-22 12:50:53 +01004786 Object* e = other->get(y);
4787 ASSERT(e->IsString() || e->IsNumber());
4788 result->set(len0 + index, e, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00004789 index++;
4790 }
4791 }
4792 ASSERT(extra == index);
4793 return result;
4794}
4795
4796
John Reck59135872010-11-02 12:39:01 -07004797MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004798 Heap* heap = GetHeap();
4799 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004800 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004801 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004802 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4803 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004804 FixedArray* result = FixedArray::cast(obj);
4805 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004806 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004807 int len = length();
4808 if (new_length < len) len = new_length;
4809 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004810 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004811 for (int i = 0; i < len; i++) {
4812 result->set(i, get(i), mode);
4813 }
4814 return result;
4815}
4816
4817
4818void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004819 AssertNoAllocation no_gc;
4820 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004821 for (int index = 0; index < len; index++) {
4822 dest->set(dest_pos+index, get(pos+index), mode);
4823 }
4824}
4825
4826
4827#ifdef DEBUG
4828bool FixedArray::IsEqualTo(FixedArray* other) {
4829 if (length() != other->length()) return false;
4830 for (int i = 0 ; i < length(); ++i) {
4831 if (get(i) != other->get(i)) return false;
4832 }
4833 return true;
4834}
4835#endif
4836
4837
John Reck59135872010-11-02 12:39:01 -07004838MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004839 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004840 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004841 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004842 }
4843 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004844 Object* array;
4845 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004846 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004847 if (!maybe_array->ToObject(&array)) return maybe_array;
4848 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004849 // Do not use DescriptorArray::cast on incomplete object.
4850 FixedArray* result = FixedArray::cast(array);
4851
4852 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004853 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004854 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004855 if (!maybe_array->ToObject(&array)) return maybe_array;
4856 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004857 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00004858 result->set(kContentArrayIndex, array);
4859 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004860 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004861 return result;
4862}
4863
4864
4865void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4866 FixedArray* new_cache) {
4867 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4868 if (HasEnumCache()) {
4869 FixedArray::cast(get(kEnumerationIndexIndex))->
4870 set(kEnumCacheBridgeCacheIndex, new_cache);
4871 } else {
4872 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4873 FixedArray::cast(bridge_storage)->
4874 set(kEnumCacheBridgeCacheIndex, new_cache);
4875 fast_set(FixedArray::cast(bridge_storage),
4876 kEnumCacheBridgeEnumIndex,
4877 get(kEnumerationIndexIndex));
4878 set(kEnumerationIndexIndex, bridge_storage);
4879 }
4880}
4881
4882
John Reck59135872010-11-02 12:39:01 -07004883MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4884 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004885 // Transitions are only kept when inserting another transition.
4886 // This precondition is not required by this function's implementation, but
4887 // is currently required by the semantics of maps, so we check it.
4888 // Conversely, we filter after replacing, so replacing a transition and
4889 // removing all other transitions is not supported.
4890 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4891 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4892 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4893
4894 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004895 Object* result;
4896 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4897 if (!maybe_result->ToObject(&result)) return maybe_result;
4898 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004899
4900 int transitions = 0;
4901 int null_descriptors = 0;
4902 if (remove_transitions) {
4903 for (int i = 0; i < number_of_descriptors(); i++) {
4904 if (IsTransition(i)) transitions++;
4905 if (IsNullDescriptor(i)) null_descriptors++;
4906 }
4907 } else {
4908 for (int i = 0; i < number_of_descriptors(); i++) {
4909 if (IsNullDescriptor(i)) null_descriptors++;
4910 }
4911 }
4912 int new_size = number_of_descriptors() - transitions - null_descriptors;
4913
4914 // If key is in descriptor, we replace it in-place when filtering.
4915 // Count a null descriptor for key as inserted, not replaced.
4916 int index = Search(descriptor->GetKey());
4917 const bool inserting = (index == kNotFound);
4918 const bool replacing = !inserting;
4919 bool keep_enumeration_index = false;
4920 if (inserting) {
4921 ++new_size;
4922 }
4923 if (replacing) {
4924 // We are replacing an existing descriptor. We keep the enumeration
4925 // index of a visible property.
4926 PropertyType t = PropertyDetails(GetDetails(index)).type();
4927 if (t == CONSTANT_FUNCTION ||
4928 t == FIELD ||
4929 t == CALLBACKS ||
4930 t == INTERCEPTOR) {
4931 keep_enumeration_index = true;
4932 } else if (remove_transitions) {
4933 // Replaced descriptor has been counted as removed if it is
4934 // a transition that will be replaced. Adjust count in this case.
4935 ++new_size;
4936 }
4937 }
John Reck59135872010-11-02 12:39:01 -07004938 { MaybeObject* maybe_result = Allocate(new_size);
4939 if (!maybe_result->ToObject(&result)) return maybe_result;
4940 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004941 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4942 // Set the enumeration index in the descriptors and set the enumeration index
4943 // in the result.
4944 int enumeration_index = NextEnumerationIndex();
4945 if (!descriptor->GetDetails().IsTransition()) {
4946 if (keep_enumeration_index) {
4947 descriptor->SetEnumerationIndex(
4948 PropertyDetails(GetDetails(index)).index());
4949 } else {
4950 descriptor->SetEnumerationIndex(enumeration_index);
4951 ++enumeration_index;
4952 }
4953 }
4954 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4955
4956 // Copy the descriptors, filtering out transitions and null descriptors,
4957 // and inserting or replacing a descriptor.
4958 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4959 int from_index = 0;
4960 int to_index = 0;
4961
4962 for (; from_index < number_of_descriptors(); from_index++) {
4963 String* key = GetKey(from_index);
4964 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4965 break;
4966 }
4967 if (IsNullDescriptor(from_index)) continue;
4968 if (remove_transitions && IsTransition(from_index)) continue;
4969 new_descriptors->CopyFrom(to_index++, this, from_index);
4970 }
4971
4972 new_descriptors->Set(to_index++, descriptor);
4973 if (replacing) from_index++;
4974
4975 for (; from_index < number_of_descriptors(); from_index++) {
4976 if (IsNullDescriptor(from_index)) continue;
4977 if (remove_transitions && IsTransition(from_index)) continue;
4978 new_descriptors->CopyFrom(to_index++, this, from_index);
4979 }
4980
4981 ASSERT(to_index == new_descriptors->number_of_descriptors());
4982 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4983
4984 return new_descriptors;
4985}
4986
4987
John Reck59135872010-11-02 12:39:01 -07004988MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004989 // Remove all transitions and null descriptors. Return a copy of the array
4990 // with all transitions removed, or a Failure object if the new array could
4991 // not be allocated.
4992
4993 // Compute the size of the map transition entries to be removed.
4994 int num_removed = 0;
4995 for (int i = 0; i < number_of_descriptors(); i++) {
4996 if (!IsProperty(i)) num_removed++;
4997 }
4998
4999 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07005000 Object* result;
5001 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
5002 if (!maybe_result->ToObject(&result)) return maybe_result;
5003 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005004 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
5005
5006 // Copy the content.
5007 int next_descriptor = 0;
5008 for (int i = 0; i < number_of_descriptors(); i++) {
5009 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
5010 }
5011 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
5012
5013 return new_descriptors;
5014}
5015
5016
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005017void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005018 // In-place heap sort.
5019 int len = number_of_descriptors();
5020
5021 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01005022 // Index of the last node with children
5023 const int max_parent_index = (len / 2) - 1;
5024 for (int i = max_parent_index; i >= 0; --i) {
5025 int parent_index = i;
5026 const uint32_t parent_hash = GetKey(i)->Hash();
5027 while (parent_index <= max_parent_index) {
5028 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00005029 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01005030 if (child_index + 1 < len) {
5031 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5032 if (right_child_hash > child_hash) {
5033 child_index++;
5034 child_hash = right_child_hash;
5035 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005036 }
Steve Block6ded16b2010-05-10 14:33:55 +01005037 if (child_hash <= parent_hash) break;
5038 Swap(parent_index, child_index);
5039 // Now element at child_index could be < its children.
5040 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00005041 }
5042 }
5043
5044 // Extract elements and create sorted array.
5045 for (int i = len - 1; i > 0; --i) {
5046 // Put max element at the back of the array.
5047 Swap(0, i);
5048 // Sift down the new top element.
5049 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01005050 const uint32_t parent_hash = GetKey(parent_index)->Hash();
5051 const int max_parent_index = (i / 2) - 1;
5052 while (parent_index <= max_parent_index) {
5053 int child_index = parent_index * 2 + 1;
5054 uint32_t child_hash = GetKey(child_index)->Hash();
5055 if (child_index + 1 < i) {
5056 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
5057 if (right_child_hash > child_hash) {
5058 child_index++;
5059 child_hash = right_child_hash;
5060 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005061 }
Steve Block6ded16b2010-05-10 14:33:55 +01005062 if (child_hash <= parent_hash) break;
5063 Swap(parent_index, child_index);
5064 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00005065 }
5066 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005067}
Steve Blocka7e24c12009-10-30 11:49:00 +00005068
Kristian Monsen0d5e1162010-09-30 15:31:59 +01005069
5070void DescriptorArray::Sort() {
5071 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00005072 SLOW_ASSERT(IsSortedNoDuplicates());
5073}
5074
5075
5076int DescriptorArray::BinarySearch(String* name, int low, int high) {
5077 uint32_t hash = name->Hash();
5078
5079 while (low <= high) {
5080 int mid = (low + high) / 2;
5081 String* mid_name = GetKey(mid);
5082 uint32_t mid_hash = mid_name->Hash();
5083
5084 if (mid_hash > hash) {
5085 high = mid - 1;
5086 continue;
5087 }
5088 if (mid_hash < hash) {
5089 low = mid + 1;
5090 continue;
5091 }
5092 // Found an element with the same hash-code.
5093 ASSERT(hash == mid_hash);
5094 // There might be more, so we find the first one and
5095 // check them all to see if we have a match.
5096 if (name == mid_name && !is_null_descriptor(mid)) return mid;
5097 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
5098 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
5099 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
5100 }
5101 break;
5102 }
5103 return kNotFound;
5104}
5105
5106
5107int DescriptorArray::LinearSearch(String* name, int len) {
5108 uint32_t hash = name->Hash();
5109 for (int number = 0; number < len; number++) {
5110 String* entry = GetKey(number);
5111 if ((entry->Hash() == hash) &&
5112 name->Equals(entry) &&
5113 !is_null_descriptor(number)) {
5114 return number;
5115 }
5116 }
5117 return kNotFound;
5118}
5119
5120
Ben Murdochb0fe1622011-05-05 13:52:32 +01005121MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
5122 PretenureFlag pretenure) {
5123 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01005124 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005125 pretenure);
5126}
5127
5128
5129MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5130 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005131 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5132 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005133 pretenure);
5134}
5135
5136
Steve Blocka7e24c12009-10-30 11:49:00 +00005137#ifdef DEBUG
5138bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5139 if (IsEmpty()) return other->IsEmpty();
5140 if (other->IsEmpty()) return false;
5141 if (length() != other->length()) return false;
5142 for (int i = 0; i < length(); ++i) {
5143 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5144 }
5145 return GetContentArray()->IsEqualTo(other->GetContentArray());
5146}
5147#endif
5148
5149
Steve Blocka7e24c12009-10-30 11:49:00 +00005150bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01005151 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005152 return true;
5153}
5154
5155
5156int String::Utf8Length() {
5157 if (IsAsciiRepresentation()) return length();
5158 // Attempt to flatten before accessing the string. It probably
5159 // doesn't make Utf8Length faster, but it is very likely that
5160 // the string will be accessed later (for example by WriteUtf8)
5161 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01005162 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01005163 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01005164 Access<StringInputBuffer> buffer(
5165 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005166 buffer->Reset(0, this);
5167 int result = 0;
5168 while (buffer->has_more())
5169 result += unibrow::Utf8::Length(buffer->GetNext());
5170 return result;
5171}
5172
5173
5174Vector<const char> String::ToAsciiVector() {
5175 ASSERT(IsAsciiRepresentation());
5176 ASSERT(IsFlat());
5177
5178 int offset = 0;
5179 int length = this->length();
5180 StringRepresentationTag string_tag = StringShape(this).representation_tag();
5181 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00005182 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005183 ConsString* cons = ConsString::cast(string);
5184 ASSERT(cons->second()->length() == 0);
5185 string = cons->first();
5186 string_tag = StringShape(string).representation_tag();
5187 }
5188 if (string_tag == kSeqStringTag) {
5189 SeqAsciiString* seq = SeqAsciiString::cast(string);
5190 char* start = seq->GetChars();
5191 return Vector<const char>(start + offset, length);
5192 }
5193 ASSERT(string_tag == kExternalStringTag);
5194 ExternalAsciiString* ext = ExternalAsciiString::cast(string);
5195 const char* start = ext->resource()->data();
5196 return Vector<const char>(start + offset, length);
5197}
5198
5199
5200Vector<const uc16> String::ToUC16Vector() {
5201 ASSERT(IsTwoByteRepresentation());
5202 ASSERT(IsFlat());
5203
5204 int offset = 0;
5205 int length = this->length();
5206 StringRepresentationTag string_tag = StringShape(this).representation_tag();
5207 String* string = this;
Steve Blockd0582a62009-12-15 09:54:21 +00005208 if (string_tag == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005209 ConsString* cons = ConsString::cast(string);
5210 ASSERT(cons->second()->length() == 0);
5211 string = cons->first();
5212 string_tag = StringShape(string).representation_tag();
5213 }
5214 if (string_tag == kSeqStringTag) {
5215 SeqTwoByteString* seq = SeqTwoByteString::cast(string);
5216 return Vector<const uc16>(seq->GetChars() + offset, length);
5217 }
5218 ASSERT(string_tag == kExternalStringTag);
5219 ExternalTwoByteString* ext = ExternalTwoByteString::cast(string);
5220 const uc16* start =
5221 reinterpret_cast<const uc16*>(ext->resource()->data());
5222 return Vector<const uc16>(start + offset, length);
5223}
5224
5225
5226SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5227 RobustnessFlag robust_flag,
5228 int offset,
5229 int length,
5230 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005231 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
5232 return SmartPointer<char>(NULL);
5233 }
Steve Block44f0eee2011-05-26 01:26:41 +01005234 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005235
5236 // Negative length means the to the end of the string.
5237 if (length < 0) length = kMaxInt - offset;
5238
5239 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01005240 Access<StringInputBuffer> buffer(
5241 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005242 buffer->Reset(offset, this);
5243 int character_position = offset;
5244 int utf8_bytes = 0;
5245 while (buffer->has_more()) {
5246 uint16_t character = buffer->GetNext();
5247 if (character_position < offset + length) {
5248 utf8_bytes += unibrow::Utf8::Length(character);
5249 }
5250 character_position++;
5251 }
5252
5253 if (length_return) {
5254 *length_return = utf8_bytes;
5255 }
5256
5257 char* result = NewArray<char>(utf8_bytes + 1);
5258
5259 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5260 buffer->Rewind();
5261 buffer->Seek(offset);
5262 character_position = offset;
5263 int utf8_byte_position = 0;
5264 while (buffer->has_more()) {
5265 uint16_t character = buffer->GetNext();
5266 if (character_position < offset + length) {
5267 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5268 character = ' ';
5269 }
5270 utf8_byte_position +=
5271 unibrow::Utf8::Encode(result + utf8_byte_position, character);
5272 }
5273 character_position++;
5274 }
5275 result[utf8_byte_position] = 0;
5276 return SmartPointer<char>(result);
5277}
5278
5279
5280SmartPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5281 RobustnessFlag robust_flag,
5282 int* length_return) {
5283 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5284}
5285
5286
5287const uc16* String::GetTwoByteData() {
5288 return GetTwoByteData(0);
5289}
5290
5291
5292const uc16* String::GetTwoByteData(unsigned start) {
5293 ASSERT(!IsAsciiRepresentation());
5294 switch (StringShape(this).representation_tag()) {
5295 case kSeqStringTag:
5296 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
5297 case kExternalStringTag:
5298 return ExternalTwoByteString::cast(this)->
5299 ExternalTwoByteStringGetData(start);
Steve Blocka7e24c12009-10-30 11:49:00 +00005300 case kConsStringTag:
5301 UNREACHABLE();
5302 return NULL;
5303 }
5304 UNREACHABLE();
5305 return NULL;
5306}
5307
5308
5309SmartPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005310 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
5311 return SmartPointer<uc16>();
5312 }
Steve Block44f0eee2011-05-26 01:26:41 +01005313 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005314
Steve Block44f0eee2011-05-26 01:26:41 +01005315 Access<StringInputBuffer> buffer(
5316 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005317 buffer->Reset(this);
5318
5319 uc16* result = NewArray<uc16>(length() + 1);
5320
5321 int i = 0;
5322 while (buffer->has_more()) {
5323 uint16_t character = buffer->GetNext();
5324 result[i++] = character;
5325 }
5326 result[i] = 0;
5327 return SmartPointer<uc16>(result);
5328}
5329
5330
5331const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
5332 return reinterpret_cast<uc16*>(
5333 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5334}
5335
5336
5337void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5338 unsigned* offset_ptr,
5339 unsigned max_chars) {
5340 unsigned chars_read = 0;
5341 unsigned offset = *offset_ptr;
5342 while (chars_read < max_chars) {
5343 uint16_t c = *reinterpret_cast<uint16_t*>(
5344 reinterpret_cast<char*>(this) -
5345 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5346 if (c <= kMaxAsciiCharCode) {
5347 // Fast case for ASCII characters. Cursor is an input output argument.
5348 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5349 rbb->util_buffer,
5350 rbb->capacity,
5351 rbb->cursor)) {
5352 break;
5353 }
5354 } else {
5355 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5356 rbb->util_buffer,
5357 rbb->capacity,
5358 rbb->cursor)) {
5359 break;
5360 }
5361 }
5362 offset++;
5363 chars_read++;
5364 }
5365 *offset_ptr = offset;
5366 rbb->remaining += chars_read;
5367}
5368
5369
5370const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5371 unsigned* remaining,
5372 unsigned* offset_ptr,
5373 unsigned max_chars) {
5374 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5375 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5376 *remaining = max_chars;
5377 *offset_ptr += max_chars;
5378 return b;
5379}
5380
5381
5382// This will iterate unless the block of string data spans two 'halves' of
5383// a ConsString, in which case it will recurse. Since the block of string
5384// data to be read has a maximum size this limits the maximum recursion
5385// depth to something sane. Since C++ does not have tail call recursion
5386// elimination, the iteration must be explicit. Since this is not an
5387// -IntoBuffer method it can delegate to one of the efficient
5388// *AsciiStringReadBlock routines.
5389const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5390 unsigned* offset_ptr,
5391 unsigned max_chars) {
5392 ConsString* current = this;
5393 unsigned offset = *offset_ptr;
5394 int offset_correction = 0;
5395
5396 while (true) {
5397 String* left = current->first();
5398 unsigned left_length = (unsigned)left->length();
5399 if (left_length > offset &&
5400 (max_chars <= left_length - offset ||
5401 (rbb->capacity <= left_length - offset &&
5402 (max_chars = left_length - offset, true)))) { // comma operator!
5403 // Left hand side only - iterate unless we have reached the bottom of
5404 // the cons tree. The assignment on the left of the comma operator is
5405 // in order to make use of the fact that the -IntoBuffer routines can
5406 // produce at most 'capacity' characters. This enables us to postpone
5407 // the point where we switch to the -IntoBuffer routines (below) in order
5408 // to maximize the chances of delegating a big chunk of work to the
5409 // efficient *AsciiStringReadBlock routines.
5410 if (StringShape(left).IsCons()) {
5411 current = ConsString::cast(left);
5412 continue;
5413 } else {
5414 const unibrow::byte* answer =
5415 String::ReadBlock(left, rbb, &offset, max_chars);
5416 *offset_ptr = offset + offset_correction;
5417 return answer;
5418 }
5419 } else if (left_length <= offset) {
5420 // Right hand side only - iterate unless we have reached the bottom of
5421 // the cons tree.
5422 String* right = current->second();
5423 offset -= left_length;
5424 offset_correction += left_length;
5425 if (StringShape(right).IsCons()) {
5426 current = ConsString::cast(right);
5427 continue;
5428 } else {
5429 const unibrow::byte* answer =
5430 String::ReadBlock(right, rbb, &offset, max_chars);
5431 *offset_ptr = offset + offset_correction;
5432 return answer;
5433 }
5434 } else {
5435 // The block to be read spans two sides of the ConsString, so we call the
5436 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5437 // are able to assemble data from several part strings because they use
5438 // the util_buffer to store their data and never return direct pointers
5439 // to their storage. We don't try to read more than the buffer capacity
5440 // here or we can get too much recursion.
5441 ASSERT(rbb->remaining == 0);
5442 ASSERT(rbb->cursor == 0);
5443 current->ConsStringReadBlockIntoBuffer(
5444 rbb,
5445 &offset,
5446 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5447 *offset_ptr = offset + offset_correction;
5448 return rbb->util_buffer;
5449 }
5450 }
5451}
5452
5453
Steve Blocka7e24c12009-10-30 11:49:00 +00005454uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5455 ASSERT(index >= 0 && index < length());
5456 return resource()->data()[index];
5457}
5458
5459
5460const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5461 unsigned* remaining,
5462 unsigned* offset_ptr,
5463 unsigned max_chars) {
5464 // Cast const char* to unibrow::byte* (signedness difference).
5465 const unibrow::byte* b =
5466 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
5467 *remaining = max_chars;
5468 *offset_ptr += max_chars;
5469 return b;
5470}
5471
5472
5473const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5474 unsigned start) {
5475 return resource()->data() + start;
5476}
5477
5478
5479uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5480 ASSERT(index >= 0 && index < length());
5481 return resource()->data()[index];
5482}
5483
5484
5485void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5486 ReadBlockBuffer* rbb,
5487 unsigned* offset_ptr,
5488 unsigned max_chars) {
5489 unsigned chars_read = 0;
5490 unsigned offset = *offset_ptr;
5491 const uint16_t* data = resource()->data();
5492 while (chars_read < max_chars) {
5493 uint16_t c = data[offset];
5494 if (c <= kMaxAsciiCharCode) {
5495 // Fast case for ASCII characters. Cursor is an input output argument.
5496 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5497 rbb->util_buffer,
5498 rbb->capacity,
5499 rbb->cursor))
5500 break;
5501 } else {
5502 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5503 rbb->util_buffer,
5504 rbb->capacity,
5505 rbb->cursor))
5506 break;
5507 }
5508 offset++;
5509 chars_read++;
5510 }
5511 *offset_ptr = offset;
5512 rbb->remaining += chars_read;
5513}
5514
5515
5516void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5517 unsigned* offset_ptr,
5518 unsigned max_chars) {
5519 unsigned capacity = rbb->capacity - rbb->cursor;
5520 if (max_chars > capacity) max_chars = capacity;
5521 memcpy(rbb->util_buffer + rbb->cursor,
5522 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5523 *offset_ptr * kCharSize,
5524 max_chars);
5525 rbb->remaining += max_chars;
5526 *offset_ptr += max_chars;
5527 rbb->cursor += max_chars;
5528}
5529
5530
5531void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5532 ReadBlockBuffer* rbb,
5533 unsigned* offset_ptr,
5534 unsigned max_chars) {
5535 unsigned capacity = rbb->capacity - rbb->cursor;
5536 if (max_chars > capacity) max_chars = capacity;
5537 memcpy(rbb->util_buffer + rbb->cursor,
5538 resource()->data() + *offset_ptr,
5539 max_chars);
5540 rbb->remaining += max_chars;
5541 *offset_ptr += max_chars;
5542 rbb->cursor += max_chars;
5543}
5544
5545
5546// This method determines the type of string involved and then copies
5547// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5548// where they can be found. The pointer is not necessarily valid across a GC
5549// (see AsciiStringReadBlock).
5550const unibrow::byte* String::ReadBlock(String* input,
5551 ReadBlockBuffer* rbb,
5552 unsigned* offset_ptr,
5553 unsigned max_chars) {
5554 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5555 if (max_chars == 0) {
5556 rbb->remaining = 0;
5557 return NULL;
5558 }
5559 switch (StringShape(input).representation_tag()) {
5560 case kSeqStringTag:
5561 if (input->IsAsciiRepresentation()) {
5562 SeqAsciiString* str = SeqAsciiString::cast(input);
5563 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5564 offset_ptr,
5565 max_chars);
5566 } else {
5567 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5568 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5569 offset_ptr,
5570 max_chars);
5571 return rbb->util_buffer;
5572 }
5573 case kConsStringTag:
5574 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5575 offset_ptr,
5576 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005577 case kExternalStringTag:
5578 if (input->IsAsciiRepresentation()) {
5579 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5580 &rbb->remaining,
5581 offset_ptr,
5582 max_chars);
5583 } else {
5584 ExternalTwoByteString::cast(input)->
5585 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5586 offset_ptr,
5587 max_chars);
5588 return rbb->util_buffer;
5589 }
5590 default:
5591 break;
5592 }
5593
5594 UNREACHABLE();
5595 return 0;
5596}
5597
5598
Steve Blocka7e24c12009-10-30 11:49:00 +00005599void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01005600 Isolate* isolate = Isolate::Current();
5601 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00005602 while (current != NULL) {
5603 current->PostGarbageCollection();
5604 current = current->prev_;
5605 }
5606}
5607
5608
5609// Reserve space for statics needing saving and restoring.
5610int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01005611 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005612}
5613
5614
5615// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005616char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01005617 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5618 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005619 return to + ArchiveSpacePerThread();
5620}
5621
5622
5623// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005624char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01005625 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00005626 return from + ArchiveSpacePerThread();
5627}
5628
5629
5630char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5631 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5632 Iterate(v, top);
5633 return thread_storage + ArchiveSpacePerThread();
5634}
5635
5636
5637void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01005638 Isolate* isolate = Isolate::Current();
5639 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005640}
5641
5642
5643void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5644 Relocatable* current = top;
5645 while (current != NULL) {
5646 current->IterateInstance(v);
5647 current = current->prev_;
5648 }
5649}
5650
5651
Steve Block44f0eee2011-05-26 01:26:41 +01005652FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5653 : Relocatable(isolate),
5654 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00005655 length_(str->length()) {
5656 PostGarbageCollection();
5657}
5658
5659
Steve Block44f0eee2011-05-26 01:26:41 +01005660FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5661 : Relocatable(isolate),
5662 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005663 is_ascii_(true),
5664 length_(input.length()),
5665 start_(input.start()) { }
5666
5667
5668void FlatStringReader::PostGarbageCollection() {
5669 if (str_ == NULL) return;
5670 Handle<String> str(str_);
5671 ASSERT(str->IsFlat());
5672 is_ascii_ = str->IsAsciiRepresentation();
5673 if (is_ascii_) {
5674 start_ = str->ToAsciiVector().start();
5675 } else {
5676 start_ = str->ToUC16Vector().start();
5677 }
5678}
5679
5680
5681void StringInputBuffer::Seek(unsigned pos) {
5682 Reset(pos, input_);
5683}
5684
5685
5686void SafeStringInputBuffer::Seek(unsigned pos) {
5687 Reset(pos, input_);
5688}
5689
5690
5691// This method determines the type of string involved and then copies
5692// a whole chunk of characters into a buffer. It can be used with strings
5693// that have been glued together to form a ConsString and which must cooperate
5694// to fill up a buffer.
5695void String::ReadBlockIntoBuffer(String* input,
5696 ReadBlockBuffer* rbb,
5697 unsigned* offset_ptr,
5698 unsigned max_chars) {
5699 ASSERT(*offset_ptr <= (unsigned)input->length());
5700 if (max_chars == 0) return;
5701
5702 switch (StringShape(input).representation_tag()) {
5703 case kSeqStringTag:
5704 if (input->IsAsciiRepresentation()) {
5705 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5706 offset_ptr,
5707 max_chars);
5708 return;
5709 } else {
5710 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5711 offset_ptr,
5712 max_chars);
5713 return;
5714 }
5715 case kConsStringTag:
5716 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5717 offset_ptr,
5718 max_chars);
5719 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005720 case kExternalStringTag:
5721 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005722 ExternalAsciiString::cast(input)->
5723 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5724 } else {
5725 ExternalTwoByteString::cast(input)->
5726 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5727 offset_ptr,
5728 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005729 }
5730 return;
5731 default:
5732 break;
5733 }
5734
5735 UNREACHABLE();
5736 return;
5737}
5738
5739
5740const unibrow::byte* String::ReadBlock(String* input,
5741 unibrow::byte* util_buffer,
5742 unsigned capacity,
5743 unsigned* remaining,
5744 unsigned* offset_ptr) {
5745 ASSERT(*offset_ptr <= (unsigned)input->length());
5746 unsigned chars = input->length() - *offset_ptr;
5747 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5748 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5749 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5750 *remaining = rbb.remaining;
5751 return answer;
5752}
5753
5754
5755const unibrow::byte* String::ReadBlock(String** raw_input,
5756 unibrow::byte* util_buffer,
5757 unsigned capacity,
5758 unsigned* remaining,
5759 unsigned* offset_ptr) {
5760 Handle<String> input(raw_input);
5761 ASSERT(*offset_ptr <= (unsigned)input->length());
5762 unsigned chars = input->length() - *offset_ptr;
5763 if (chars > capacity) chars = capacity;
5764 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5765 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5766 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5767 *remaining = rbb.remaining;
5768 return rbb.util_buffer;
5769}
5770
5771
5772// This will iterate unless the block of string data spans two 'halves' of
5773// a ConsString, in which case it will recurse. Since the block of string
5774// data to be read has a maximum size this limits the maximum recursion
5775// depth to something sane. Since C++ does not have tail call recursion
5776// elimination, the iteration must be explicit.
5777void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5778 unsigned* offset_ptr,
5779 unsigned max_chars) {
5780 ConsString* current = this;
5781 unsigned offset = *offset_ptr;
5782 int offset_correction = 0;
5783
5784 while (true) {
5785 String* left = current->first();
5786 unsigned left_length = (unsigned)left->length();
5787 if (left_length > offset &&
5788 max_chars <= left_length - offset) {
5789 // Left hand side only - iterate unless we have reached the bottom of
5790 // the cons tree.
5791 if (StringShape(left).IsCons()) {
5792 current = ConsString::cast(left);
5793 continue;
5794 } else {
5795 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5796 *offset_ptr = offset + offset_correction;
5797 return;
5798 }
5799 } else if (left_length <= offset) {
5800 // Right hand side only - iterate unless we have reached the bottom of
5801 // the cons tree.
5802 offset -= left_length;
5803 offset_correction += left_length;
5804 String* right = current->second();
5805 if (StringShape(right).IsCons()) {
5806 current = ConsString::cast(right);
5807 continue;
5808 } else {
5809 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5810 *offset_ptr = offset + offset_correction;
5811 return;
5812 }
5813 } else {
5814 // The block to be read spans two sides of the ConsString, so we recurse.
5815 // First recurse on the left.
5816 max_chars -= left_length - offset;
5817 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5818 // We may have reached the max or there may not have been enough space
5819 // in the buffer for the characters in the left hand side.
5820 if (offset == left_length) {
5821 // Recurse on the right.
5822 String* right = String::cast(current->second());
5823 offset -= left_length;
5824 offset_correction += left_length;
5825 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5826 }
5827 *offset_ptr = offset + offset_correction;
5828 return;
5829 }
5830 }
5831}
5832
5833
Steve Blocka7e24c12009-10-30 11:49:00 +00005834uint16_t ConsString::ConsStringGet(int index) {
5835 ASSERT(index >= 0 && index < this->length());
5836
5837 // Check for a flattened cons string
5838 if (second()->length() == 0) {
5839 String* left = first();
5840 return left->Get(index);
5841 }
5842
5843 String* string = String::cast(this);
5844
5845 while (true) {
5846 if (StringShape(string).IsCons()) {
5847 ConsString* cons_string = ConsString::cast(string);
5848 String* left = cons_string->first();
5849 if (left->length() > index) {
5850 string = left;
5851 } else {
5852 index -= left->length();
5853 string = cons_string->second();
5854 }
5855 } else {
5856 return string->Get(index);
5857 }
5858 }
5859
5860 UNREACHABLE();
5861 return 0;
5862}
5863
5864
5865template <typename sinkchar>
5866void String::WriteToFlat(String* src,
5867 sinkchar* sink,
5868 int f,
5869 int t) {
5870 String* source = src;
5871 int from = f;
5872 int to = t;
5873 while (true) {
5874 ASSERT(0 <= from && from <= to && to <= source->length());
5875 switch (StringShape(source).full_representation_tag()) {
5876 case kAsciiStringTag | kExternalStringTag: {
5877 CopyChars(sink,
5878 ExternalAsciiString::cast(source)->resource()->data() + from,
5879 to - from);
5880 return;
5881 }
5882 case kTwoByteStringTag | kExternalStringTag: {
5883 const uc16* data =
5884 ExternalTwoByteString::cast(source)->resource()->data();
5885 CopyChars(sink,
5886 data + from,
5887 to - from);
5888 return;
5889 }
5890 case kAsciiStringTag | kSeqStringTag: {
5891 CopyChars(sink,
5892 SeqAsciiString::cast(source)->GetChars() + from,
5893 to - from);
5894 return;
5895 }
5896 case kTwoByteStringTag | kSeqStringTag: {
5897 CopyChars(sink,
5898 SeqTwoByteString::cast(source)->GetChars() + from,
5899 to - from);
5900 return;
5901 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005902 case kAsciiStringTag | kConsStringTag:
5903 case kTwoByteStringTag | kConsStringTag: {
5904 ConsString* cons_string = ConsString::cast(source);
5905 String* first = cons_string->first();
5906 int boundary = first->length();
5907 if (to - boundary >= boundary - from) {
5908 // Right hand side is longer. Recurse over left.
5909 if (from < boundary) {
5910 WriteToFlat(first, sink, from, boundary);
5911 sink += boundary - from;
5912 from = 0;
5913 } else {
5914 from -= boundary;
5915 }
5916 to -= boundary;
5917 source = cons_string->second();
5918 } else {
5919 // Left hand side is longer. Recurse over right.
5920 if (to > boundary) {
5921 String* second = cons_string->second();
5922 WriteToFlat(second,
5923 sink + boundary - from,
5924 0,
5925 to - boundary);
5926 to = boundary;
5927 }
5928 source = first;
5929 }
5930 break;
5931 }
5932 }
5933 }
5934}
5935
5936
Steve Blocka7e24c12009-10-30 11:49:00 +00005937template <typename IteratorA, typename IteratorB>
5938static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5939 // General slow case check. We know that the ia and ib iterators
5940 // have the same length.
5941 while (ia->has_more()) {
5942 uc32 ca = ia->GetNext();
5943 uc32 cb = ib->GetNext();
5944 if (ca != cb)
5945 return false;
5946 }
5947 return true;
5948}
5949
5950
5951// Compares the contents of two strings by reading and comparing
5952// int-sized blocks of characters.
5953template <typename Char>
5954static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5955 int length = a.length();
5956 ASSERT_EQ(length, b.length());
5957 const Char* pa = a.start();
5958 const Char* pb = b.start();
5959 int i = 0;
5960#ifndef V8_HOST_CAN_READ_UNALIGNED
5961 // If this architecture isn't comfortable reading unaligned ints
5962 // then we have to check that the strings are aligned before
5963 // comparing them blockwise.
5964 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5965 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5966 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5967 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5968#endif
5969 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5970 int endpoint = length - kStepSize;
5971 // Compare blocks until we reach near the end of the string.
5972 for (; i <= endpoint; i += kStepSize) {
5973 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5974 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5975 if (wa != wb) {
5976 return false;
5977 }
5978 }
5979#ifndef V8_HOST_CAN_READ_UNALIGNED
5980 }
5981#endif
5982 // Compare the remaining characters that didn't fit into a block.
5983 for (; i < length; i++) {
5984 if (a[i] != b[i]) {
5985 return false;
5986 }
5987 }
5988 return true;
5989}
5990
5991
Steve Blocka7e24c12009-10-30 11:49:00 +00005992template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005993static inline bool CompareStringContentsPartial(Isolate* isolate,
5994 IteratorA* ia,
5995 String* b) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005996 if (b->IsFlat()) {
5997 if (b->IsAsciiRepresentation()) {
5998 VectorIterator<char> ib(b->ToAsciiVector());
5999 return CompareStringContents(ia, &ib);
6000 } else {
6001 VectorIterator<uc16> ib(b->ToUC16Vector());
6002 return CompareStringContents(ia, &ib);
6003 }
6004 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006005 isolate->objects_string_compare_buffer_b()->Reset(0, b);
6006 return CompareStringContents(ia,
6007 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006008 }
6009}
6010
6011
Steve Blocka7e24c12009-10-30 11:49:00 +00006012bool String::SlowEquals(String* other) {
6013 // Fast check: negative check with lengths.
6014 int len = length();
6015 if (len != other->length()) return false;
6016 if (len == 0) return true;
6017
6018 // Fast check: if hash code is computed for both strings
6019 // a fast negative check can be performed.
6020 if (HasHashCode() && other->HasHashCode()) {
6021 if (Hash() != other->Hash()) return false;
6022 }
6023
Leon Clarkef7060e22010-06-03 12:02:55 +01006024 // We know the strings are both non-empty. Compare the first chars
6025 // before we try to flatten the strings.
6026 if (this->Get(0) != other->Get(0)) return false;
6027
6028 String* lhs = this->TryFlattenGetString();
6029 String* rhs = other->TryFlattenGetString();
6030
6031 if (StringShape(lhs).IsSequentialAscii() &&
6032 StringShape(rhs).IsSequentialAscii()) {
6033 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
6034 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00006035 return CompareRawStringContents(Vector<const char>(str1, len),
6036 Vector<const char>(str2, len));
6037 }
6038
Steve Block44f0eee2011-05-26 01:26:41 +01006039 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01006040 if (lhs->IsFlat()) {
Ben Murdochbb769b22010-08-11 14:56:33 +01006041 if (lhs->IsAsciiRepresentation()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01006042 Vector<const char> vec1 = lhs->ToAsciiVector();
6043 if (rhs->IsFlat()) {
6044 if (rhs->IsAsciiRepresentation()) {
6045 Vector<const char> vec2 = rhs->ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00006046 return CompareRawStringContents(vec1, vec2);
6047 } else {
6048 VectorIterator<char> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01006049 VectorIterator<uc16> ib(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006050 return CompareStringContents(&buf1, &ib);
6051 }
6052 } else {
6053 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006054 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6055 return CompareStringContents(&buf1,
6056 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006057 }
6058 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01006059 Vector<const uc16> vec1 = lhs->ToUC16Vector();
6060 if (rhs->IsFlat()) {
6061 if (rhs->IsAsciiRepresentation()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006062 VectorIterator<uc16> buf1(vec1);
Leon Clarkef7060e22010-06-03 12:02:55 +01006063 VectorIterator<char> ib(rhs->ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006064 return CompareStringContents(&buf1, &ib);
6065 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01006066 Vector<const uc16> vec2(rhs->ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00006067 return CompareRawStringContents(vec1, vec2);
6068 }
6069 } else {
6070 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01006071 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
6072 return CompareStringContents(&buf1,
6073 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00006074 }
6075 }
6076 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006077 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
6078 return CompareStringContentsPartial(isolate,
6079 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00006080 }
6081}
6082
6083
6084bool String::MarkAsUndetectable() {
6085 if (StringShape(this).IsSymbol()) return false;
6086
6087 Map* map = this->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006088 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01006089 if (map == heap->string_map()) {
6090 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006091 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01006092 } else if (map == heap->ascii_string_map()) {
6093 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006094 return true;
6095 }
6096 // Rest cannot be marked as undetectable
6097 return false;
6098}
6099
6100
6101bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01006102 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006103 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006104 Access<UnicodeCache::Utf8Decoder>
6105 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00006106 decoder->Reset(str.start(), str.length());
6107 int i;
6108 for (i = 0; i < slen && decoder->has_more(); i++) {
6109 uc32 r = decoder->GetNext();
6110 if (Get(i) != r) return false;
6111 }
6112 return i == slen && !decoder->has_more();
6113}
6114
6115
Steve Block9fac8402011-05-12 15:51:54 +01006116bool String::IsAsciiEqualTo(Vector<const char> str) {
6117 int slen = length();
6118 if (str.length() != slen) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006119 if (IsFlat() && IsAsciiRepresentation()) {
6120 return CompareChars(ToAsciiVector().start(), str.start(), slen) == 0;
6121 }
6122 for (int i = 0; i < slen; i++) {
6123 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01006124 }
6125 return true;
6126}
6127
6128
6129bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6130 int slen = length();
6131 if (str.length() != slen) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006132 if (IsFlat() && IsTwoByteRepresentation()) {
6133 return CompareChars(ToUC16Vector().start(), str.start(), slen) == 0;
6134 }
Steve Block9fac8402011-05-12 15:51:54 +01006135 for (int i = 0; i < slen; i++) {
6136 if (Get(i) != str[i]) return false;
6137 }
6138 return true;
6139}
6140
6141
Steve Blocka7e24c12009-10-30 11:49:00 +00006142uint32_t String::ComputeAndSetHash() {
6143 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006144 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006145
Steve Block6ded16b2010-05-10 14:33:55 +01006146 const int len = length();
6147
Steve Blocka7e24c12009-10-30 11:49:00 +00006148 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01006149 uint32_t field = 0;
6150 if (StringShape(this).IsSequentialAscii()) {
6151 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
6152 } else if (StringShape(this).IsSequentialTwoByte()) {
6153 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
6154 } else {
6155 StringInputBuffer buffer(this);
6156 field = ComputeHashField(&buffer, len);
6157 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006158
6159 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00006160 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00006161
6162 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006163 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006164 uint32_t result = field >> kHashShift;
6165 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6166 return result;
6167}
6168
6169
6170bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6171 uint32_t* index,
6172 int length) {
6173 if (length == 0 || length > kMaxArrayIndexSize) return false;
6174 uc32 ch = buffer->GetNext();
6175
6176 // If the string begins with a '0' character, it must only consist
6177 // of it to be a legal array index.
6178 if (ch == '0') {
6179 *index = 0;
6180 return length == 1;
6181 }
6182
6183 // Convert string to uint32 array index; character by character.
6184 int d = ch - '0';
6185 if (d < 0 || d > 9) return false;
6186 uint32_t result = d;
6187 while (buffer->has_more()) {
6188 d = buffer->GetNext() - '0';
6189 if (d < 0 || d > 9) return false;
6190 // Check that the new result is below the 32 bit limit.
6191 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6192 result = (result * 10) + d;
6193 }
6194
6195 *index = result;
6196 return true;
6197}
6198
6199
6200bool String::SlowAsArrayIndex(uint32_t* index) {
6201 if (length() <= kMaxCachedArrayIndexLength) {
6202 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00006203 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006204 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00006205 // Isolate the array index form the full hash field.
6206 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00006207 return true;
6208 } else {
6209 StringInputBuffer buffer(this);
6210 return ComputeArrayIndex(&buffer, index, length());
6211 }
6212}
6213
6214
Iain Merrick9ac36c92010-09-13 15:29:50 +01006215uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006216 // For array indexes mix the length into the hash as an array index could
6217 // be zero.
6218 ASSERT(length > 0);
6219 ASSERT(length <= String::kMaxArrayIndexSize);
6220 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6221 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01006222
6223 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006224 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01006225
6226 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6227 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6228 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006229 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00006230}
6231
6232
6233uint32_t StringHasher::GetHashField() {
6234 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00006235 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006236 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01006237 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00006238 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006239 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006240 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006241 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006242 }
6243}
6244
6245
Steve Blockd0582a62009-12-15 09:54:21 +00006246uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
6247 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006248 StringHasher hasher(length);
6249
6250 // Very long strings have a trivial hash that doesn't inspect the
6251 // string contents.
6252 if (hasher.has_trivial_hash()) {
6253 return hasher.GetHashField();
6254 }
6255
6256 // Do the iterative array index computation as long as there is a
6257 // chance this is an array index.
6258 while (buffer->has_more() && hasher.is_array_index()) {
6259 hasher.AddCharacter(buffer->GetNext());
6260 }
6261
6262 // Process the remaining characters without updating the array
6263 // index.
6264 while (buffer->has_more()) {
6265 hasher.AddCharacterNoIndex(buffer->GetNext());
6266 }
6267
6268 return hasher.GetHashField();
6269}
6270
6271
John Reck59135872010-11-02 12:39:01 -07006272MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01006273 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006274 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01006275 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00006276 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00006277}
6278
6279
6280void String::PrintOn(FILE* file) {
6281 int length = this->length();
6282 for (int i = 0; i < length; i++) {
6283 fprintf(file, "%c", Get(i));
6284 }
6285}
6286
6287
6288void Map::CreateBackPointers() {
6289 DescriptorArray* descriptors = instance_descriptors();
6290 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01006291 if (descriptors->GetType(i) == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01006292 descriptors->GetType(i) == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01006293 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006294 // Get target.
6295 Map* target = Map::cast(descriptors->GetValue(i));
6296#ifdef DEBUG
6297 // Verify target.
6298 Object* source_prototype = prototype();
6299 Object* target_prototype = target->prototype();
6300 ASSERT(source_prototype->IsJSObject() ||
6301 source_prototype->IsMap() ||
6302 source_prototype->IsNull());
6303 ASSERT(target_prototype->IsJSObject() ||
6304 target_prototype->IsNull());
6305 ASSERT(source_prototype->IsMap() ||
6306 source_prototype == target_prototype);
6307#endif
6308 // Point target back to source. set_prototype() will not let us set
6309 // the prototype to a map, as we do here.
6310 *RawField(target, kPrototypeOffset) = this;
6311 }
6312 }
6313}
6314
6315
Steve Block44f0eee2011-05-26 01:26:41 +01006316void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006317 // Live DescriptorArray objects will be marked, so we must use
6318 // low-level accessors to get and modify their data.
6319 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00006320 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6321 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006322 Smi* NullDescriptorDetails =
6323 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
6324 FixedArray* contents = reinterpret_cast<FixedArray*>(
6325 d->get(DescriptorArray::kContentArrayIndex));
6326 ASSERT(contents->length() >= 2);
6327 for (int i = 0; i < contents->length(); i += 2) {
6328 // If the pair (value, details) is a map transition,
6329 // check if the target is live. If not, null the descriptor.
6330 // Also drop the back pointer for that map transition, so that this
6331 // map is not reached again by following a back pointer from a
6332 // non-live object.
6333 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01006334 if (details.type() == MAP_TRANSITION ||
Steve Block44f0eee2011-05-26 01:26:41 +01006335 details.type() == EXTERNAL_ARRAY_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01006336 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006337 Map* target = reinterpret_cast<Map*>(contents->get(i));
6338 ASSERT(target->IsHeapObject());
6339 if (!target->IsMarked()) {
6340 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01006341 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01006342 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00006343 ASSERT(target->prototype() == this ||
6344 target->prototype() == real_prototype);
6345 // Getter prototype() is read-only, set_prototype() has side effects.
6346 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6347 }
6348 }
6349 }
6350}
6351
6352
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006353int Map::Hash() {
6354 // For performance reasons we only hash the 3 most variable fields of a map:
6355 // constructor, prototype and bit_field2.
6356
6357 // Shift away the tag.
6358 int hash = (static_cast<uint32_t>(
6359 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6360
6361 // XOR-ing the prototype and constructor directly yields too many zero bits
6362 // when the two pointers are close (which is fairly common).
6363 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6364 hash ^= (static_cast<uint32_t>(
6365 reinterpret_cast<uintptr_t>(prototype())) << 2);
6366
6367 return hash ^ (hash >> 16) ^ bit_field2();
6368}
6369
6370
6371bool Map::EquivalentToForNormalization(Map* other,
6372 PropertyNormalizationMode mode) {
6373 return
6374 constructor() == other->constructor() &&
6375 prototype() == other->prototype() &&
6376 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6377 0 :
6378 other->inobject_properties()) &&
6379 instance_type() == other->instance_type() &&
6380 bit_field() == other->bit_field() &&
6381 bit_field2() == other->bit_field2() &&
6382 (bit_field3() & ~(1<<Map::kIsShared)) ==
6383 (other->bit_field3() & ~(1<<Map::kIsShared));
6384}
6385
6386
Steve Block791712a2010-08-27 10:21:07 +01006387void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6388 // Iterate over all fields in the body but take care in dealing with
6389 // the code entry.
6390 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6391 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6392 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6393}
6394
6395
Ben Murdochb0fe1622011-05-05 13:52:32 +01006396void JSFunction::MarkForLazyRecompilation() {
6397 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01006398 ASSERT(shared()->allows_lazy_compilation() ||
6399 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01006400 Builtins* builtins = GetIsolate()->builtins();
6401 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006402}
6403
6404
Ben Murdochb0fe1622011-05-05 13:52:32 +01006405bool JSFunction::IsInlineable() {
6406 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006407 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006408 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006409 if (!shared_info->script()->IsScript()) return false;
6410 if (shared_info->optimization_disabled()) return false;
6411 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006412 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6413 // If we never ran this (unlikely) then lets try to optimize it.
6414 if (code->kind() != Code::FUNCTION) return true;
6415 return code->optimizable();
6416}
6417
6418
Steve Blocka7e24c12009-10-30 11:49:00 +00006419Object* JSFunction::SetInstancePrototype(Object* value) {
6420 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01006421 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006422 if (has_initial_map()) {
6423 initial_map()->set_prototype(value);
6424 } else {
6425 // Put the value in the initial map field until an initial map is
6426 // needed. At that point, a new initial map is created and the
6427 // prototype is put into the initial map where it belongs.
6428 set_prototype_or_initial_map(value);
6429 }
Steve Block44f0eee2011-05-26 01:26:41 +01006430 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00006431 return value;
6432}
6433
6434
John Reck59135872010-11-02 12:39:01 -07006435MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01006436 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00006437 Object* construct_prototype = value;
6438
6439 // If the value is not a JSObject, store the value in the map's
6440 // constructor field so it can be accessed. Also, set the prototype
6441 // used for constructing objects to the original object prototype.
6442 // See ECMA-262 13.2.2.
6443 if (!value->IsJSObject()) {
6444 // Copy the map so this does not affect unrelated functions.
6445 // Remove map transitions because they point to maps with a
6446 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006447 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07006448 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006449 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07006450 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01006451 Map* new_map = Map::cast(new_object);
6452 Heap* heap = new_map->heap();
6453 set_map(new_map);
6454 new_map->set_constructor(value);
6455 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006456 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01006457 heap->isolate()->context()->global_context()->
6458 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00006459 } else {
6460 map()->set_non_instance_prototype(false);
6461 }
6462
6463 return SetInstancePrototype(construct_prototype);
6464}
6465
6466
Steve Block6ded16b2010-05-10 14:33:55 +01006467Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01006468 Context* global_context = context()->global_context();
6469 Map* no_prototype_map = shared()->strict_mode()
6470 ? global_context->strict_mode_function_without_prototype_map()
6471 : global_context->function_without_prototype_map();
6472
6473 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006474 // Be idempotent.
6475 return this;
6476 }
Steve Block44f0eee2011-05-26 01:26:41 +01006477
6478 ASSERT(!shared()->strict_mode() ||
6479 map() == global_context->strict_mode_function_map());
6480 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
6481
6482 set_map(no_prototype_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01006483 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01006484 return this;
6485}
6486
6487
Steve Blocka7e24c12009-10-30 11:49:00 +00006488Object* JSFunction::SetInstanceClassName(String* name) {
6489 shared()->set_instance_class_name(name);
6490 return this;
6491}
6492
6493
Ben Murdochb0fe1622011-05-05 13:52:32 +01006494void JSFunction::PrintName(FILE* out) {
6495 SmartPointer<char> name = shared()->DebugName()->ToCString();
6496 PrintF(out, "%s", *name);
6497}
6498
6499
Steve Blocka7e24c12009-10-30 11:49:00 +00006500Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6501 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6502}
6503
6504
Steve Block44f0eee2011-05-26 01:26:41 +01006505MaybeObject* Oddball::Initialize(const char* to_string,
6506 Object* to_number,
6507 byte kind) {
John Reck59135872010-11-02 12:39:01 -07006508 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01006509 { MaybeObject* maybe_symbol =
6510 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07006511 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6512 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006513 set_to_string(String::cast(symbol));
6514 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01006515 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00006516 return this;
6517}
6518
6519
Ben Murdochf87a2032010-10-22 12:50:53 +01006520String* SharedFunctionInfo::DebugName() {
6521 Object* n = name();
6522 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6523 return String::cast(n);
6524}
6525
6526
Steve Blocka7e24c12009-10-30 11:49:00 +00006527bool SharedFunctionInfo::HasSourceCode() {
6528 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01006529 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00006530}
6531
6532
6533Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01006534 Isolate* isolate = GetIsolate();
6535 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6536 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006537 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01006538 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00006539 start_position(), end_position());
6540}
6541
6542
Ben Murdochb0fe1622011-05-05 13:52:32 +01006543int SharedFunctionInfo::SourceSize() {
6544 return end_position() - start_position();
6545}
6546
6547
Steve Blocka7e24c12009-10-30 11:49:00 +00006548int SharedFunctionInfo::CalculateInstanceSize() {
6549 int instance_size =
6550 JSObject::kHeaderSize +
6551 expected_nof_properties() * kPointerSize;
6552 if (instance_size > JSObject::kMaxInstanceSize) {
6553 instance_size = JSObject::kMaxInstanceSize;
6554 }
6555 return instance_size;
6556}
6557
6558
6559int SharedFunctionInfo::CalculateInObjectProperties() {
6560 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6561}
6562
6563
Andrei Popescu402d9372010-02-26 13:31:12 +00006564bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6565 // Check the basic conditions for generating inline constructor code.
6566 if (!FLAG_inline_new
6567 || !has_only_simple_this_property_assignments()
6568 || this_property_assignments_count() == 0) {
6569 return false;
6570 }
6571
6572 // If the prototype is null inline constructors cause no problems.
6573 if (!prototype->IsJSObject()) {
6574 ASSERT(prototype->IsNull());
6575 return true;
6576 }
6577
Ben Murdoch8b112d22011-06-08 16:22:53 +01006578 Heap* heap = GetHeap();
6579
Andrei Popescu402d9372010-02-26 13:31:12 +00006580 // Traverse the proposed prototype chain looking for setters for properties of
6581 // the same names as are set by the inline constructor.
6582 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01006583 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00006584 obj = obj->GetPrototype()) {
6585 JSObject* js_object = JSObject::cast(obj);
6586 for (int i = 0; i < this_property_assignments_count(); i++) {
6587 LookupResult result;
6588 String* name = GetThisPropertyAssignmentName(i);
6589 js_object->LocalLookupRealNamedProperty(name, &result);
6590 if (result.IsProperty() && result.type() == CALLBACKS) {
6591 return false;
6592 }
6593 }
6594 }
6595
6596 return true;
6597}
6598
6599
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006600void SharedFunctionInfo::ForbidInlineConstructor() {
6601 set_compiler_hints(BooleanBit::set(compiler_hints(),
6602 kHasOnlySimpleThisPropertyAssignments,
6603 false));
6604}
6605
6606
Steve Blocka7e24c12009-10-30 11:49:00 +00006607void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00006608 bool only_simple_this_property_assignments,
6609 FixedArray* assignments) {
6610 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006611 kHasOnlySimpleThisPropertyAssignments,
6612 only_simple_this_property_assignments));
6613 set_this_property_assignments(assignments);
6614 set_this_property_assignments_count(assignments->length() / 3);
6615}
6616
6617
6618void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01006619 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006620 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006621 kHasOnlySimpleThisPropertyAssignments,
6622 false));
Steve Block44f0eee2011-05-26 01:26:41 +01006623 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006624 set_this_property_assignments_count(0);
6625}
6626
6627
6628String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6629 Object* obj = this_property_assignments();
6630 ASSERT(obj->IsFixedArray());
6631 ASSERT(index < this_property_assignments_count());
6632 obj = FixedArray::cast(obj)->get(index * 3);
6633 ASSERT(obj->IsString());
6634 return String::cast(obj);
6635}
6636
6637
6638bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6639 Object* obj = this_property_assignments();
6640 ASSERT(obj->IsFixedArray());
6641 ASSERT(index < this_property_assignments_count());
6642 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6643 return Smi::cast(obj)->value() != -1;
6644}
6645
6646
6647int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6648 ASSERT(IsThisPropertyAssignmentArgument(index));
6649 Object* obj =
6650 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6651 return Smi::cast(obj)->value();
6652}
6653
6654
6655Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6656 ASSERT(!IsThisPropertyAssignmentArgument(index));
6657 Object* obj =
6658 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6659 return obj;
6660}
6661
6662
Steve Blocka7e24c12009-10-30 11:49:00 +00006663// Support function for printing the source code to a StringStream
6664// without any allocation in the heap.
6665void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6666 int max_length) {
6667 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006668 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006669 accumulator->Add("<No Source>");
6670 return;
6671 }
6672
Steve Blockd0582a62009-12-15 09:54:21 +00006673 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00006674 // Don't use String::cast because we don't want more assertion errors while
6675 // we are already creating a stack dump.
6676 String* script_source =
6677 reinterpret_cast<String*>(Script::cast(script())->source());
6678
6679 if (!script_source->LooksValid()) {
6680 accumulator->Add("<Invalid Source>");
6681 return;
6682 }
6683
6684 if (!is_toplevel()) {
6685 accumulator->Add("function ");
6686 Object* name = this->name();
6687 if (name->IsString() && String::cast(name)->length() > 0) {
6688 accumulator->PrintName(name);
6689 }
6690 }
6691
6692 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006693 if (len <= max_length || max_length < 0) {
6694 accumulator->Put(script_source, start_position(), end_position());
6695 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006696 accumulator->Put(script_source,
6697 start_position(),
6698 start_position() + max_length);
6699 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006700 }
6701}
6702
6703
Ben Murdochb0fe1622011-05-05 13:52:32 +01006704static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6705 if (code->instruction_size() != recompiled->instruction_size()) return false;
6706 ByteArray* code_relocation = code->relocation_info();
6707 ByteArray* recompiled_relocation = recompiled->relocation_info();
6708 int length = code_relocation->length();
6709 if (length != recompiled_relocation->length()) return false;
6710 int compare = memcmp(code_relocation->GetDataStartAddress(),
6711 recompiled_relocation->GetDataStartAddress(),
6712 length);
6713 return compare == 0;
6714}
6715
6716
6717void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6718 ASSERT(!has_deoptimization_support());
6719 AssertNoAllocation no_allocation;
6720 Code* code = this->code();
6721 if (IsCodeEquivalent(code, recompiled)) {
6722 // Copy the deoptimization data from the recompiled code.
6723 code->set_deoptimization_data(recompiled->deoptimization_data());
6724 code->set_has_deoptimization_support(true);
6725 } else {
6726 // TODO(3025757): In case the recompiled isn't equivalent to the
6727 // old code, we have to replace it. We should try to avoid this
6728 // altogether because it flushes valuable type feedback by
6729 // effectively resetting all IC state.
6730 set_code(recompiled);
6731 }
6732 ASSERT(has_deoptimization_support());
6733}
6734
6735
Ben Murdoch257744e2011-11-30 15:57:28 +00006736void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6737 // Disable optimization for the shared function info and mark the
6738 // code as non-optimizable. The marker on the shared function info
6739 // is there because we flush non-optimized code thereby loosing the
6740 // non-optimizable information for the code. When the code is
6741 // regenerated and set on the shared function info it is marked as
6742 // non-optimizable if optimization is disabled for the shared
6743 // function info.
6744 set_optimization_disabled(true);
6745 // Code should be the lazy compilation stub or else unoptimized. If the
6746 // latter, disable optimization for the code too.
6747 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6748 if (code()->kind() == Code::FUNCTION) {
6749 code()->set_optimizable(false);
6750 }
6751 if (FLAG_trace_opt) {
6752 PrintF("[disabled optimization for: ");
6753 function->PrintName();
6754 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6755 }
6756}
6757
6758
Ben Murdochb0fe1622011-05-05 13:52:32 +01006759bool SharedFunctionInfo::VerifyBailoutId(int id) {
6760 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6761 // we are always bailing out on ARM.
6762
6763 ASSERT(id != AstNode::kNoNumber);
6764 Code* unoptimized = code();
6765 DeoptimizationOutputData* data =
6766 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6767 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6768 USE(ignore);
6769 return true; // Return true if there was no ASSERT.
6770}
6771
6772
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006773void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6774 ASSERT(!IsInobjectSlackTrackingInProgress());
6775
6776 // Only initiate the tracking the first time.
6777 if (live_objects_may_exist()) return;
6778 set_live_objects_may_exist(true);
6779
6780 // No tracking during the snapshot construction phase.
6781 if (Serializer::enabled()) return;
6782
6783 if (map->unused_property_fields() == 0) return;
6784
6785 // Nonzero counter is a leftover from the previous attempt interrupted
6786 // by GC, keep it.
6787 if (construction_count() == 0) {
6788 set_construction_count(kGenerousAllocationCount);
6789 }
6790 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006791 Builtins* builtins = map->heap()->isolate()->builtins();
6792 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006793 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006794 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006795}
6796
6797
6798// Called from GC, hence reinterpret_cast and unchecked accessors.
6799void SharedFunctionInfo::DetachInitialMap() {
6800 Map* map = reinterpret_cast<Map*>(initial_map());
6801
6802 // Make the map remember to restore the link if it survives the GC.
6803 map->set_bit_field2(
6804 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6805
6806 // Undo state changes made by StartInobjectTracking (except the
6807 // construction_count). This way if the initial map does not survive the GC
6808 // then StartInobjectTracking will be called again the next time the
6809 // constructor is called. The countdown will continue and (possibly after
6810 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006811 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6812 Builtins* builtins = map->heap()->isolate()->builtins();
6813 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006814 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006815 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006816 // It is safe to clear the flag: it will be set again if the map is live.
6817 set_live_objects_may_exist(false);
6818}
6819
6820
6821// Called from GC, hence reinterpret_cast and unchecked accessors.
6822void SharedFunctionInfo::AttachInitialMap(Map* map) {
6823 map->set_bit_field2(
6824 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6825
6826 // Resume inobject slack tracking.
6827 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006828 Builtins* builtins = map->heap()->isolate()->builtins();
6829 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006830 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006831 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006832 // The map survived the gc, so there may be objects referencing it.
6833 set_live_objects_may_exist(true);
6834}
6835
6836
6837static void GetMinInobjectSlack(Map* map, void* data) {
6838 int slack = map->unused_property_fields();
6839 if (*reinterpret_cast<int*>(data) > slack) {
6840 *reinterpret_cast<int*>(data) = slack;
6841 }
6842}
6843
6844
6845static void ShrinkInstanceSize(Map* map, void* data) {
6846 int slack = *reinterpret_cast<int*>(data);
6847 map->set_inobject_properties(map->inobject_properties() - slack);
6848 map->set_unused_property_fields(map->unused_property_fields() - slack);
6849 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6850
6851 // Visitor id might depend on the instance size, recalculate it.
6852 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6853}
6854
6855
6856void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6857 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6858 Map* map = Map::cast(initial_map());
6859
Steve Block44f0eee2011-05-26 01:26:41 +01006860 Heap* heap = map->heap();
6861 set_initial_map(heap->undefined_value());
6862 Builtins* builtins = heap->isolate()->builtins();
6863 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006864 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006865 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006866
6867 int slack = map->unused_property_fields();
6868 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6869 if (slack != 0) {
6870 // Resize the initial map and all maps in its transition tree.
6871 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006872
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006873 // Give the correct expected_nof_properties to initial maps created later.
6874 ASSERT(expected_nof_properties() >= slack);
6875 set_expected_nof_properties(expected_nof_properties() - slack);
6876 }
6877}
6878
6879
Steve Blocka7e24c12009-10-30 11:49:00 +00006880void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6881 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6882 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6883 Object* old_target = target;
6884 VisitPointer(&target);
6885 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6886}
6887
6888
Steve Block791712a2010-08-27 10:21:07 +01006889void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6890 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6891 Object* old_code = code;
6892 VisitPointer(&code);
6893 if (code != old_code) {
6894 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6895 }
6896}
6897
6898
Ben Murdochb0fe1622011-05-05 13:52:32 +01006899void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6900 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6901 Object* cell = rinfo->target_cell();
6902 Object* old_cell = cell;
6903 VisitPointer(&cell);
6904 if (cell != old_cell) {
6905 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6906 }
6907}
6908
6909
Steve Blocka7e24c12009-10-30 11:49:00 +00006910void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006911 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6912 rinfo->IsPatchedReturnSequence()) ||
6913 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6914 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006915 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6916 Object* old_target = target;
6917 VisitPointer(&target);
6918 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6919}
6920
6921
Ben Murdochb0fe1622011-05-05 13:52:32 +01006922void Code::InvalidateRelocation() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006923 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006924}
6925
6926
Steve Blockd0582a62009-12-15 09:54:21 +00006927void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006928 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6929 it.rinfo()->apply(delta);
6930 }
6931 CPU::FlushICache(instruction_start(), instruction_size());
6932}
6933
6934
6935void Code::CopyFrom(const CodeDesc& desc) {
6936 // copy code
6937 memmove(instruction_start(), desc.buffer, desc.instr_size);
6938
Steve Blocka7e24c12009-10-30 11:49:00 +00006939 // copy reloc info
6940 memmove(relocation_start(),
6941 desc.buffer + desc.buffer_size - desc.reloc_size,
6942 desc.reloc_size);
6943
6944 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006945 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006946 int mode_mask = RelocInfo::kCodeTargetMask |
6947 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006948 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006949 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006950 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006951 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6952 RelocInfo::Mode mode = it.rinfo()->rmode();
6953 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006954 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006955 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006956 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006957 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006958 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006959 } else if (RelocInfo::IsCodeTarget(mode)) {
6960 // rewrite code handles in inline cache targets to direct
6961 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006962 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006963 Code* code = Code::cast(*p);
6964 it.rinfo()->set_target_address(code->instruction_start());
6965 } else {
6966 it.rinfo()->apply(delta);
6967 }
6968 }
6969 CPU::FlushICache(instruction_start(), instruction_size());
6970}
6971
6972
6973// Locate the source position which is closest to the address in the code. This
6974// is using the source position information embedded in the relocation info.
6975// The position returned is relative to the beginning of the script where the
6976// source for this function is found.
6977int Code::SourcePosition(Address pc) {
6978 int distance = kMaxInt;
6979 int position = RelocInfo::kNoPosition; // Initially no position found.
6980 // Run through all the relocation info to find the best matching source
6981 // position. All the code needs to be considered as the sequence of the
6982 // instructions in the code does not necessarily follow the same order as the
6983 // source.
6984 RelocIterator it(this, RelocInfo::kPositionMask);
6985 while (!it.done()) {
6986 // Only look at positions after the current pc.
6987 if (it.rinfo()->pc() < pc) {
6988 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006989
6990 int dist = static_cast<int>(pc - it.rinfo()->pc());
6991 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006992 // If this position is closer than the current candidate or if it has the
6993 // same distance as the current candidate and the position is higher then
6994 // this position is the new candidate.
6995 if ((dist < distance) ||
6996 (dist == distance && pos > position)) {
6997 position = pos;
6998 distance = dist;
6999 }
7000 }
7001 it.next();
7002 }
7003 return position;
7004}
7005
7006
7007// Same as Code::SourcePosition above except it only looks for statement
7008// positions.
7009int Code::SourceStatementPosition(Address pc) {
7010 // First find the position as close as possible using all position
7011 // information.
7012 int position = SourcePosition(pc);
7013 // Now find the closest statement position before the position.
7014 int statement_position = 0;
7015 RelocIterator it(this, RelocInfo::kPositionMask);
7016 while (!it.done()) {
7017 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00007018 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00007019 if (statement_position < p && p <= position) {
7020 statement_position = p;
7021 }
7022 }
7023 it.next();
7024 }
7025 return statement_position;
7026}
7027
7028
Ben Murdochb8e0da22011-05-16 14:20:40 +01007029SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007030 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01007031 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01007032}
7033
7034
7035void Code::SetNoStackCheckTable() {
7036 // Indicate the absence of a stack-check table by a table start after the
7037 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01007038 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01007039}
7040
7041
7042Map* Code::FindFirstMap() {
7043 ASSERT(is_inline_cache_stub());
7044 AssertNoAllocation no_allocation;
7045 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
7046 for (RelocIterator it(this, mask); !it.done(); it.next()) {
7047 RelocInfo* info = it.rinfo();
7048 Object* object = info->target_object();
7049 if (object->IsMap()) return Map::cast(object);
7050 }
7051 return NULL;
7052}
7053
7054
Steve Blocka7e24c12009-10-30 11:49:00 +00007055#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01007056
Ben Murdochb0fe1622011-05-05 13:52:32 +01007057void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
7058 disasm::NameConverter converter;
7059 int deopt_count = DeoptCount();
7060 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
7061 if (0 == deopt_count) return;
7062
7063 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
7064 for (int i = 0; i < deopt_count; i++) {
7065 int command_count = 0;
7066 PrintF(out, "%6d %6d %6d",
7067 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
7068 int translation_index = TranslationIndex(i)->value();
7069 TranslationIterator iterator(TranslationByteArray(), translation_index);
7070 Translation::Opcode opcode =
7071 static_cast<Translation::Opcode>(iterator.Next());
7072 ASSERT(Translation::BEGIN == opcode);
7073 int frame_count = iterator.Next();
7074 if (FLAG_print_code_verbose) {
7075 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
7076 frame_count);
7077 }
7078
7079 for (int i = 0; i < frame_count; ++i) {
7080 opcode = static_cast<Translation::Opcode>(iterator.Next());
7081 ASSERT(Translation::FRAME == opcode);
7082 int ast_id = iterator.Next();
7083 int function_id = iterator.Next();
7084 JSFunction* function =
7085 JSFunction::cast(LiteralArray()->get(function_id));
7086 unsigned height = iterator.Next();
7087 if (FLAG_print_code_verbose) {
7088 PrintF(out, "%24s %s {ast_id=%d, function=",
7089 "", Translation::StringFor(opcode), ast_id);
7090 function->PrintName(out);
7091 PrintF(out, ", height=%u}\n", height);
7092 }
7093
7094 // Size of translation is height plus all incoming arguments including
7095 // receiver.
7096 int size = height + function->shared()->formal_parameter_count() + 1;
7097 command_count += size;
7098 for (int j = 0; j < size; ++j) {
7099 opcode = static_cast<Translation::Opcode>(iterator.Next());
7100 if (FLAG_print_code_verbose) {
7101 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
7102 }
7103
7104 if (opcode == Translation::DUPLICATE) {
7105 opcode = static_cast<Translation::Opcode>(iterator.Next());
7106 if (FLAG_print_code_verbose) {
7107 PrintF(out, "%s ", Translation::StringFor(opcode));
7108 }
7109 --j; // Two commands share the same frame index.
7110 }
7111
7112 switch (opcode) {
7113 case Translation::BEGIN:
7114 case Translation::FRAME:
7115 case Translation::DUPLICATE:
7116 UNREACHABLE();
7117 break;
7118
7119 case Translation::REGISTER: {
7120 int reg_code = iterator.Next();
7121 if (FLAG_print_code_verbose) {
7122 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7123 }
7124 break;
7125 }
7126
7127 case Translation::INT32_REGISTER: {
7128 int reg_code = iterator.Next();
7129 if (FLAG_print_code_verbose) {
7130 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7131 }
7132 break;
7133 }
7134
7135 case Translation::DOUBLE_REGISTER: {
7136 int reg_code = iterator.Next();
7137 if (FLAG_print_code_verbose) {
7138 PrintF(out, "{input=%s}",
7139 DoubleRegister::AllocationIndexToString(reg_code));
7140 }
7141 break;
7142 }
7143
7144 case Translation::STACK_SLOT: {
7145 int input_slot_index = iterator.Next();
7146 if (FLAG_print_code_verbose) {
7147 PrintF(out, "{input=%d}", input_slot_index);
7148 }
7149 break;
7150 }
7151
7152 case Translation::INT32_STACK_SLOT: {
7153 int input_slot_index = iterator.Next();
7154 if (FLAG_print_code_verbose) {
7155 PrintF(out, "{input=%d}", input_slot_index);
7156 }
7157 break;
7158 }
7159
7160 case Translation::DOUBLE_STACK_SLOT: {
7161 int input_slot_index = iterator.Next();
7162 if (FLAG_print_code_verbose) {
7163 PrintF(out, "{input=%d}", input_slot_index);
7164 }
7165 break;
7166 }
7167
7168 case Translation::LITERAL: {
7169 unsigned literal_index = iterator.Next();
7170 if (FLAG_print_code_verbose) {
7171 PrintF(out, "{literal_id=%u}", literal_index);
7172 }
7173 break;
7174 }
7175
7176 case Translation::ARGUMENTS_OBJECT:
7177 break;
7178 }
7179 if (FLAG_print_code_verbose) PrintF(out, "\n");
7180 }
7181 }
7182 if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
7183 }
7184}
7185
7186
7187void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7188 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
7189 this->DeoptPoints());
7190 if (this->DeoptPoints() == 0) return;
7191
7192 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7193 for (int i = 0; i < this->DeoptPoints(); i++) {
7194 int pc_and_state = this->PcAndState(i)->value();
7195 PrintF("%6d %8d %s\n",
7196 this->AstId(i)->value(),
7197 FullCodeGenerator::PcField::decode(pc_and_state),
7198 FullCodeGenerator::State2String(
7199 FullCodeGenerator::StateField::decode(pc_and_state)));
7200 }
7201}
7202
Ben Murdochb0fe1622011-05-05 13:52:32 +01007203
Steve Blocka7e24c12009-10-30 11:49:00 +00007204// Identify kind of code.
7205const char* Code::Kind2String(Kind kind) {
7206 switch (kind) {
7207 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007208 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007209 case STUB: return "STUB";
7210 case BUILTIN: return "BUILTIN";
7211 case LOAD_IC: return "LOAD_IC";
7212 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7213 case STORE_IC: return "STORE_IC";
7214 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7215 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007216 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00007217 case UNARY_OP_IC: return "UNARY_OP_IC";
7218 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007219 case COMPARE_IC: return "COMPARE_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00007220 }
7221 UNREACHABLE();
7222 return NULL;
7223}
7224
7225
7226const char* Code::ICState2String(InlineCacheState state) {
7227 switch (state) {
7228 case UNINITIALIZED: return "UNINITIALIZED";
7229 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7230 case MONOMORPHIC: return "MONOMORPHIC";
7231 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7232 case MEGAMORPHIC: return "MEGAMORPHIC";
7233 case DEBUG_BREAK: return "DEBUG_BREAK";
7234 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7235 }
7236 UNREACHABLE();
7237 return NULL;
7238}
7239
7240
7241const char* Code::PropertyType2String(PropertyType type) {
7242 switch (type) {
7243 case NORMAL: return "NORMAL";
7244 case FIELD: return "FIELD";
7245 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7246 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00007247 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00007248 case INTERCEPTOR: return "INTERCEPTOR";
7249 case MAP_TRANSITION: return "MAP_TRANSITION";
Steve Block44f0eee2011-05-26 01:26:41 +01007250 case EXTERNAL_ARRAY_TRANSITION: return "EXTERNAL_ARRAY_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007251 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7252 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7253 }
7254 UNREACHABLE();
7255 return NULL;
7256}
7257
Ben Murdochb0fe1622011-05-05 13:52:32 +01007258
Steve Block1e0659c2011-05-24 12:43:12 +01007259void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7260 const char* name = NULL;
7261 switch (kind) {
7262 case CALL_IC:
7263 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7264 name = "STRING_INDEX_OUT_OF_BOUNDS";
7265 }
7266 break;
7267 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007268 case KEYED_STORE_IC:
7269 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01007270 name = "STRICT";
7271 }
7272 break;
7273 default:
7274 break;
7275 }
7276 if (name != NULL) {
7277 PrintF(out, "extra_ic_state = %s\n", name);
7278 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007279 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01007280 }
7281}
7282
7283
Ben Murdochb0fe1622011-05-05 13:52:32 +01007284void Code::Disassemble(const char* name, FILE* out) {
7285 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007286 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007287 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01007288 PrintExtraICState(out, kind(), extra_ic_state());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007289 PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
Steve Blocka7e24c12009-10-30 11:49:00 +00007290 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007291 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007292 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007293 if (is_call_stub() || is_keyed_call_stub()) {
7294 PrintF(out, "argc = %d\n", arguments_count());
7295 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007296 }
7297 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007298 PrintF(out, "name = %s\n", name);
7299 }
7300 if (kind() == OPTIMIZED_FUNCTION) {
7301 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00007302 }
7303
Ben Murdochb0fe1622011-05-05 13:52:32 +01007304 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7305 Disassembler::Decode(out, this);
7306 PrintF(out, "\n");
7307
Ben Murdochb0fe1622011-05-05 13:52:32 +01007308 if (kind() == FUNCTION) {
7309 DeoptimizationOutputData* data =
7310 DeoptimizationOutputData::cast(this->deoptimization_data());
7311 data->DeoptimizationOutputDataPrint(out);
7312 } else if (kind() == OPTIMIZED_FUNCTION) {
7313 DeoptimizationInputData* data =
7314 DeoptimizationInputData::cast(this->deoptimization_data());
7315 data->DeoptimizationInputDataPrint(out);
7316 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007317 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007318
7319 if (kind() == OPTIMIZED_FUNCTION) {
7320 SafepointTable table(this);
7321 PrintF(out, "Safepoints (size = %u)\n", table.size());
7322 for (unsigned i = 0; i < table.length(); i++) {
7323 unsigned pc_offset = table.GetPcOffset(i);
7324 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
7325 table.PrintEntry(i);
7326 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01007327 SafepointEntry entry = table.GetEntry(i);
7328 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7329 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007330 } else {
7331 PrintF(out, " <none>");
7332 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01007333 if (entry.argument_count() > 0) {
7334 PrintF(out, " argc: %d", entry.argument_count());
7335 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007336 PrintF(out, "\n");
7337 }
7338 PrintF(out, "\n");
7339 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01007340 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007341 // If there is no stack check table, the "table start" will at or after
7342 // (due to alignment) the end of the instruction stream.
7343 if (static_cast<int>(offset) < instruction_size()) {
7344 unsigned* address =
7345 reinterpret_cast<unsigned*>(instruction_start() + offset);
7346 unsigned length = address[0];
7347 PrintF(out, "Stack checks (size = %u)\n", length);
7348 PrintF(out, "ast_id pc_offset\n");
7349 for (unsigned i = 0; i < length; ++i) {
7350 unsigned index = (2 * i) + 1;
7351 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
7352 }
7353 PrintF(out, "\n");
7354 }
7355 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007356
7357 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007358 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7359 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007360}
7361#endif // ENABLE_DISASSEMBLER
7362
7363
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007364static void CopyFastElementsToFast(FixedArray* source,
7365 FixedArray* destination,
7366 WriteBarrierMode mode) {
7367 uint32_t count = static_cast<uint32_t>(source->length());
7368 for (uint32_t i = 0; i < count; ++i) {
7369 destination->set(i, source->get(i), mode);
7370 }
7371}
7372
7373
7374static void CopySlowElementsToFast(NumberDictionary* source,
7375 FixedArray* destination,
7376 WriteBarrierMode mode) {
7377 for (int i = 0; i < source->Capacity(); ++i) {
7378 Object* key = source->KeyAt(i);
7379 if (key->IsNumber()) {
7380 uint32_t entry = static_cast<uint32_t>(key->Number());
7381 destination->set(entry, source->ValueAt(i), mode);
7382 }
7383 }
7384}
7385
7386
John Reck59135872010-11-02 12:39:01 -07007387MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7388 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01007389 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00007390 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007391 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01007392
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007393 // Allocate a new fast elements backing store.
7394 FixedArray* new_elements = NULL;
7395 { Object* object;
7396 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
7397 if (!maybe->ToObject(&object)) return maybe;
7398 new_elements = FixedArray::cast(object);
7399 }
7400
7401 // Find the new map to use for this object if there is a map change.
7402 Map* new_map = NULL;
7403 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
7404 Object* object;
7405 MaybeObject* maybe = map()->GetFastElementsMap();
7406 if (!maybe->ToObject(&object)) return maybe;
7407 new_map = Map::cast(object);
7408 }
7409
7410 switch (GetElementsKind()) {
7411 case FAST_ELEMENTS: {
7412 AssertNoAllocation no_gc;
7413 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7414 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
7415 set_map(new_map);
7416 set_elements(new_elements);
7417 break;
7418 }
7419 case DICTIONARY_ELEMENTS: {
7420 AssertNoAllocation no_gc;
7421 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7422 CopySlowElementsToFast(NumberDictionary::cast(elements()),
7423 new_elements,
7424 mode);
7425 set_map(new_map);
7426 set_elements(new_elements);
7427 break;
7428 }
7429 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7430 AssertNoAllocation no_gc;
7431 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7432 // The object's map and the parameter map are unchanged, the unaliased
7433 // arguments are copied to the new backing store.
7434 FixedArray* parameter_map = FixedArray::cast(elements());
7435 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7436 if (arguments->IsDictionary()) {
7437 CopySlowElementsToFast(NumberDictionary::cast(arguments),
7438 new_elements,
7439 mode);
7440 } else {
7441 CopyFastElementsToFast(arguments, new_elements, mode);
7442 }
7443 parameter_map->set(1, new_elements);
7444 break;
7445 }
7446 case FAST_DOUBLE_ELEMENTS: {
7447 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7448 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7449 // Fill out the new array with this content and array holes.
7450 for (uint32_t i = 0; i < old_length; i++) {
7451 if (!old_elements->is_the_hole(i)) {
7452 Object* obj;
7453 // Objects must be allocated in the old object space, since the
7454 // overall number of HeapNumbers needed for the conversion might
7455 // exceed the capacity of new space, and we would fail repeatedly
7456 // trying to convert the FixedDoubleArray.
7457 MaybeObject* maybe_value_object =
7458 GetHeap()->AllocateHeapNumber(old_elements->get(i), TENURED);
7459 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7460 // Force write barrier. It's not worth trying to exploit
7461 // elems->GetWriteBarrierMode(), since it requires an
7462 // AssertNoAllocation stack object that would have to be positioned
7463 // after the HeapNumber allocation anyway.
7464 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
7465 }
7466 }
7467 set_map(new_map);
7468 set_elements(new_elements);
7469 break;
7470 }
7471 case EXTERNAL_BYTE_ELEMENTS:
7472 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7473 case EXTERNAL_SHORT_ELEMENTS:
7474 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7475 case EXTERNAL_INT_ELEMENTS:
7476 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7477 case EXTERNAL_FLOAT_ELEMENTS:
7478 case EXTERNAL_DOUBLE_ELEMENTS:
7479 case EXTERNAL_PIXEL_ELEMENTS:
7480 UNREACHABLE();
7481 break;
7482 }
7483
7484 // Update the length if necessary.
7485 if (IsJSArray()) {
7486 JSArray::cast(this)->set_length(Smi::FromInt(length));
7487 }
7488
7489 return new_elements;
7490}
7491
7492
7493MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7494 int capacity,
7495 int length) {
7496 Heap* heap = GetHeap();
7497 // We should never end in here with a pixel or external array.
7498 ASSERT(!HasExternalArrayElements());
7499
John Reck59135872010-11-02 12:39:01 -07007500 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007501 { MaybeObject* maybe_obj =
7502 heap->AllocateUninitializedFixedDoubleArray(capacity);
John Reck59135872010-11-02 12:39:01 -07007503 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7504 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007505 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
Steve Block8defd9f2010-07-08 12:39:36 +01007506
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007507 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
John Reck59135872010-11-02 12:39:01 -07007508 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7509 }
Steve Block8defd9f2010-07-08 12:39:36 +01007510 Map* new_map = Map::cast(obj);
7511
Leon Clarke4515c472010-02-03 11:58:03 +00007512 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00007513 switch (GetElementsKind()) {
7514 case FAST_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007515 elems->Initialize(FixedArray::cast(elements()));
7516 break;
7517 }
7518 case FAST_DOUBLE_ELEMENTS: {
7519 elems->Initialize(FixedDoubleArray::cast(elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007520 break;
7521 }
7522 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007523 elems->Initialize(NumberDictionary::cast(elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007524 break;
7525 }
7526 default:
7527 UNREACHABLE();
7528 break;
7529 }
Steve Block8defd9f2010-07-08 12:39:36 +01007530
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007531 ASSERT(new_map->has_fast_double_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01007532 set_map(new_map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007533 ASSERT(elems->IsFixedDoubleArray());
Steve Blocka7e24c12009-10-30 11:49:00 +00007534 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01007535
7536 if (IsJSArray()) {
7537 JSArray::cast(this)->set_length(Smi::FromInt(length));
7538 }
7539
7540 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00007541}
7542
7543
John Reck59135872010-11-02 12:39:01 -07007544MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007545 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007546 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007547
7548 uint32_t new_length = static_cast<uint32_t>(len->Number());
7549
7550 switch (GetElementsKind()) {
7551 case FAST_ELEMENTS: {
7552 // Make sure we never try to shrink dense arrays into sparse arrays.
7553 ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <=
7554 new_length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007555 MaybeObject* result = NormalizeElements();
7556 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007557
7558 // Update length for JSArrays.
7559 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7560 break;
7561 }
7562 case DICTIONARY_ELEMENTS: {
7563 if (IsJSArray()) {
7564 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01007565 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00007566 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7567 JSArray::cast(this)->set_length(len);
7568 }
7569 break;
7570 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007571 case NON_STRICT_ARGUMENTS_ELEMENTS:
7572 UNIMPLEMENTED();
7573 break;
7574 case EXTERNAL_BYTE_ELEMENTS:
7575 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7576 case EXTERNAL_SHORT_ELEMENTS:
7577 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7578 case EXTERNAL_INT_ELEMENTS:
7579 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7580 case EXTERNAL_FLOAT_ELEMENTS:
7581 case EXTERNAL_DOUBLE_ELEMENTS:
7582 case EXTERNAL_PIXEL_ELEMENTS:
7583 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007584 UNREACHABLE();
7585 break;
7586 }
7587 return this;
7588}
7589
7590
John Reck59135872010-11-02 12:39:01 -07007591MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01007592 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007593 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00007594 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00007595 FixedArray* new_elements;
7596 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01007597 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00007598 } else {
John Reck59135872010-11-02 12:39:01 -07007599 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007600 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07007601 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7602 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007603 new_elements = FixedArray::cast(obj);
7604 }
7605 set_elements(new_elements);
7606 return this;
7607}
7608
7609
7610void JSArray::Expand(int required_size) {
7611 Handle<JSArray> self(this);
7612 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
7613 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00007614 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01007615 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00007616 // Can't use this any more now because we may have had a GC!
7617 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7618 self->SetContent(*new_backing);
7619}
7620
7621
Steve Block44f0eee2011-05-26 01:26:41 +01007622static Failure* ArrayLengthRangeError(Heap* heap) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007623 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007624 return heap->isolate()->Throw(
7625 *FACTORY->NewRangeError("invalid_array_length",
7626 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007627}
7628
7629
John Reck59135872010-11-02 12:39:01 -07007630MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007631 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01007632 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00007633
John Reck59135872010-11-02 12:39:01 -07007634 MaybeObject* maybe_smi_length = len->ToSmi();
7635 Object* smi_length = Smi::FromInt(0);
7636 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01007637 const int value = Smi::cast(smi_length)->value();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007638 if (value < 0) return ArrayLengthRangeError(GetHeap());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007639 JSObject::ElementsKind elements_kind = GetElementsKind();
7640 switch (elements_kind) {
7641 case FAST_ELEMENTS:
7642 case FAST_DOUBLE_ELEMENTS: {
7643 int old_capacity = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00007644 if (value <= old_capacity) {
7645 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07007646 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007647 if (elements_kind == FAST_ELEMENTS) {
7648 MaybeObject* maybe_obj = EnsureWritableFastElements();
John Reck59135872010-11-02 12:39:01 -07007649 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7650 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007651 if (2 * value <= old_capacity) {
7652 // If more than half the elements won't be used, trim the array.
7653 if (value == 0) {
7654 initialize_elements();
7655 } else {
7656 Address filler_start;
7657 int filler_size;
7658 if (GetElementsKind() == FAST_ELEMENTS) {
7659 FixedArray* fast_elements = FixedArray::cast(elements());
7660 fast_elements->set_length(value);
7661 filler_start = fast_elements->address() +
7662 FixedArray::OffsetOfElementAt(value);
7663 filler_size = (old_capacity - value) * kPointerSize;
7664 } else {
7665 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7666 FixedDoubleArray* fast_double_elements =
7667 FixedDoubleArray::cast(elements());
7668 fast_double_elements->set_length(value);
7669 filler_start = fast_double_elements->address() +
7670 FixedDoubleArray::OffsetOfElementAt(value);
7671 filler_size = (old_capacity - value) * kDoubleSize;
7672 }
7673 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
7674 }
7675 } else {
7676 // Otherwise, fill the unused tail with holes.
7677 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
7678 if (GetElementsKind() == FAST_ELEMENTS) {
7679 FixedArray* fast_elements = FixedArray::cast(elements());
7680 for (int i = value; i < old_length; i++) {
7681 fast_elements->set_the_hole(i);
7682 }
7683 } else {
7684 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7685 FixedDoubleArray* fast_double_elements =
7686 FixedDoubleArray::cast(elements());
7687 for (int i = value; i < old_length; i++) {
7688 fast_double_elements->set_the_hole(i);
7689 }
7690 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007691 }
Leon Clarke4515c472010-02-03 11:58:03 +00007692 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007693 }
7694 return this;
7695 }
7696 int min = NewElementsCapacity(old_capacity);
7697 int new_capacity = value > min ? value : min;
7698 if (new_capacity <= kMaxFastElementsLength ||
7699 !ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007700 MaybeObject* result;
7701 if (GetElementsKind() == FAST_ELEMENTS) {
7702 result = SetFastElementsCapacityAndLength(new_capacity, value);
7703 } else {
7704 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7705 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
7706 value);
John Reck59135872010-11-02 12:39:01 -07007707 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007708 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007709 return this;
7710 }
7711 break;
7712 }
7713 case DICTIONARY_ELEMENTS: {
7714 if (IsJSArray()) {
7715 if (value == 0) {
7716 // If the length of a slow array is reset to zero, we clear
7717 // the array and flush backing storage. This has the added
7718 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07007719 Object* obj;
7720 { MaybeObject* maybe_obj = ResetElements();
7721 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7722 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007723 } else {
7724 // Remove deleted elements.
7725 uint32_t old_length =
7726 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7727 element_dictionary()->RemoveNumberEntries(value, old_length);
7728 }
Leon Clarke4515c472010-02-03 11:58:03 +00007729 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007730 }
7731 return this;
7732 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007733 case NON_STRICT_ARGUMENTS_ELEMENTS:
7734 case EXTERNAL_BYTE_ELEMENTS:
7735 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7736 case EXTERNAL_SHORT_ELEMENTS:
7737 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7738 case EXTERNAL_INT_ELEMENTS:
7739 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7740 case EXTERNAL_FLOAT_ELEMENTS:
7741 case EXTERNAL_DOUBLE_ELEMENTS:
7742 case EXTERNAL_PIXEL_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007743 UNREACHABLE();
7744 break;
7745 }
7746 }
7747
7748 // General slow case.
7749 if (len->IsNumber()) {
7750 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007751 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007752 return SetSlowElements(len);
7753 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007754 return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00007755 }
7756 }
7757
7758 // len is not a number so make the array size one and
7759 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07007760 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007761 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07007762 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7763 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007764 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00007765 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007766 set_elements(FixedArray::cast(obj));
7767 return this;
7768}
7769
7770
Steve Block053d10c2011-06-13 19:13:29 +01007771Object* Map::GetPrototypeTransition(Object* prototype) {
7772 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007773 int number_of_transitions = NumberOfProtoTransitions();
7774 const int proto_offset =
7775 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7776 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7777 const int step = kProtoTransitionElementsPerEntry;
7778 for (int i = 0; i < number_of_transitions; i++) {
7779 if (cache->get(proto_offset + i * step) == prototype) {
7780 Object* map = cache->get(map_offset + i * step);
7781 ASSERT(map->IsMap());
7782 return map;
7783 }
Steve Block053d10c2011-06-13 19:13:29 +01007784 }
7785 return NULL;
7786}
7787
7788
7789MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007790 ASSERT(map->IsMap());
7791 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01007792 // Don't cache prototype transition if this map is shared.
7793 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7794
7795 FixedArray* cache = prototype_transitions();
7796
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007797 const int step = kProtoTransitionElementsPerEntry;
7798 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01007799
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007800 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01007801
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007802 int transitions = NumberOfProtoTransitions() + 1;
7803
7804 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01007805 if (capacity > kMaxCachedPrototypeTransitions) return this;
7806
7807 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007808 // Grow array by factor 2 over and above what we need.
7809 { MaybeObject* maybe_cache =
7810 heap()->AllocateFixedArray(transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +01007811 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7812 }
7813
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007814 for (int i = 0; i < capacity * step; i++) {
7815 new_cache->set(i + header, cache->get(i + header));
7816 }
Steve Block053d10c2011-06-13 19:13:29 +01007817 cache = new_cache;
7818 set_prototype_transitions(cache);
7819 }
7820
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007821 int last = transitions - 1;
7822
7823 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7824 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7825 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01007826
7827 return cache;
7828}
7829
7830
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007831MaybeObject* JSReceiver::SetPrototype(Object* value,
7832 bool skip_hidden_prototypes) {
7833#ifdef DEBUG
7834 int size = Size();
7835#endif
7836
Steve Block44f0eee2011-05-26 01:26:41 +01007837 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00007838 // Silently ignore the change if value is not a JSObject or null.
7839 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007840 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00007841
Ben Murdoch8b112d22011-06-08 16:22:53 +01007842 // From 8.6.2 Object Internal Methods
7843 // ...
7844 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7845 // [[Prototype]] internal properties of the object may not be modified.
7846 // ...
7847 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7848 // or [[Extensible]] must not violate the invariants defined in the preceding
7849 // paragraph.
7850 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007851 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01007852 Handle<Object> handle(this, heap->isolate());
7853 return heap->isolate()->Throw(
7854 *FACTORY->NewTypeError("non_extensible_proto",
7855 HandleVector<Object>(&handle, 1)));
7856 }
7857
Andrei Popescu402d9372010-02-26 13:31:12 +00007858 // Before we can set the prototype we need to be sure
7859 // prototype cycles are prevented.
7860 // It is sufficient to validate that the receiver is not in the new prototype
7861 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01007862 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007863 if (JSObject::cast(pt) == this) {
7864 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007865 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007866 return heap->isolate()->Throw(
7867 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00007868 }
7869 }
7870
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007871 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00007872
7873 if (skip_hidden_prototypes) {
7874 // Find the first object in the chain whose prototype object is not
7875 // hidden and set the new prototype on that object.
7876 Object* current_proto = real_receiver->GetPrototype();
7877 while (current_proto->IsJSObject() &&
7878 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7879 real_receiver = JSObject::cast(current_proto);
7880 current_proto = current_proto->GetPrototype();
7881 }
7882 }
7883
7884 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01007885 Map* map = real_receiver->map();
7886
7887 // Nothing to do if prototype is already set.
7888 if (map->prototype() == value) return value;
7889
7890 Object* new_map = map->GetPrototypeTransition(value);
7891 if (new_map == NULL) {
7892 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7893 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7894 }
7895
7896 { MaybeObject* maybe_new_cache =
7897 map->PutPrototypeTransition(value, Map::cast(new_map));
7898 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7899 }
7900
7901 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07007902 }
Steve Block053d10c2011-06-13 19:13:29 +01007903 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00007904 real_receiver->set_map(Map::cast(new_map));
7905
Steve Block44f0eee2011-05-26 01:26:41 +01007906 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007907 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00007908 return value;
7909}
7910
7911
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007912bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007913 switch (GetElementsKind()) {
7914 case FAST_ELEMENTS: {
7915 uint32_t length = IsJSArray() ?
7916 static_cast<uint32_t>
7917 (Smi::cast(JSArray::cast(this)->length())->value()) :
7918 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7919 if ((index < length) &&
7920 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7921 return true;
7922 }
7923 break;
7924 }
Steve Block44f0eee2011-05-26 01:26:41 +01007925 case EXTERNAL_PIXEL_ELEMENTS: {
7926 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007927 if (index < static_cast<uint32_t>(pixels->length())) {
7928 return true;
7929 }
7930 break;
7931 }
Steve Block3ce2e202009-11-05 08:53:23 +00007932 case EXTERNAL_BYTE_ELEMENTS:
7933 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7934 case EXTERNAL_SHORT_ELEMENTS:
7935 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7936 case EXTERNAL_INT_ELEMENTS:
7937 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007938 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007939 case EXTERNAL_DOUBLE_ELEMENTS:
7940 case FAST_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007941 ExternalArray* array = ExternalArray::cast(elements());
7942 if (index < static_cast<uint32_t>(array->length())) {
7943 return true;
7944 }
7945 break;
7946 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007947 case DICTIONARY_ELEMENTS: {
7948 if (element_dictionary()->FindEntry(index)
7949 != NumberDictionary::kNotFound) {
7950 return true;
7951 }
7952 break;
7953 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007954 case NON_STRICT_ARGUMENTS_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007955 UNREACHABLE();
7956 break;
7957 }
7958
7959 // Handle [] on String objects.
7960 if (this->IsStringObjectWithCharacterAt(index)) return true;
7961
7962 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007963 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007964 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7965}
7966
7967
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007968bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007969 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007970 // Make sure that the top context does not change when doing
7971 // callbacks or interceptor calls.
7972 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007973 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007974 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007975 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00007976 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007977 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007978 v8::AccessorInfo info(args.end());
7979 if (!interceptor->query()->IsUndefined()) {
7980 v8::IndexedPropertyQuery query =
7981 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007982 LOG(isolate,
7983 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007984 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007985 {
7986 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007987 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007988 result = query(index, info);
7989 }
Iain Merrick75681382010-08-19 15:07:18 +01007990 if (!result.IsEmpty()) {
7991 ASSERT(result->IsInt32());
7992 return true; // absence of property is signaled by empty handle.
7993 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007994 } else if (!interceptor->getter()->IsUndefined()) {
7995 v8::IndexedPropertyGetter getter =
7996 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007997 LOG(isolate,
7998 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007999 v8::Handle<v8::Value> result;
8000 {
8001 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008002 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008003 result = getter(index, info);
8004 }
8005 if (!result.IsEmpty()) return true;
8006 }
8007 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
8008}
8009
8010
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008011JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008012 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008013 if (IsAccessCheckNeeded()) {
8014 Heap* heap = GetHeap();
8015 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8016 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8017 return UNDEFINED_ELEMENT;
8018 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008019 }
8020
Steve Block1e0659c2011-05-24 12:43:12 +01008021 if (IsJSGlobalProxy()) {
8022 Object* proto = GetPrototype();
8023 if (proto->IsNull()) return UNDEFINED_ELEMENT;
8024 ASSERT(proto->IsJSGlobalObject());
8025 return JSObject::cast(proto)->HasLocalElement(index);
8026 }
8027
Steve Blocka7e24c12009-10-30 11:49:00 +00008028 // Check for lookup interceptor
8029 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008030 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
8031 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008032 }
8033
8034 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008035 if (this->IsStringObjectWithCharacterAt(index)) {
8036 return STRING_CHARACTER_ELEMENT;
8037 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008038
8039 switch (GetElementsKind()) {
8040 case FAST_ELEMENTS: {
8041 uint32_t length = IsJSArray() ?
8042 static_cast<uint32_t>
8043 (Smi::cast(JSArray::cast(this)->length())->value()) :
8044 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008045 if ((index < length) &&
8046 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
8047 return FAST_ELEMENT;
8048 }
8049 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008050 }
Steve Block44f0eee2011-05-26 01:26:41 +01008051 case EXTERNAL_PIXEL_ELEMENTS: {
8052 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008053 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
8054 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008055 }
Steve Block3ce2e202009-11-05 08:53:23 +00008056 case EXTERNAL_BYTE_ELEMENTS:
8057 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8058 case EXTERNAL_SHORT_ELEMENTS:
8059 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8060 case EXTERNAL_INT_ELEMENTS:
8061 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008062 case EXTERNAL_FLOAT_ELEMENTS:
8063 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008064 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008065 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
8066 break;
Steve Block3ce2e202009-11-05 08:53:23 +00008067 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008068 case FAST_DOUBLE_ELEMENTS:
8069 UNREACHABLE();
8070 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008071 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008072 if (element_dictionary()->FindEntry(index) !=
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008073 NumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008074 return DICTIONARY_ELEMENT;
8075 }
8076 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008077 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008078 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8079 // Aliased parameters and non-aliased elements in a fast backing store
8080 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
8081 // backing store behave as DICTIONARY_ELEMENT.
8082 FixedArray* parameter_map = FixedArray::cast(elements());
8083 uint32_t length = parameter_map->length();
8084 Object* probe =
8085 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
8086 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8087 // If not aliased, check the arguments.
8088 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8089 if (arguments->IsDictionary()) {
8090 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
8091 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
8092 return DICTIONARY_ELEMENT;
8093 }
8094 } else {
8095 length = arguments->length();
8096 probe = (index < length) ? arguments->get(index) : NULL;
8097 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8098 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008099 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008100 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008101 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008102
8103 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008104}
8105
8106
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008107bool JSObject::HasElementInElements(FixedArray* elements,
8108 ElementsKind kind,
8109 uint32_t index) {
8110 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8111 if (kind == FAST_ELEMENTS) {
8112 int length = IsJSArray()
8113 ? Smi::cast(JSArray::cast(this)->length())->value()
8114 : elements->length();
8115 if (index < static_cast<uint32_t>(length) &&
8116 !elements->get(index)->IsTheHole()) {
8117 return true;
8118 }
8119 } else {
8120 if (NumberDictionary::cast(elements)->FindEntry(index) !=
8121 NumberDictionary::kNotFound) {
8122 return true;
8123 }
8124 }
8125 return false;
8126}
8127
8128
8129bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008130 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008131 if (IsAccessCheckNeeded()) {
8132 Heap* heap = GetHeap();
8133 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8134 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8135 return false;
8136 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008137 }
8138
8139 // Check for lookup interceptor
8140 if (HasIndexedInterceptor()) {
8141 return HasElementWithInterceptor(receiver, index);
8142 }
8143
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008144 ElementsKind kind = GetElementsKind();
8145 switch (kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008146 case FAST_ELEMENTS: {
8147 uint32_t length = IsJSArray() ?
8148 static_cast<uint32_t>
8149 (Smi::cast(JSArray::cast(this)->length())->value()) :
8150 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8151 if ((index < length) &&
8152 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8153 break;
8154 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008155 case FAST_DOUBLE_ELEMENTS: {
8156 uint32_t length = IsJSArray() ?
8157 static_cast<uint32_t>
8158 (Smi::cast(JSArray::cast(this)->length())->value()) :
8159 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8160 if ((index < length) &&
8161 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8162 break;
8163 }
Steve Block44f0eee2011-05-26 01:26:41 +01008164 case EXTERNAL_PIXEL_ELEMENTS: {
8165 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008166 if (index < static_cast<uint32_t>(pixels->length())) {
8167 return true;
8168 }
8169 break;
8170 }
Steve Block3ce2e202009-11-05 08:53:23 +00008171 case EXTERNAL_BYTE_ELEMENTS:
8172 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8173 case EXTERNAL_SHORT_ELEMENTS:
8174 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8175 case EXTERNAL_INT_ELEMENTS:
8176 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008177 case EXTERNAL_FLOAT_ELEMENTS:
8178 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008179 ExternalArray* array = ExternalArray::cast(elements());
8180 if (index < static_cast<uint32_t>(array->length())) {
8181 return true;
8182 }
8183 break;
8184 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008185 case DICTIONARY_ELEMENTS: {
8186 if (element_dictionary()->FindEntry(index)
8187 != NumberDictionary::kNotFound) {
8188 return true;
8189 }
8190 break;
8191 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008192 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8193 FixedArray* parameter_map = FixedArray::cast(elements());
8194 uint32_t length = parameter_map->length();
8195 Object* probe =
8196 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8197 if (probe != NULL && !probe->IsTheHole()) return true;
8198
8199 // Not a mapped parameter, check the arguments.
8200 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8201 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8202 if (HasElementInElements(arguments, kind, index)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008203 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008204 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008205 }
8206
8207 // Handle [] on String objects.
8208 if (this->IsStringObjectWithCharacterAt(index)) return true;
8209
8210 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008211 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008212 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8213}
8214
8215
John Reck59135872010-11-02 12:39:01 -07008216MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008217 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008218 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008219 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008220 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008221 // Make sure that the top context does not change when doing
8222 // callbacks or interceptor calls.
8223 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008224 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008225 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8226 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008227 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008228 if (!interceptor->setter()->IsUndefined()) {
8229 v8::IndexedPropertySetter setter =
8230 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01008231 LOG(isolate,
8232 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8233 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008234 v8::AccessorInfo info(args.end());
8235 v8::Handle<v8::Value> result;
8236 {
8237 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008238 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008239 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8240 }
Steve Block44f0eee2011-05-26 01:26:41 +01008241 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008242 if (!result.IsEmpty()) return *value_handle;
8243 }
John Reck59135872010-11-02 12:39:01 -07008244 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01008245 this_handle->SetElementWithoutInterceptor(index,
8246 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008247 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008248 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008249 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008250 return raw_result;
8251}
8252
8253
John Reck59135872010-11-02 12:39:01 -07008254MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8255 Object* structure,
8256 uint32_t index,
8257 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01008258 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00008259 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008260
8261 // api style callbacks.
8262 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00008263 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008264 Object* fun_obj = data->getter();
8265 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008266 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008267 Handle<JSObject> self(JSObject::cast(receiver));
8268 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01008269 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008270 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01008271 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8272 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008273 v8::AccessorInfo info(args.end());
8274 v8::Handle<v8::Value> result;
8275 {
8276 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008277 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008278 result = call_fun(v8::Utils::ToLocal(key), info);
8279 }
Steve Block44f0eee2011-05-26 01:26:41 +01008280 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8281 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008282 return *v8::Utils::OpenHandle(*result);
8283 }
8284
8285 // __defineGetter__ callback
8286 if (structure->IsFixedArray()) {
8287 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
8288 if (getter->IsJSFunction()) {
8289 return Object::GetPropertyWithDefinedGetter(receiver,
8290 JSFunction::cast(getter));
8291 }
8292 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01008293 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008294 }
8295
8296 UNREACHABLE();
8297 return NULL;
8298}
8299
8300
John Reck59135872010-11-02 12:39:01 -07008301MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8302 uint32_t index,
8303 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008304 JSObject* holder,
8305 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008306 Isolate* isolate = GetIsolate();
8307 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008308
8309 // We should never get here to initialize a const with the hole
8310 // value since a const declaration would conflict with the setter.
8311 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01008312 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008313
8314 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00008315 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01008316 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00008317 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008318
8319 if (structure->IsAccessorInfo()) {
8320 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00008321 Handle<JSObject> self(this);
8322 Handle<JSObject> holder_handle(JSObject::cast(holder));
8323 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008324 Object* call_obj = data->setter();
8325 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8326 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01008327 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8328 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00008329 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8330 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008331 v8::AccessorInfo info(args.end());
8332 {
8333 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008334 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008335 call_fun(v8::Utils::ToLocal(key),
8336 v8::Utils::ToLocal(value_handle),
8337 info);
8338 }
Steve Block44f0eee2011-05-26 01:26:41 +01008339 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008340 return *value_handle;
8341 }
8342
8343 if (structure->IsFixedArray()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008344 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
Leon Clarkef7060e22010-06-03 12:02:55 +01008345 if (setter->IsJSFunction()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008346 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01008347 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008348 if (strict_mode == kNonStrictMode) {
8349 return value;
8350 }
Steve Block44f0eee2011-05-26 01:26:41 +01008351 Handle<Object> holder_handle(holder, isolate);
8352 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01008353 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01008354 return isolate->Throw(
8355 *isolate->factory()->NewTypeError("no_setter_in_callback",
8356 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01008357 }
8358 }
8359
8360 UNREACHABLE();
8361 return NULL;
8362}
8363
8364
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008365bool JSObject::HasFastArgumentsElements() {
8366 Heap* heap = GetHeap();
8367 if (!elements()->IsFixedArray()) return false;
8368 FixedArray* elements = FixedArray::cast(this->elements());
8369 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8370 return false;
8371 }
8372 FixedArray* arguments = FixedArray::cast(elements->get(1));
8373 return !arguments->IsDictionary();
8374}
8375
8376
8377bool JSObject::HasDictionaryArgumentsElements() {
8378 Heap* heap = GetHeap();
8379 if (!elements()->IsFixedArray()) return false;
8380 FixedArray* elements = FixedArray::cast(this->elements());
8381 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8382 return false;
8383 }
8384 FixedArray* arguments = FixedArray::cast(elements->get(1));
8385 return arguments->IsDictionary();
8386}
8387
8388
Steve Blocka7e24c12009-10-30 11:49:00 +00008389// Adding n elements in fast case is O(n*n).
8390// Note: revisit design to have dual undefined values to capture absent
8391// elements.
Steve Block9fac8402011-05-12 15:51:54 +01008392MaybeObject* JSObject::SetFastElement(uint32_t index,
8393 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008394 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008395 bool check_prototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008396 ASSERT(HasFastElements() || HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008397
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008398 FixedArray* backing_store = FixedArray::cast(elements());
8399 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
8400 backing_store = FixedArray::cast(backing_store->get(1));
8401 } else {
8402 Object* writable;
8403 MaybeObject* maybe = EnsureWritableFastElements();
8404 if (!maybe->ToObject(&writable)) return maybe;
8405 backing_store = FixedArray::cast(writable);
John Reck59135872010-11-02 12:39:01 -07008406 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008407 uint32_t length = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008408
Steve Block9fac8402011-05-12 15:51:54 +01008409 if (check_prototype &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008410 (index >= length || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01008411 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008412 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8413 value,
8414 &found,
8415 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01008416 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008417 }
8418
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008419 // Check whether there is extra space in fixed array.
8420 if (index < length) {
8421 backing_store->set(index, value);
8422 if (IsJSArray()) {
8423 // Update the length of the array if needed.
8424 uint32_t array_length = 0;
8425 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8426 if (index >= array_length) {
8427 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
8428 }
8429 }
8430 return value;
8431 }
Steve Block9fac8402011-05-12 15:51:54 +01008432
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008433 // Allow gap in fast case.
8434 if ((index - length) < kMaxGap) {
8435 // Try allocating extra space.
8436 int new_capacity = NewElementsCapacity(index + 1);
8437 if (new_capacity <= kMaxFastElementsLength ||
8438 !ShouldConvertToSlowElements(new_capacity)) {
8439 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8440 Object* new_elements;
8441 MaybeObject* maybe =
8442 SetFastElementsCapacityAndLength(new_capacity, index + 1);
8443 if (!maybe->ToObject(&new_elements)) return maybe;
8444 FixedArray::cast(new_elements)->set(index, value);
8445 return value;
8446 }
8447 }
8448
8449 // Otherwise default to slow case.
8450 MaybeObject* result = NormalizeElements();
8451 if (result->IsFailure()) return result;
8452 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8453}
8454
8455
8456MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
8457 Object* value,
8458 StrictModeFlag strict_mode,
8459 bool check_prototype) {
8460 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
8461 Isolate* isolate = GetIsolate();
8462 Heap* heap = isolate->heap();
8463
8464 // Insert element in the dictionary.
8465 FixedArray* elements = FixedArray::cast(this->elements());
8466 bool is_arguments =
8467 (elements->map() == heap->non_strict_arguments_elements_map());
8468 NumberDictionary* dictionary = NULL;
8469 if (is_arguments) {
8470 dictionary = NumberDictionary::cast(elements->get(1));
8471 } else {
8472 dictionary = NumberDictionary::cast(elements);
8473 }
8474
8475 int entry = dictionary->FindEntry(index);
8476 if (entry != NumberDictionary::kNotFound) {
8477 Object* element = dictionary->ValueAt(entry);
8478 PropertyDetails details = dictionary->DetailsAt(entry);
8479 if (details.type() == CALLBACKS) {
8480 return SetElementWithCallback(element, index, value, this, strict_mode);
8481 } else {
8482 dictionary->UpdateMaxNumberKey(index);
8483 // If put fails in strict mode, throw an exception.
8484 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
8485 Handle<Object> holder(this);
8486 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8487 Handle<Object> args[2] = { number, holder };
8488 Handle<Object> error =
8489 isolate->factory()->NewTypeError("strict_read_only_property",
8490 HandleVector(args, 2));
8491 return isolate->Throw(*error);
8492 }
8493 }
8494 } else {
8495 // Index not already used. Look for an accessor in the prototype chain.
8496 if (check_prototype) {
8497 bool found;
8498 MaybeObject* result =
8499 SetElementWithCallbackSetterInPrototypes(
8500 index, value, &found, strict_mode);
8501 if (found) return result;
8502 }
8503 // When we set the is_extensible flag to false we always force the
8504 // element into dictionary mode (and force them to stay there).
8505 if (!map()->is_extensible()) {
8506 if (strict_mode == kNonStrictMode) {
8507 return isolate->heap()->undefined_value();
8508 } else {
8509 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8510 Handle<String> name = isolate->factory()->NumberToString(number);
8511 Handle<Object> args[1] = { name };
8512 Handle<Object> error =
8513 isolate->factory()->NewTypeError("object_not_extensible",
8514 HandleVector(args, 1));
8515 return isolate->Throw(*error);
8516 }
8517 }
8518 Object* new_dictionary;
8519 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
8520 if (!maybe->ToObject(&new_dictionary)) return maybe;
8521 if (dictionary != NumberDictionary::cast(new_dictionary)) {
8522 if (is_arguments) {
8523 elements->set(1, new_dictionary);
8524 } else {
8525 set_elements(HeapObject::cast(new_dictionary));
8526 }
8527 dictionary = NumberDictionary::cast(new_dictionary);
8528 }
8529 }
8530
8531 // Update the array length if this JSObject is an array.
8532 if (IsJSArray()) {
8533 MaybeObject* result =
8534 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
8535 if (result->IsFailure()) return result;
8536 }
8537
8538 // Attempt to put this object back in fast case.
8539 if (ShouldConvertToFastElements()) {
8540 uint32_t new_length = 0;
8541 if (IsJSArray()) {
8542 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
8543 } else {
8544 new_length = dictionary->max_number_key() + 1;
8545 }
8546 MaybeObject* result = ShouldConvertToFastDoubleElements()
8547 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
8548 : SetFastElementsCapacityAndLength(new_length, new_length);
8549 if (result->IsFailure()) return result;
8550#ifdef DEBUG
8551 if (FLAG_trace_normalization) {
8552 PrintF("Object elements are fast case again:\n");
8553 Print();
8554 }
8555#endif
8556 }
8557 return value;
8558}
8559
8560
8561MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8562 uint32_t index,
8563 Object* value,
8564 StrictModeFlag strict_mode,
8565 bool check_prototype) {
8566 ASSERT(HasFastDoubleElements());
8567
8568 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8569 uint32_t elms_length = static_cast<uint32_t>(elms->length());
8570
8571 // If storing to an element that isn't in the array, pass the store request
8572 // up the prototype chain before storing in the receiver's elements.
8573 if (check_prototype &&
8574 (index >= elms_length || elms->is_the_hole(index))) {
8575 bool found;
8576 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8577 value,
8578 &found,
8579 strict_mode);
8580 if (found) return result;
8581 }
8582
8583 // If the value object is not a heap number, switch to fast elements and try
8584 // again.
8585 bool value_is_smi = value->IsSmi();
8586 if (!value->IsNumber()) {
8587 Object* obj;
8588 uint32_t length = elms_length;
8589 if (IsJSArray()) {
8590 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8591 }
8592 MaybeObject* maybe_obj =
8593 SetFastElementsCapacityAndLength(elms_length, length);
8594 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8595 return SetFastElement(index, value, strict_mode, check_prototype);
8596 }
8597
8598 double double_value = value_is_smi
8599 ? static_cast<double>(Smi::cast(value)->value())
8600 : HeapNumber::cast(value)->value();
8601
8602 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00008603 if (index < elms_length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008604 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008605 if (IsJSArray()) {
8606 // Update the length of the array if needed.
8607 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008608 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00008609 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00008610 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00008611 }
8612 }
8613 return value;
8614 }
8615
8616 // Allow gap in fast case.
8617 if ((index - elms_length) < kMaxGap) {
8618 // Try allocating extra space.
8619 int new_capacity = NewElementsCapacity(index+1);
8620 if (new_capacity <= kMaxFastElementsLength ||
8621 !ShouldConvertToSlowElements(new_capacity)) {
8622 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07008623 Object* obj;
8624 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008625 SetFastDoubleElementsCapacityAndLength(new_capacity,
8626 index + 1);
John Reck59135872010-11-02 12:39:01 -07008627 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8628 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008629 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008630 return value;
8631 }
8632 }
8633
8634 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008635 ASSERT(HasFastDoubleElements());
8636 ASSERT(map()->has_fast_double_elements());
8637 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07008638 Object* obj;
8639 { MaybeObject* maybe_obj = NormalizeElements();
8640 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8641 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008642 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008643 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008644}
8645
Iain Merrick75681382010-08-19 15:07:18 +01008646
Steve Block9fac8402011-05-12 15:51:54 +01008647MaybeObject* JSObject::SetElement(uint32_t index,
8648 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008649 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008650 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008651 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008652 if (IsAccessCheckNeeded()) {
8653 Heap* heap = GetHeap();
8654 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008655 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008656 Handle<Object> value_handle(value);
8657 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8658 return *value_handle;
8659 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008660 }
8661
8662 if (IsJSGlobalProxy()) {
8663 Object* proto = GetPrototype();
8664 if (proto->IsNull()) return value;
8665 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008666 return JSObject::cast(proto)->SetElement(index,
8667 value,
8668 strict_mode,
8669 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008670 }
8671
8672 // Check for lookup interceptor
8673 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008674 return SetElementWithInterceptor(index,
8675 value,
8676 strict_mode,
8677 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008678 }
8679
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008680 return SetElementWithoutInterceptor(index,
8681 value,
8682 strict_mode,
8683 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008684}
8685
8686
John Reck59135872010-11-02 12:39:01 -07008687MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008688 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008689 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008690 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008691 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008692 switch (GetElementsKind()) {
8693 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008694 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008695 case FAST_DOUBLE_ELEMENTS:
8696 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008697 case EXTERNAL_PIXEL_ELEMENTS: {
8698 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008699 return pixels->SetValue(index, value);
8700 }
Steve Block3ce2e202009-11-05 08:53:23 +00008701 case EXTERNAL_BYTE_ELEMENTS: {
8702 ExternalByteArray* array = ExternalByteArray::cast(elements());
8703 return array->SetValue(index, value);
8704 }
8705 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8706 ExternalUnsignedByteArray* array =
8707 ExternalUnsignedByteArray::cast(elements());
8708 return array->SetValue(index, value);
8709 }
8710 case EXTERNAL_SHORT_ELEMENTS: {
8711 ExternalShortArray* array = ExternalShortArray::cast(elements());
8712 return array->SetValue(index, value);
8713 }
8714 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8715 ExternalUnsignedShortArray* array =
8716 ExternalUnsignedShortArray::cast(elements());
8717 return array->SetValue(index, value);
8718 }
8719 case EXTERNAL_INT_ELEMENTS: {
8720 ExternalIntArray* array = ExternalIntArray::cast(elements());
8721 return array->SetValue(index, value);
8722 }
8723 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8724 ExternalUnsignedIntArray* array =
8725 ExternalUnsignedIntArray::cast(elements());
8726 return array->SetValue(index, value);
8727 }
8728 case EXTERNAL_FLOAT_ELEMENTS: {
8729 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8730 return array->SetValue(index, value);
8731 }
Ben Murdoch257744e2011-11-30 15:57:28 +00008732 case EXTERNAL_DOUBLE_ELEMENTS: {
8733 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8734 return array->SetValue(index, value);
8735 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008736 case DICTIONARY_ELEMENTS:
8737 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8738 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8739 FixedArray* parameter_map = FixedArray::cast(elements());
8740 uint32_t length = parameter_map->length();
8741 Object* probe =
8742 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8743 if (probe != NULL && !probe->IsTheHole()) {
8744 Context* context = Context::cast(parameter_map->get(0));
8745 int context_index = Smi::cast(probe)->value();
8746 ASSERT(!context->get(context_index)->IsTheHole());
8747 context->set(context_index, value);
8748 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00008749 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008750 // Object is not mapped, defer to the arguments.
8751 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8752 if (arguments->IsDictionary()) {
8753 return SetDictionaryElement(index, value, strict_mode,
8754 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008755 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008756 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008757 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008758 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008759 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008760 }
8761 // All possible cases have been handled above. Add a return to avoid the
8762 // complaints from the compiler.
8763 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01008764 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008765}
8766
8767
John Reck59135872010-11-02 12:39:01 -07008768MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8769 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008770 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008771 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00008772 // Check to see if we need to update the length. For now, we make
8773 // sure that the length stays within 32-bits (unsigned).
8774 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07008775 Object* len;
8776 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01008777 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07008778 if (!maybe_len->ToObject(&len)) return maybe_len;
8779 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008780 set_length(len);
8781 }
8782 return value;
8783}
8784
8785
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008786MaybeObject* JSObject::GetElementPostInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07008787 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008788 // Get element works for both JSObject and JSArray since
8789 // JSArray::length cannot change.
8790 switch (GetElementsKind()) {
8791 case FAST_ELEMENTS: {
8792 FixedArray* elms = FixedArray::cast(elements());
8793 if (index < static_cast<uint32_t>(elms->length())) {
8794 Object* value = elms->get(index);
8795 if (!value->IsTheHole()) return value;
8796 }
8797 break;
8798 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008799 case FAST_DOUBLE_ELEMENTS: {
8800 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8801 if (index < static_cast<uint32_t>(elms->length())) {
8802 if (!elms->is_the_hole(index)) {
8803 return GetHeap()->NumberFromDouble(elms->get(index));
8804 }
8805 }
8806 break;
8807 }
Steve Block44f0eee2011-05-26 01:26:41 +01008808 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00008809 case EXTERNAL_BYTE_ELEMENTS:
8810 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8811 case EXTERNAL_SHORT_ELEMENTS:
8812 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8813 case EXTERNAL_INT_ELEMENTS:
8814 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008815 case EXTERNAL_FLOAT_ELEMENTS:
8816 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008817 MaybeObject* maybe_value = GetExternalElement(index);
8818 Object* value;
8819 if (!maybe_value->ToObject(&value)) return maybe_value;
8820 if (!value->IsUndefined()) return value;
Steve Block3ce2e202009-11-05 08:53:23 +00008821 break;
8822 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008823 case DICTIONARY_ELEMENTS: {
8824 NumberDictionary* dictionary = element_dictionary();
8825 int entry = dictionary->FindEntry(index);
8826 if (entry != NumberDictionary::kNotFound) {
8827 Object* element = dictionary->ValueAt(entry);
8828 PropertyDetails details = dictionary->DetailsAt(entry);
8829 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01008830 return GetElementWithCallback(receiver,
8831 element,
8832 index,
8833 this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008834 }
8835 return element;
8836 }
8837 break;
8838 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008839 case NON_STRICT_ARGUMENTS_ELEMENTS:
8840 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00008841 break;
8842 }
8843
8844 // Continue searching via the prototype chain.
8845 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008846 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008847 return pt->GetElementWithReceiver(receiver, index);
8848}
8849
8850
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008851MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07008852 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008853 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008854 // Make sure that the top context does not change when doing
8855 // callbacks or interceptor calls.
8856 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008857 HandleScope scope(isolate);
8858 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8859 Handle<Object> this_handle(receiver, isolate);
8860 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008861 if (!interceptor->getter()->IsUndefined()) {
8862 v8::IndexedPropertyGetter getter =
8863 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008864 LOG(isolate,
8865 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8866 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008867 v8::AccessorInfo info(args.end());
8868 v8::Handle<v8::Value> result;
8869 {
8870 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008871 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008872 result = getter(index, info);
8873 }
Steve Block44f0eee2011-05-26 01:26:41 +01008874 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008875 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8876 }
8877
John Reck59135872010-11-02 12:39:01 -07008878 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00008879 holder_handle->GetElementPostInterceptor(*this_handle, index);
Steve Block44f0eee2011-05-26 01:26:41 +01008880 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008881 return raw_result;
8882}
8883
8884
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008885MaybeObject* JSObject::GetElementWithReceiver(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07008886 uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008887 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008888 if (IsAccessCheckNeeded()) {
8889 Heap* heap = GetHeap();
8890 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_GET)) {
8891 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
8892 return heap->undefined_value();
8893 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008894 }
8895
8896 if (HasIndexedInterceptor()) {
8897 return GetElementWithInterceptor(receiver, index);
8898 }
8899
8900 // Get element works for both JSObject and JSArray since
8901 // JSArray::length cannot change.
8902 switch (GetElementsKind()) {
8903 case FAST_ELEMENTS: {
8904 FixedArray* elms = FixedArray::cast(elements());
8905 if (index < static_cast<uint32_t>(elms->length())) {
8906 Object* value = elms->get(index);
8907 if (!value->IsTheHole()) return value;
8908 }
8909 break;
8910 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008911 case FAST_DOUBLE_ELEMENTS: {
8912 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8913 if (index < static_cast<uint32_t>(elms->length())) {
8914 if (!elms->is_the_hole(index)) {
8915 double double_value = elms->get(index);
8916 return GetHeap()->NumberFromDouble(double_value);
8917 }
8918 }
8919 break;
8920 }
Steve Block44f0eee2011-05-26 01:26:41 +01008921 case EXTERNAL_PIXEL_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008922 case EXTERNAL_BYTE_ELEMENTS:
8923 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8924 case EXTERNAL_SHORT_ELEMENTS:
8925 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8926 case EXTERNAL_INT_ELEMENTS:
8927 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008928 case EXTERNAL_FLOAT_ELEMENTS:
8929 case EXTERNAL_DOUBLE_ELEMENTS: {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008930 MaybeObject* maybe_value = GetExternalElement(index);
8931 Object* value;
8932 if (!maybe_value->ToObject(&value)) return maybe_value;
8933 if (!value->IsUndefined()) return value;
8934 break;
8935 }
8936 case DICTIONARY_ELEMENTS: {
8937 NumberDictionary* dictionary = element_dictionary();
8938 int entry = dictionary->FindEntry(index);
8939 if (entry != NumberDictionary::kNotFound) {
8940 Object* element = dictionary->ValueAt(entry);
8941 PropertyDetails details = dictionary->DetailsAt(entry);
8942 if (details.type() == CALLBACKS) {
8943 return GetElementWithCallback(receiver,
8944 element,
8945 index,
8946 this);
8947 }
8948 return element;
8949 }
8950 break;
8951 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008952 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8953 FixedArray* parameter_map = FixedArray::cast(elements());
8954 uint32_t length = parameter_map->length();
8955 Object* probe =
8956 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8957 if (probe != NULL && !probe->IsTheHole()) {
8958 Context* context = Context::cast(parameter_map->get(0));
8959 int context_index = Smi::cast(probe)->value();
8960 ASSERT(!context->get(context_index)->IsTheHole());
8961 return context->get(context_index);
8962 } else {
8963 // Object is not mapped, defer to the arguments.
8964 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8965 if (arguments->IsDictionary()) {
8966 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
8967 int entry = dictionary->FindEntry(index);
8968 if (entry != NumberDictionary::kNotFound) {
8969 Object* element = dictionary->ValueAt(entry);
8970 PropertyDetails details = dictionary->DetailsAt(entry);
8971 if (details.type() == CALLBACKS) {
8972 return GetElementWithCallback(receiver,
8973 element,
8974 index,
8975 this);
8976 }
8977 return element;
8978 }
8979 } else if (index < static_cast<uint32_t>(arguments->length())) {
8980 Object* value = arguments->get(index);
8981 if (!value->IsTheHole()) return value;
8982 }
8983 }
8984 break;
8985 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008986 }
8987
8988 Object* pt = GetPrototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +01008989 Heap* heap = GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +01008990 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008991 return pt->GetElementWithReceiver(receiver, index);
8992}
8993
8994
8995MaybeObject* JSObject::GetExternalElement(uint32_t index) {
8996 // Get element works for both JSObject and JSArray since
8997 // JSArray::length cannot change.
8998 switch (GetElementsKind()) {
Steve Block44f0eee2011-05-26 01:26:41 +01008999 case EXTERNAL_PIXEL_ELEMENTS: {
9000 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009001 if (index < static_cast<uint32_t>(pixels->length())) {
9002 uint8_t value = pixels->get(index);
9003 return Smi::FromInt(value);
9004 }
9005 break;
9006 }
Steve Block3ce2e202009-11-05 08:53:23 +00009007 case EXTERNAL_BYTE_ELEMENTS: {
9008 ExternalByteArray* array = ExternalByteArray::cast(elements());
9009 if (index < static_cast<uint32_t>(array->length())) {
9010 int8_t value = array->get(index);
9011 return Smi::FromInt(value);
9012 }
9013 break;
9014 }
9015 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9016 ExternalUnsignedByteArray* array =
9017 ExternalUnsignedByteArray::cast(elements());
9018 if (index < static_cast<uint32_t>(array->length())) {
9019 uint8_t value = array->get(index);
9020 return Smi::FromInt(value);
9021 }
9022 break;
9023 }
9024 case EXTERNAL_SHORT_ELEMENTS: {
9025 ExternalShortArray* array = ExternalShortArray::cast(elements());
9026 if (index < static_cast<uint32_t>(array->length())) {
9027 int16_t value = array->get(index);
9028 return Smi::FromInt(value);
9029 }
9030 break;
9031 }
9032 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9033 ExternalUnsignedShortArray* array =
9034 ExternalUnsignedShortArray::cast(elements());
9035 if (index < static_cast<uint32_t>(array->length())) {
9036 uint16_t value = array->get(index);
9037 return Smi::FromInt(value);
9038 }
9039 break;
9040 }
9041 case EXTERNAL_INT_ELEMENTS: {
9042 ExternalIntArray* array = ExternalIntArray::cast(elements());
9043 if (index < static_cast<uint32_t>(array->length())) {
9044 int32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01009045 return GetHeap()->NumberFromInt32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00009046 }
9047 break;
9048 }
9049 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9050 ExternalUnsignedIntArray* array =
9051 ExternalUnsignedIntArray::cast(elements());
9052 if (index < static_cast<uint32_t>(array->length())) {
9053 uint32_t value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01009054 return GetHeap()->NumberFromUint32(value);
Steve Block3ce2e202009-11-05 08:53:23 +00009055 }
9056 break;
9057 }
9058 case EXTERNAL_FLOAT_ELEMENTS: {
9059 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
9060 if (index < static_cast<uint32_t>(array->length())) {
9061 float value = array->get(index);
Steve Block44f0eee2011-05-26 01:26:41 +01009062 return GetHeap()->AllocateHeapNumber(value);
Steve Block3ce2e202009-11-05 08:53:23 +00009063 }
9064 break;
9065 }
Ben Murdoch257744e2011-11-30 15:57:28 +00009066 case EXTERNAL_DOUBLE_ELEMENTS: {
9067 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
9068 if (index < static_cast<uint32_t>(array->length())) {
9069 double value = array->get(index);
9070 return GetHeap()->AllocateHeapNumber(value);
9071 }
9072 break;
9073 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009074 case FAST_DOUBLE_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01009075 case FAST_ELEMENTS:
9076 case DICTIONARY_ELEMENTS:
9077 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00009078 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009079 case NON_STRICT_ARGUMENTS_ELEMENTS:
9080 UNIMPLEMENTED();
9081 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00009082 }
Steve Block44f0eee2011-05-26 01:26:41 +01009083 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009084}
9085
9086
9087bool JSObject::HasDenseElements() {
9088 int capacity = 0;
9089 int number_of_elements = 0;
9090
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009091 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
9092 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00009093 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009094 case NON_STRICT_ARGUMENTS_ELEMENTS:
9095 backing_store_base =
9096 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
9097 backing_store = FixedArray::cast(backing_store_base);
9098 if (backing_store->IsDictionary()) {
9099 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
9100 capacity = dictionary->Capacity();
9101 number_of_elements = dictionary->NumberOfElements();
9102 break;
9103 }
9104 // Fall through.
9105 case FAST_ELEMENTS:
9106 backing_store = FixedArray::cast(backing_store_base);
9107 capacity = backing_store->length();
9108 for (int i = 0; i < capacity; ++i) {
9109 if (!backing_store->get(i)->IsTheHole()) ++number_of_elements;
9110 }
9111 break;
9112 case DICTIONARY_ELEMENTS: {
9113 NumberDictionary* dictionary =
9114 NumberDictionary::cast(FixedArray::cast(elements()));
9115 capacity = dictionary->Capacity();
9116 number_of_elements = dictionary->NumberOfElements();
9117 break;
9118 }
9119 case FAST_DOUBLE_ELEMENTS: {
9120 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009121 capacity = elms->length();
9122 for (int i = 0; i < capacity; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009123 if (!elms->is_the_hole(i)) number_of_elements++;
Steve Blocka7e24c12009-10-30 11:49:00 +00009124 }
9125 break;
9126 }
Steve Block44f0eee2011-05-26 01:26:41 +01009127 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00009128 case EXTERNAL_BYTE_ELEMENTS:
9129 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9130 case EXTERNAL_SHORT_ELEMENTS:
9131 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9132 case EXTERNAL_INT_ELEMENTS:
9133 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009134 case EXTERNAL_FLOAT_ELEMENTS:
9135 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Blocka7e24c12009-10-30 11:49:00 +00009136 return true;
9137 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009138 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009139 return (capacity == 0) || (number_of_elements > (capacity / 2));
Steve Blocka7e24c12009-10-30 11:49:00 +00009140}
9141
9142
9143bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009144 // Keep the array in fast case if the current backing storage is
9145 // almost filled and if the new capacity is no more than twice the
9146 // old capacity.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009147 int elements_length = 0;
9148 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
9149 FixedArray* backing_store = FixedArray::cast(elements());
9150 elements_length = FixedArray::cast(backing_store->get(1))->length();
9151 } else if (HasFastElements()) {
9152 elements_length = FixedArray::cast(elements())->length();
9153 } else if (HasFastDoubleElements()) {
9154 elements_length = FixedDoubleArray::cast(elements())->length();
9155 } else {
9156 UNREACHABLE();
9157 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009158 return !HasDenseElements() || ((new_capacity / 2) > elements_length);
9159}
9160
9161
9162bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009163 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009164 // If the elements are sparse, we should not go back to fast case.
9165 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009166 // An object requiring access checks is never allowed to have fast
9167 // elements. If it had fast elements we would skip security checks.
9168 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009169
9170 FixedArray* elements = FixedArray::cast(this->elements());
9171 NumberDictionary* dictionary = NULL;
9172 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
9173 dictionary = NumberDictionary::cast(elements->get(1));
9174 } else {
9175 dictionary = NumberDictionary::cast(elements);
9176 }
9177 // If an element has been added at a very high index in the elements
9178 // dictionary, we cannot go back to fast case.
9179 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009180 // If the dictionary backing storage takes up roughly half as much
9181 // space as a fast-case backing storage would the array should have
9182 // fast elements.
9183 uint32_t length = 0;
9184 if (IsJSArray()) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01009185 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
Steve Blocka7e24c12009-10-30 11:49:00 +00009186 } else {
9187 length = dictionary->max_number_key();
9188 }
9189 return static_cast<uint32_t>(dictionary->Capacity()) >=
9190 (length / (2 * NumberDictionary::kEntrySize));
9191}
9192
9193
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009194bool JSObject::ShouldConvertToFastDoubleElements() {
9195 if (FLAG_unbox_double_arrays) {
9196 ASSERT(HasDictionaryElements());
9197 NumberDictionary* dictionary = NumberDictionary::cast(elements());
9198 for (int i = 0; i < dictionary->Capacity(); i++) {
9199 Object* key = dictionary->KeyAt(i);
9200 if (key->IsNumber()) {
9201 if (!dictionary->ValueAt(i)->IsNumber()) return false;
9202 }
9203 }
9204 return true;
9205 } else {
9206 return false;
9207 }
9208}
9209
9210
Steve Blocka7e24c12009-10-30 11:49:00 +00009211// Certain compilers request function template instantiation when they
9212// see the definition of the other template functions in the
9213// class. This requires us to have the template functions put
9214// together, so even though this function belongs in objects-debug.cc,
9215// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01009216#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00009217template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01009218void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009219 int capacity = HashTable<Shape, Key>::Capacity();
9220 for (int i = 0; i < capacity; i++) {
9221 Object* k = HashTable<Shape, Key>::KeyAt(i);
9222 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009223 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00009224 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009225 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00009226 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01009227 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00009228 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01009229 PrintF(out, ": ");
9230 ValueAt(i)->ShortPrint(out);
9231 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00009232 }
9233 }
9234}
9235#endif
9236
9237
9238template<typename Shape, typename Key>
9239void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
9240 int pos = 0;
9241 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00009242 AssertNoAllocation no_gc;
9243 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00009244 for (int i = 0; i < capacity; i++) {
9245 Object* k = Dictionary<Shape, Key>::KeyAt(i);
9246 if (Dictionary<Shape, Key>::IsKey(k)) {
9247 elements->set(pos++, ValueAt(i), mode);
9248 }
9249 }
9250 ASSERT(pos == elements->length());
9251}
9252
9253
9254InterceptorInfo* JSObject::GetNamedInterceptor() {
9255 ASSERT(map()->has_named_interceptor());
9256 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01009257 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00009258 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01009259 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00009260 return InterceptorInfo::cast(result);
9261}
9262
9263
9264InterceptorInfo* JSObject::GetIndexedInterceptor() {
9265 ASSERT(map()->has_indexed_interceptor());
9266 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01009267 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00009268 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01009269 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00009270 return InterceptorInfo::cast(result);
9271}
9272
9273
John Reck59135872010-11-02 12:39:01 -07009274MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009275 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -07009276 String* name,
9277 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009278 // Check local property in holder, ignore interceptor.
9279 LookupResult result;
9280 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009281 if (result.IsProperty()) {
9282 return GetProperty(receiver, &result, name, attributes);
9283 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009284 // Continue searching via the prototype chain.
9285 Object* pt = GetPrototype();
9286 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01009287 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009288 return pt->GetPropertyWithReceiver(receiver, name, attributes);
9289}
9290
9291
John Reck59135872010-11-02 12:39:01 -07009292MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009293 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +00009294 String* name,
9295 PropertyAttributes* attributes) {
9296 // Check local property in holder, ignore interceptor.
9297 LookupResult result;
9298 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009299 if (result.IsProperty()) {
9300 return GetProperty(receiver, &result, name, attributes);
9301 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01009302 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00009303}
9304
9305
John Reck59135872010-11-02 12:39:01 -07009306MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009307 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00009308 String* name,
9309 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01009310 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00009311 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01009312 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009313 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00009314 Handle<JSObject> holder_handle(this);
9315 Handle<String> name_handle(name);
9316
9317 if (!interceptor->getter()->IsUndefined()) {
9318 v8::NamedPropertyGetter getter =
9319 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01009320 LOG(isolate,
9321 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
9322 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00009323 v8::AccessorInfo info(args.end());
9324 v8::Handle<v8::Value> result;
9325 {
9326 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01009327 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00009328 result = getter(v8::Utils::ToLocal(name_handle), info);
9329 }
Steve Block44f0eee2011-05-26 01:26:41 +01009330 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009331 if (!result.IsEmpty()) {
9332 *attributes = NONE;
9333 return *v8::Utils::OpenHandle(*result);
9334 }
9335 }
9336
John Reck59135872010-11-02 12:39:01 -07009337 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00009338 *receiver_handle,
9339 *name_handle,
9340 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01009341 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00009342 return result;
9343}
9344
9345
9346bool JSObject::HasRealNamedProperty(String* key) {
9347 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009348 if (IsAccessCheckNeeded()) {
9349 Heap* heap = GetHeap();
9350 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9351 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9352 return false;
9353 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009354 }
9355
9356 LookupResult result;
9357 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009358 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00009359}
9360
9361
9362bool JSObject::HasRealElementProperty(uint32_t index) {
9363 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009364 if (IsAccessCheckNeeded()) {
9365 Heap* heap = GetHeap();
9366 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9367 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9368 return false;
9369 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009370 }
9371
9372 // Handle [] on String objects.
9373 if (this->IsStringObjectWithCharacterAt(index)) return true;
9374
9375 switch (GetElementsKind()) {
9376 case FAST_ELEMENTS: {
9377 uint32_t length = IsJSArray() ?
9378 static_cast<uint32_t>(
9379 Smi::cast(JSArray::cast(this)->length())->value()) :
9380 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9381 return (index < length) &&
9382 !FixedArray::cast(elements())->get(index)->IsTheHole();
9383 }
Steve Block44f0eee2011-05-26 01:26:41 +01009384 case EXTERNAL_PIXEL_ELEMENTS: {
9385 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009386 return index < static_cast<uint32_t>(pixels->length());
9387 }
Steve Block3ce2e202009-11-05 08:53:23 +00009388 case EXTERNAL_BYTE_ELEMENTS:
9389 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9390 case EXTERNAL_SHORT_ELEMENTS:
9391 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9392 case EXTERNAL_INT_ELEMENTS:
9393 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009394 case EXTERNAL_FLOAT_ELEMENTS:
9395 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009396 ExternalArray* array = ExternalArray::cast(elements());
9397 return index < static_cast<uint32_t>(array->length());
9398 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009399 case FAST_DOUBLE_ELEMENTS:
9400 UNREACHABLE();
9401 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00009402 case DICTIONARY_ELEMENTS: {
9403 return element_dictionary()->FindEntry(index)
9404 != NumberDictionary::kNotFound;
9405 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009406 case NON_STRICT_ARGUMENTS_ELEMENTS:
9407 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00009408 break;
9409 }
9410 // All possibilities have been handled above already.
9411 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009412 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009413}
9414
9415
9416bool JSObject::HasRealNamedCallbackProperty(String* key) {
9417 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009418 if (IsAccessCheckNeeded()) {
9419 Heap* heap = GetHeap();
9420 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9421 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9422 return false;
9423 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009424 }
9425
9426 LookupResult result;
9427 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009428 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00009429}
9430
9431
9432int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
9433 if (HasFastProperties()) {
9434 DescriptorArray* descs = map()->instance_descriptors();
9435 int result = 0;
9436 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009437 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009438 if (details.IsProperty() && (details.attributes() & filter) == 0) {
9439 result++;
9440 }
9441 }
9442 return result;
9443 } else {
9444 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9445 }
9446}
9447
9448
9449int JSObject::NumberOfEnumProperties() {
9450 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
9451}
9452
9453
9454void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
9455 Object* temp = get(i);
9456 set(i, get(j));
9457 set(j, temp);
9458 if (this != numbers) {
9459 temp = numbers->get(i);
9460 numbers->set(i, numbers->get(j));
9461 numbers->set(j, temp);
9462 }
9463}
9464
9465
9466static void InsertionSortPairs(FixedArray* content,
9467 FixedArray* numbers,
9468 int len) {
9469 for (int i = 1; i < len; i++) {
9470 int j = i;
9471 while (j > 0 &&
9472 (NumberToUint32(numbers->get(j - 1)) >
9473 NumberToUint32(numbers->get(j)))) {
9474 content->SwapPairs(numbers, j - 1, j);
9475 j--;
9476 }
9477 }
9478}
9479
9480
9481void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
9482 // In-place heap sort.
9483 ASSERT(content->length() == numbers->length());
9484
9485 // Bottom-up max-heap construction.
9486 for (int i = 1; i < len; ++i) {
9487 int child_index = i;
9488 while (child_index > 0) {
9489 int parent_index = ((child_index + 1) >> 1) - 1;
9490 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9491 uint32_t child_value = NumberToUint32(numbers->get(child_index));
9492 if (parent_value < child_value) {
9493 content->SwapPairs(numbers, parent_index, child_index);
9494 } else {
9495 break;
9496 }
9497 child_index = parent_index;
9498 }
9499 }
9500
9501 // Extract elements and create sorted array.
9502 for (int i = len - 1; i > 0; --i) {
9503 // Put max element at the back of the array.
9504 content->SwapPairs(numbers, 0, i);
9505 // Sift down the new top element.
9506 int parent_index = 0;
9507 while (true) {
9508 int child_index = ((parent_index + 1) << 1) - 1;
9509 if (child_index >= i) break;
9510 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
9511 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
9512 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9513 if (child_index + 1 >= i || child1_value > child2_value) {
9514 if (parent_value > child1_value) break;
9515 content->SwapPairs(numbers, parent_index, child_index);
9516 parent_index = child_index;
9517 } else {
9518 if (parent_value > child2_value) break;
9519 content->SwapPairs(numbers, parent_index, child_index + 1);
9520 parent_index = child_index + 1;
9521 }
9522 }
9523 }
9524}
9525
9526
9527// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9528void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9529 ASSERT(this->length() == numbers->length());
9530 // For small arrays, simply use insertion sort.
9531 if (len <= 10) {
9532 InsertionSortPairs(this, numbers, len);
9533 return;
9534 }
9535 // Check the range of indices.
9536 uint32_t min_index = NumberToUint32(numbers->get(0));
9537 uint32_t max_index = min_index;
9538 uint32_t i;
9539 for (i = 1; i < len; i++) {
9540 if (NumberToUint32(numbers->get(i)) < min_index) {
9541 min_index = NumberToUint32(numbers->get(i));
9542 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9543 max_index = NumberToUint32(numbers->get(i));
9544 }
9545 }
9546 if (max_index - min_index + 1 == len) {
9547 // Indices form a contiguous range, unless there are duplicates.
9548 // Do an in-place linear time sort assuming distinct numbers, but
9549 // avoid hanging in case they are not.
9550 for (i = 0; i < len; i++) {
9551 uint32_t p;
9552 uint32_t j = 0;
9553 // While the current element at i is not at its correct position p,
9554 // swap the elements at these two positions.
9555 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
9556 j++ < len) {
9557 SwapPairs(numbers, i, p);
9558 }
9559 }
9560 } else {
9561 HeapSortPairs(this, numbers, len);
9562 return;
9563 }
9564}
9565
9566
9567// Fill in the names of local properties into the supplied storage. The main
9568// purpose of this function is to provide reflection information for the object
9569// mirrors.
9570void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
9571 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
9572 if (HasFastProperties()) {
9573 DescriptorArray* descs = map()->instance_descriptors();
9574 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9575 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
9576 }
9577 ASSERT(storage->length() >= index);
9578 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009579 property_dictionary()->CopyKeysTo(storage,
9580 index,
9581 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009582 }
9583}
9584
9585
9586int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9587 return GetLocalElementKeys(NULL, filter);
9588}
9589
9590
9591int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00009592 // Fast case for objects with no elements.
9593 if (!IsJSValue() && HasFastElements()) {
9594 uint32_t length = IsJSArray() ?
9595 static_cast<uint32_t>(
9596 Smi::cast(JSArray::cast(this)->length())->value()) :
9597 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9598 if (length == 0) return 0;
9599 }
9600 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00009601 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9602}
9603
9604
9605int JSObject::GetLocalElementKeys(FixedArray* storage,
9606 PropertyAttributes filter) {
9607 int counter = 0;
9608 switch (GetElementsKind()) {
9609 case FAST_ELEMENTS: {
9610 int length = IsJSArray() ?
9611 Smi::cast(JSArray::cast(this)->length())->value() :
9612 FixedArray::cast(elements())->length();
9613 for (int i = 0; i < length; i++) {
9614 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9615 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009616 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009617 }
9618 counter++;
9619 }
9620 }
9621 ASSERT(!storage || storage->length() >= counter);
9622 break;
9623 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009624 case FAST_DOUBLE_ELEMENTS: {
9625 int length = IsJSArray() ?
9626 Smi::cast(JSArray::cast(this)->length())->value() :
9627 FixedDoubleArray::cast(elements())->length();
9628 for (int i = 0; i < length; i++) {
9629 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
9630 if (storage != NULL) {
9631 storage->set(counter, Smi::FromInt(i));
9632 }
9633 counter++;
9634 }
9635 }
9636 ASSERT(!storage || storage->length() >= counter);
9637 break;
9638 }
Steve Block44f0eee2011-05-26 01:26:41 +01009639 case EXTERNAL_PIXEL_ELEMENTS: {
9640 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00009641 while (counter < length) {
9642 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009643 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00009644 }
9645 counter++;
9646 }
9647 ASSERT(!storage || storage->length() >= counter);
9648 break;
9649 }
Steve Block3ce2e202009-11-05 08:53:23 +00009650 case EXTERNAL_BYTE_ELEMENTS:
9651 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9652 case EXTERNAL_SHORT_ELEMENTS:
9653 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9654 case EXTERNAL_INT_ELEMENTS:
9655 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009656 case EXTERNAL_FLOAT_ELEMENTS:
9657 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009658 int length = ExternalArray::cast(elements())->length();
9659 while (counter < length) {
9660 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009661 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00009662 }
9663 counter++;
9664 }
9665 ASSERT(!storage || storage->length() >= counter);
9666 break;
9667 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009668 case DICTIONARY_ELEMENTS: {
9669 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009670 element_dictionary()->CopyKeysTo(storage,
9671 filter,
9672 NumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009673 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009674 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +00009675 break;
9676 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009677 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9678 FixedArray* parameter_map = FixedArray::cast(elements());
9679 int mapped_length = parameter_map->length() - 2;
9680 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9681 if (arguments->IsDictionary()) {
9682 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
9683 // will insert in storage starting at index 0.
9684 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
9685 if (storage != NULL) {
9686 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
9687 }
9688 counter += dictionary->NumberOfElementsFilterAttributes(filter);
9689 for (int i = 0; i < mapped_length; ++i) {
9690 if (!parameter_map->get(i + 2)->IsTheHole()) {
9691 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9692 ++counter;
9693 }
9694 }
9695 if (storage != NULL) storage->SortPairs(storage, counter);
9696
9697 } else {
9698 int backing_length = arguments->length();
9699 int i = 0;
9700 for (; i < mapped_length; ++i) {
9701 if (!parameter_map->get(i + 2)->IsTheHole()) {
9702 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9703 ++counter;
9704 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
9705 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9706 ++counter;
9707 }
9708 }
9709 for (; i < backing_length; ++i) {
9710 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9711 ++counter;
9712 }
9713 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009714 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009715 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009716 }
9717
9718 if (this->IsJSValue()) {
9719 Object* val = JSValue::cast(this)->value();
9720 if (val->IsString()) {
9721 String* str = String::cast(val);
9722 if (storage) {
9723 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009724 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009725 }
9726 }
9727 counter += str->length();
9728 }
9729 }
9730 ASSERT(!storage || storage->length() == counter);
9731 return counter;
9732}
9733
9734
9735int JSObject::GetEnumElementKeys(FixedArray* storage) {
9736 return GetLocalElementKeys(storage,
9737 static_cast<PropertyAttributes>(DONT_ENUM));
9738}
9739
9740
Steve Blocka7e24c12009-10-30 11:49:00 +00009741// StringKey simply carries a string object as key.
9742class StringKey : public HashTableKey {
9743 public:
9744 explicit StringKey(String* string) :
9745 string_(string),
9746 hash_(HashForObject(string)) { }
9747
9748 bool IsMatch(Object* string) {
9749 // We know that all entries in a hash table had their hash keys created.
9750 // Use that knowledge to have fast failure.
9751 if (hash_ != HashForObject(string)) {
9752 return false;
9753 }
9754 return string_->Equals(String::cast(string));
9755 }
9756
9757 uint32_t Hash() { return hash_; }
9758
9759 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
9760
9761 Object* AsObject() { return string_; }
9762
9763 String* string_;
9764 uint32_t hash_;
9765};
9766
9767
9768// StringSharedKeys are used as keys in the eval cache.
9769class StringSharedKey : public HashTableKey {
9770 public:
Steve Block1e0659c2011-05-24 12:43:12 +01009771 StringSharedKey(String* source,
9772 SharedFunctionInfo* shared,
9773 StrictModeFlag strict_mode)
9774 : source_(source),
9775 shared_(shared),
9776 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009777
9778 bool IsMatch(Object* other) {
9779 if (!other->IsFixedArray()) return false;
9780 FixedArray* pair = FixedArray::cast(other);
9781 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9782 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01009783 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9784 Smi::cast(pair->get(2))->value());
9785 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009786 String* source = String::cast(pair->get(1));
9787 return source->Equals(source_);
9788 }
9789
9790 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01009791 SharedFunctionInfo* shared,
9792 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009793 uint32_t hash = source->Hash();
9794 if (shared->HasSourceCode()) {
9795 // Instead of using the SharedFunctionInfo pointer in the hash
9796 // code computation, we use a combination of the hash of the
9797 // script source code and the start and end positions. We do
9798 // this to ensure that the cache entries can survive garbage
9799 // collection.
9800 Script* script = Script::cast(shared->script());
9801 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01009802 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00009803 hash += shared->start_position();
9804 }
9805 return hash;
9806 }
9807
9808 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01009809 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009810 }
9811
9812 uint32_t HashForObject(Object* obj) {
9813 FixedArray* pair = FixedArray::cast(obj);
9814 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9815 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01009816 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9817 Smi::cast(pair->get(2))->value());
9818 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009819 }
9820
John Reck59135872010-11-02 12:39:01 -07009821 MUST_USE_RESULT MaybeObject* AsObject() {
9822 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009823 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07009824 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9825 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009826 FixedArray* pair = FixedArray::cast(obj);
9827 pair->set(0, shared_);
9828 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01009829 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00009830 return pair;
9831 }
9832
9833 private:
9834 String* source_;
9835 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01009836 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009837};
9838
9839
9840// RegExpKey carries the source and flags of a regular expression as key.
9841class RegExpKey : public HashTableKey {
9842 public:
9843 RegExpKey(String* string, JSRegExp::Flags flags)
9844 : string_(string),
9845 flags_(Smi::FromInt(flags.value())) { }
9846
Steve Block3ce2e202009-11-05 08:53:23 +00009847 // Rather than storing the key in the hash table, a pointer to the
9848 // stored value is stored where the key should be. IsMatch then
9849 // compares the search key to the found object, rather than comparing
9850 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00009851 bool IsMatch(Object* obj) {
9852 FixedArray* val = FixedArray::cast(obj);
9853 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9854 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9855 }
9856
9857 uint32_t Hash() { return RegExpHash(string_, flags_); }
9858
9859 Object* AsObject() {
9860 // Plain hash maps, which is where regexp keys are used, don't
9861 // use this function.
9862 UNREACHABLE();
9863 return NULL;
9864 }
9865
9866 uint32_t HashForObject(Object* obj) {
9867 FixedArray* val = FixedArray::cast(obj);
9868 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9869 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9870 }
9871
9872 static uint32_t RegExpHash(String* string, Smi* flags) {
9873 return string->Hash() + flags->value();
9874 }
9875
9876 String* string_;
9877 Smi* flags_;
9878};
9879
9880// Utf8SymbolKey carries a vector of chars as key.
9881class Utf8SymbolKey : public HashTableKey {
9882 public:
9883 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00009884 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009885
9886 bool IsMatch(Object* string) {
9887 return String::cast(string)->IsEqualTo(string_);
9888 }
9889
9890 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00009891 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009892 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9893 static_cast<unsigned>(string_.length()));
9894 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00009895 hash_field_ = String::ComputeHashField(&buffer, chars_);
9896 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009897 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9898 return result;
9899 }
9900
9901 uint32_t HashForObject(Object* other) {
9902 return String::cast(other)->Hash();
9903 }
9904
John Reck59135872010-11-02 12:39:01 -07009905 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00009906 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009907 return Isolate::Current()->heap()->AllocateSymbol(
9908 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009909 }
9910
9911 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00009912 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009913 int chars_; // Caches the number of characters when computing the hash code.
9914};
9915
9916
Steve Block9fac8402011-05-12 15:51:54 +01009917template <typename Char>
9918class SequentialSymbolKey : public HashTableKey {
9919 public:
9920 explicit SequentialSymbolKey(Vector<const Char> string)
9921 : string_(string), hash_field_(0) { }
9922
9923 uint32_t Hash() {
9924 StringHasher hasher(string_.length());
9925
9926 // Very long strings have a trivial hash that doesn't inspect the
9927 // string contents.
9928 if (hasher.has_trivial_hash()) {
9929 hash_field_ = hasher.GetHashField();
9930 } else {
9931 int i = 0;
9932 // Do the iterative array index computation as long as there is a
9933 // chance this is an array index.
9934 while (i < string_.length() && hasher.is_array_index()) {
9935 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9936 i++;
9937 }
9938
9939 // Process the remaining characters without updating the array
9940 // index.
9941 while (i < string_.length()) {
9942 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9943 i++;
9944 }
9945 hash_field_ = hasher.GetHashField();
9946 }
9947
9948 uint32_t result = hash_field_ >> String::kHashShift;
9949 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9950 return result;
9951 }
9952
9953
9954 uint32_t HashForObject(Object* other) {
9955 return String::cast(other)->Hash();
9956 }
9957
9958 Vector<const Char> string_;
9959 uint32_t hash_field_;
9960};
9961
9962
9963
9964class AsciiSymbolKey : public SequentialSymbolKey<char> {
9965 public:
9966 explicit AsciiSymbolKey(Vector<const char> str)
9967 : SequentialSymbolKey<char>(str) { }
9968
9969 bool IsMatch(Object* string) {
9970 return String::cast(string)->IsAsciiEqualTo(string_);
9971 }
9972
9973 MaybeObject* AsObject() {
9974 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009975 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009976 }
9977};
9978
9979
Ben Murdoch257744e2011-11-30 15:57:28 +00009980class SubStringAsciiSymbolKey : public HashTableKey {
9981 public:
9982 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9983 int from,
9984 int length)
9985 : string_(string), from_(from), length_(length) { }
9986
9987 uint32_t Hash() {
9988 ASSERT(length_ >= 0);
9989 ASSERT(from_ + length_ <= string_->length());
9990 StringHasher hasher(length_);
9991
9992 // Very long strings have a trivial hash that doesn't inspect the
9993 // string contents.
9994 if (hasher.has_trivial_hash()) {
9995 hash_field_ = hasher.GetHashField();
9996 } else {
9997 int i = 0;
9998 // Do the iterative array index computation as long as there is a
9999 // chance this is an array index.
10000 while (i < length_ && hasher.is_array_index()) {
10001 hasher.AddCharacter(static_cast<uc32>(
10002 string_->SeqAsciiStringGet(i + from_)));
10003 i++;
10004 }
10005
10006 // Process the remaining characters without updating the array
10007 // index.
10008 while (i < length_) {
10009 hasher.AddCharacterNoIndex(static_cast<uc32>(
10010 string_->SeqAsciiStringGet(i + from_)));
10011 i++;
10012 }
10013 hash_field_ = hasher.GetHashField();
10014 }
10015
10016 uint32_t result = hash_field_ >> String::kHashShift;
10017 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
10018 return result;
10019 }
10020
10021
10022 uint32_t HashForObject(Object* other) {
10023 return String::cast(other)->Hash();
10024 }
10025
10026 bool IsMatch(Object* string) {
10027 Vector<const char> chars(string_->GetChars() + from_, length_);
10028 return String::cast(string)->IsAsciiEqualTo(chars);
10029 }
10030
10031 MaybeObject* AsObject() {
10032 if (hash_field_ == 0) Hash();
10033 Vector<const char> chars(string_->GetChars() + from_, length_);
10034 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
10035 }
10036
10037 private:
10038 Handle<SeqAsciiString> string_;
10039 int from_;
10040 int length_;
10041 uint32_t hash_field_;
10042};
10043
10044
Steve Block9fac8402011-05-12 15:51:54 +010010045class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
10046 public:
10047 explicit TwoByteSymbolKey(Vector<const uc16> str)
10048 : SequentialSymbolKey<uc16>(str) { }
10049
10050 bool IsMatch(Object* string) {
10051 return String::cast(string)->IsTwoByteEqualTo(string_);
10052 }
10053
10054 MaybeObject* AsObject() {
10055 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +010010056 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +010010057 }
10058};
10059
10060
Steve Blocka7e24c12009-10-30 11:49:00 +000010061// SymbolKey carries a string/symbol object as key.
10062class SymbolKey : public HashTableKey {
10063 public:
Steve Block44f0eee2011-05-26 01:26:41 +010010064 explicit SymbolKey(String* string)
10065 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +000010066
10067 bool IsMatch(Object* string) {
10068 return String::cast(string)->Equals(string_);
10069 }
10070
10071 uint32_t Hash() { return string_->Hash(); }
10072
10073 uint32_t HashForObject(Object* other) {
10074 return String::cast(other)->Hash();
10075 }
10076
John Reck59135872010-11-02 12:39:01 -070010077 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +010010078 // Attempt to flatten the string, so that symbols will most often
10079 // be flat strings.
10080 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +010010081 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010082 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +010010083 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +000010084 if (map != NULL) {
10085 string_->set_map(map);
10086 ASSERT(string_->IsSymbol());
10087 return string_;
10088 }
10089 // Otherwise allocate a new symbol.
10090 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +010010091 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +000010092 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +000010093 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +000010094 }
10095
10096 static uint32_t StringHash(Object* obj) {
10097 return String::cast(obj)->Hash();
10098 }
10099
10100 String* string_;
10101};
10102
10103
10104template<typename Shape, typename Key>
10105void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
10106 IteratePointers(v, 0, kElementsStartOffset);
10107}
10108
10109
10110template<typename Shape, typename Key>
10111void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
10112 IteratePointers(v,
10113 kElementsStartOffset,
10114 kHeaderSize + length() * kPointerSize);
10115}
10116
10117
10118template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010119MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
10120 PretenureFlag pretenure) {
Steve Block6ded16b2010-05-10 14:33:55 +010010121 const int kMinCapacity = 32;
10122 int capacity = RoundUpToPowerOf2(at_least_space_for * 2);
10123 if (capacity < kMinCapacity) {
10124 capacity = kMinCapacity; // Guarantee min capacity.
Leon Clarkee46be812010-01-19 14:06:41 +000010125 } else if (capacity > HashTable::kMaxCapacity) {
10126 return Failure::OutOfMemoryException();
10127 }
10128
John Reck59135872010-11-02 12:39:01 -070010129 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010010130 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
10131 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -070010132 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010133 }
John Reck59135872010-11-02 12:39:01 -070010134 HashTable::cast(obj)->SetNumberOfElements(0);
10135 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
10136 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000010137 return obj;
10138}
10139
10140
Leon Clarkee46be812010-01-19 14:06:41 +000010141// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +010010142int StringDictionary::FindEntry(String* key) {
10143 if (!key->IsSymbol()) {
10144 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
10145 }
10146
10147 // Optimized for symbol key. Knowledge of the key type allows:
10148 // 1. Move the check if the key is a symbol out of the loop.
10149 // 2. Avoid comparing hash codes in symbol to symbol comparision.
10150 // 3. Detect a case when a dictionary key is not a symbol but the key is.
10151 // In case of positive result the dictionary key may be replaced by
10152 // the symbol with minimal performance penalty. It gives a chance to
10153 // perform further lookups in code stubs (and significant performance boost
10154 // a certain style of code).
10155
10156 // EnsureCapacity will guarantee the hash table is never full.
10157 uint32_t capacity = Capacity();
10158 uint32_t entry = FirstProbe(key->Hash(), capacity);
10159 uint32_t count = 1;
10160
10161 while (true) {
10162 int index = EntryToIndex(entry);
10163 Object* element = get(index);
10164 if (element->IsUndefined()) break; // Empty entry.
10165 if (key == element) return entry;
10166 if (!element->IsSymbol() &&
10167 !element->IsNull() &&
10168 String::cast(element)->Equals(key)) {
10169 // Replace a non-symbol key by the equivalent symbol for faster further
10170 // lookups.
10171 set(index, key);
10172 return entry;
10173 }
10174 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
10175 entry = NextProbe(entry, count++, capacity);
10176 }
10177 return kNotFound;
10178}
10179
10180
Steve Blocka7e24c12009-10-30 11:49:00 +000010181template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010182MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
10183 ASSERT(NumberOfElements() < new_table->Capacity());
10184
10185 AssertNoAllocation no_gc;
10186 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
10187
10188 // Copy prefix to new array.
10189 for (int i = kPrefixStartIndex;
10190 i < kPrefixStartIndex + Shape::kPrefixSize;
10191 i++) {
10192 new_table->set(i, get(i), mode);
10193 }
10194
10195 // Rehash the elements.
10196 int capacity = Capacity();
10197 for (int i = 0; i < capacity; i++) {
10198 uint32_t from_index = EntryToIndex(i);
10199 Object* k = get(from_index);
10200 if (IsKey(k)) {
10201 uint32_t hash = Shape::HashForObject(key, k);
10202 uint32_t insertion_index =
10203 EntryToIndex(new_table->FindInsertionEntry(hash));
10204 for (int j = 0; j < Shape::kEntrySize; j++) {
10205 new_table->set(insertion_index + j, get(from_index + j), mode);
10206 }
10207 }
10208 }
10209 new_table->SetNumberOfElements(NumberOfElements());
10210 new_table->SetNumberOfDeletedElements(0);
10211 return new_table;
10212}
10213
10214
10215template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010216MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010217 int capacity = Capacity();
10218 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +000010219 int nod = NumberOfDeletedElements();
10220 // Return if:
10221 // 50% is still free after adding n elements and
10222 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +010010223 if (nod <= (capacity - nof) >> 1) {
10224 int needed_free = nof >> 1;
10225 if (nof + needed_free <= capacity) return this;
10226 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010227
Steve Block6ded16b2010-05-10 14:33:55 +010010228 const int kMinCapacityForPretenure = 256;
10229 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +010010230 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -070010231 Object* obj;
10232 { MaybeObject* maybe_obj =
10233 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
10234 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10235 }
Leon Clarke4515c472010-02-03 11:58:03 +000010236
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010237 return Rehash(HashTable::cast(obj), key);
10238}
Steve Blocka7e24c12009-10-30 11:49:00 +000010239
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010240
10241template<typename Shape, typename Key>
10242MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
10243 int capacity = Capacity();
10244 int nof = NumberOfElements();
10245
10246 // Shrink to fit the number of elements if only a quarter of the
10247 // capacity is filled with elements.
10248 if (nof > (capacity >> 2)) return this;
10249 // Allocate a new dictionary with room for at least the current
10250 // number of elements. The allocation method will make sure that
10251 // there is extra room in the dictionary for additions. Don't go
10252 // lower than room for 16 elements.
10253 int at_least_room_for = nof;
10254 if (at_least_room_for < 16) return this;
10255
10256 const int kMinCapacityForPretenure = 256;
10257 bool pretenure =
10258 (at_least_room_for > kMinCapacityForPretenure) &&
10259 !GetHeap()->InNewSpace(this);
10260 Object* obj;
10261 { MaybeObject* maybe_obj =
10262 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
10263 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010264 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010265
10266 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010267}
10268
10269
10270template<typename Shape, typename Key>
10271uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
10272 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +000010273 uint32_t entry = FirstProbe(hash, capacity);
10274 uint32_t count = 1;
10275 // EnsureCapacity will guarantee the hash table is never full.
10276 while (true) {
10277 Object* element = KeyAt(entry);
10278 if (element->IsUndefined() || element->IsNull()) break;
10279 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +000010280 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010281 return entry;
10282}
10283
10284// Force instantiation of template instances class.
10285// Please note this list is compiler dependent.
10286
10287template class HashTable<SymbolTableShape, HashTableKey*>;
10288
10289template class HashTable<CompilationCacheShape, HashTableKey*>;
10290
10291template class HashTable<MapCacheShape, HashTableKey*>;
10292
10293template class Dictionary<StringDictionaryShape, String*>;
10294
10295template class Dictionary<NumberDictionaryShape, uint32_t>;
10296
John Reck59135872010-11-02 12:39:01 -070010297template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +000010298 int);
10299
John Reck59135872010-11-02 12:39:01 -070010300template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +000010301 int);
10302
John Reck59135872010-11-02 12:39:01 -070010303template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +000010304 uint32_t, Object*);
10305
10306template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
10307 Object*);
10308
10309template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
10310 Object*);
10311
10312template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010313 FixedArray*,
10314 PropertyAttributes,
10315 Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010316
10317template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
10318 int, JSObject::DeleteMode);
10319
10320template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
10321 int, JSObject::DeleteMode);
10322
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010323template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
10324 String*);
10325
10326template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
10327 uint32_t);
10328
Steve Blocka7e24c12009-10-30 11:49:00 +000010329template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010330 FixedArray*,
10331 int,
10332 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010333
10334template int
10335Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
10336 PropertyAttributes);
10337
John Reck59135872010-11-02 12:39:01 -070010338template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010339 String*, Object*, PropertyDetails);
10340
John Reck59135872010-11-02 12:39:01 -070010341template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000010342Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
10343
10344template int
10345Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
10346 PropertyAttributes);
10347
John Reck59135872010-11-02 12:39:01 -070010348template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010349 uint32_t, Object*, PropertyDetails);
10350
John Reck59135872010-11-02 12:39:01 -070010351template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
10352 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010353
John Reck59135872010-11-02 12:39:01 -070010354template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10355 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000010356
John Reck59135872010-11-02 12:39:01 -070010357template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010358 uint32_t, Object*, PropertyDetails, uint32_t);
10359
John Reck59135872010-11-02 12:39:01 -070010360template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010361 String*, Object*, PropertyDetails, uint32_t);
10362
10363template
10364int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
10365
10366template
10367int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
10368
Leon Clarkee46be812010-01-19 14:06:41 +000010369template
10370int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
10371
10372
Steve Blocka7e24c12009-10-30 11:49:00 +000010373// Collates undefined and unexisting elements below limit from position
10374// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070010375MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010376 ASSERT(HasDictionaryElements());
10377 // Must stay in dictionary mode, either because of requires_slow_elements,
10378 // or because we are not going to sort (and therefore compact) all of the
10379 // elements.
10380 NumberDictionary* dict = element_dictionary();
10381 HeapNumber* result_double = NULL;
10382 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10383 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070010384 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010385 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010386 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10387 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010388 result_double = HeapNumber::cast(new_double);
10389 }
10390
John Reck59135872010-11-02 12:39:01 -070010391 Object* obj;
10392 { MaybeObject* maybe_obj =
10393 NumberDictionary::Allocate(dict->NumberOfElements());
10394 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10395 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010396 NumberDictionary* new_dict = NumberDictionary::cast(obj);
10397
10398 AssertNoAllocation no_alloc;
10399
10400 uint32_t pos = 0;
10401 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010010402 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000010403 for (int i = 0; i < capacity; i++) {
10404 Object* k = dict->KeyAt(i);
10405 if (dict->IsKey(k)) {
10406 ASSERT(k->IsNumber());
10407 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10408 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10409 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10410 Object* value = dict->ValueAt(i);
10411 PropertyDetails details = dict->DetailsAt(i);
10412 if (details.type() == CALLBACKS) {
10413 // Bail out and do the sorting of undefineds and array holes in JS.
10414 return Smi::FromInt(-1);
10415 }
10416 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070010417 // In the following we assert that adding the entry to the new dictionary
10418 // does not cause GC. This is the case because we made sure to allocate
10419 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000010420 if (key < limit) {
10421 if (value->IsUndefined()) {
10422 undefs++;
10423 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010424 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10425 // Adding an entry with the key beyond smi-range requires
10426 // allocation. Bailout.
10427 return Smi::FromInt(-1);
10428 }
John Reck59135872010-11-02 12:39:01 -070010429 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010430 pos++;
10431 }
10432 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010433 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10434 // Adding an entry with the key beyond smi-range requires
10435 // allocation. Bailout.
10436 return Smi::FromInt(-1);
10437 }
John Reck59135872010-11-02 12:39:01 -070010438 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010439 }
10440 }
10441 }
10442
10443 uint32_t result = pos;
10444 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010445 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010446 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010010447 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10448 // Adding an entry with the key beyond smi-range requires
10449 // allocation. Bailout.
10450 return Smi::FromInt(-1);
10451 }
Steve Block44f0eee2011-05-26 01:26:41 +010010452 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070010453 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010454 pos++;
10455 undefs--;
10456 }
10457
10458 set_elements(new_dict);
10459
10460 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10461 return Smi::FromInt(static_cast<int>(result));
10462 }
10463
10464 ASSERT_NE(NULL, result_double);
10465 result_double->set_value(static_cast<double>(result));
10466 return result_double;
10467}
10468
10469
10470// Collects all defined (non-hole) and non-undefined (array) elements at
10471// the start of the elements array.
10472// If the object is in dictionary mode, it is converted to fast elements
10473// mode.
John Reck59135872010-11-02 12:39:01 -070010474MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010475 Heap* heap = GetHeap();
10476
Steve Blocka7e24c12009-10-30 11:49:00 +000010477 if (HasDictionaryElements()) {
10478 // Convert to fast elements containing only the existing properties.
10479 // Ordering is irrelevant, since we are going to sort anyway.
10480 NumberDictionary* dict = element_dictionary();
10481 if (IsJSArray() || dict->requires_slow_elements() ||
10482 dict->max_number_key() >= limit) {
10483 return PrepareSlowElementsForSort(limit);
10484 }
10485 // Convert to fast elements.
10486
John Reck59135872010-11-02 12:39:01 -070010487 Object* obj;
10488 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
10489 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10490 }
Steve Block8defd9f2010-07-08 12:39:36 +010010491 Map* new_map = Map::cast(obj);
10492
Steve Block44f0eee2011-05-26 01:26:41 +010010493 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070010494 Object* new_array;
10495 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010496 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070010497 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
10498 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010499 FixedArray* fast_elements = FixedArray::cast(new_array);
10500 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010010501
10502 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000010503 set_elements(fast_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010504 } else if (HasExternalArrayElements()) {
10505 // External arrays cannot have holes or undefined elements.
10506 return Smi::FromInt(ExternalArray::cast(elements())->length());
Iain Merrick75681382010-08-19 15:07:18 +010010507 } else {
John Reck59135872010-11-02 12:39:01 -070010508 Object* obj;
10509 { MaybeObject* maybe_obj = EnsureWritableFastElements();
10510 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10511 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010512 }
10513 ASSERT(HasFastElements());
10514
10515 // Collect holes at the end, undefined before that and the rest at the
10516 // start, and return the number of non-hole, non-undefined values.
10517
10518 FixedArray* elements = FixedArray::cast(this->elements());
10519 uint32_t elements_length = static_cast<uint32_t>(elements->length());
10520 if (limit > elements_length) {
10521 limit = elements_length ;
10522 }
10523 if (limit == 0) {
10524 return Smi::FromInt(0);
10525 }
10526
10527 HeapNumber* result_double = NULL;
10528 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10529 // Pessimistically allocate space for return value before
10530 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070010531 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010010532 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010533 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10534 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010535 result_double = HeapNumber::cast(new_double);
10536 }
10537
10538 AssertNoAllocation no_alloc;
10539
10540 // Split elements into defined, undefined and the_hole, in that order.
10541 // Only count locations for undefined and the hole, and fill them afterwards.
Leon Clarke4515c472010-02-03 11:58:03 +000010542 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
Steve Blocka7e24c12009-10-30 11:49:00 +000010543 unsigned int undefs = limit;
10544 unsigned int holes = limit;
10545 // Assume most arrays contain no holes and undefined values, so minimize the
10546 // number of stores of non-undefined, non-the-hole values.
10547 for (unsigned int i = 0; i < undefs; i++) {
10548 Object* current = elements->get(i);
10549 if (current->IsTheHole()) {
10550 holes--;
10551 undefs--;
10552 } else if (current->IsUndefined()) {
10553 undefs--;
10554 } else {
10555 continue;
10556 }
10557 // Position i needs to be filled.
10558 while (undefs > i) {
10559 current = elements->get(undefs);
10560 if (current->IsTheHole()) {
10561 holes--;
10562 undefs--;
10563 } else if (current->IsUndefined()) {
10564 undefs--;
10565 } else {
10566 elements->set(i, current, write_barrier);
10567 break;
10568 }
10569 }
10570 }
10571 uint32_t result = undefs;
10572 while (undefs < holes) {
10573 elements->set_undefined(undefs);
10574 undefs++;
10575 }
10576 while (holes < limit) {
10577 elements->set_the_hole(holes);
10578 holes++;
10579 }
10580
10581 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10582 return Smi::FromInt(static_cast<int>(result));
10583 }
10584 ASSERT_NE(NULL, result_double);
10585 result_double->set_value(static_cast<double>(result));
10586 return result_double;
10587}
10588
10589
Steve Block44f0eee2011-05-26 01:26:41 +010010590Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010591 uint8_t clamped_value = 0;
10592 if (index < static_cast<uint32_t>(length())) {
10593 if (value->IsSmi()) {
10594 int int_value = Smi::cast(value)->value();
10595 if (int_value < 0) {
10596 clamped_value = 0;
10597 } else if (int_value > 255) {
10598 clamped_value = 255;
10599 } else {
10600 clamped_value = static_cast<uint8_t>(int_value);
10601 }
10602 } else if (value->IsHeapNumber()) {
10603 double double_value = HeapNumber::cast(value)->value();
10604 if (!(double_value > 0)) {
10605 // NaN and less than zero clamp to zero.
10606 clamped_value = 0;
10607 } else if (double_value > 255) {
10608 // Greater than 255 clamp to 255.
10609 clamped_value = 255;
10610 } else {
10611 // Other doubles are rounded to the nearest integer.
10612 clamped_value = static_cast<uint8_t>(double_value + 0.5);
10613 }
10614 } else {
10615 // Clamp undefined to zero (default). All other types have been
10616 // converted to a number type further up in the call chain.
10617 ASSERT(value->IsUndefined());
10618 }
10619 set(index, clamped_value);
10620 }
10621 return Smi::FromInt(clamped_value);
10622}
10623
10624
Steve Block3ce2e202009-11-05 08:53:23 +000010625template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010010626static MaybeObject* ExternalArrayIntSetter(Heap* heap,
10627 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070010628 uint32_t index,
10629 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010630 ValueType cast_value = 0;
10631 if (index < static_cast<uint32_t>(receiver->length())) {
10632 if (value->IsSmi()) {
10633 int int_value = Smi::cast(value)->value();
10634 cast_value = static_cast<ValueType>(int_value);
10635 } else if (value->IsHeapNumber()) {
10636 double double_value = HeapNumber::cast(value)->value();
10637 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10638 } else {
10639 // Clamp undefined to zero (default). All other types have been
10640 // converted to a number type further up in the call chain.
10641 ASSERT(value->IsUndefined());
10642 }
10643 receiver->set(index, cast_value);
10644 }
Steve Block44f0eee2011-05-26 01:26:41 +010010645 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010646}
10647
10648
John Reck59135872010-11-02 12:39:01 -070010649MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010650 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010651 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010652}
10653
10654
John Reck59135872010-11-02 12:39:01 -070010655MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10656 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010657 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010658 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010659}
10660
10661
John Reck59135872010-11-02 12:39:01 -070010662MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10663 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010664 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010665 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010666}
10667
10668
John Reck59135872010-11-02 12:39:01 -070010669MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10670 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010671 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010672 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010673}
10674
10675
John Reck59135872010-11-02 12:39:01 -070010676MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010677 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010678 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010679}
10680
10681
John Reck59135872010-11-02 12:39:01 -070010682MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010683 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010684 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010685 if (index < static_cast<uint32_t>(length())) {
10686 if (value->IsSmi()) {
10687 int int_value = Smi::cast(value)->value();
10688 cast_value = static_cast<uint32_t>(int_value);
10689 } else if (value->IsHeapNumber()) {
10690 double double_value = HeapNumber::cast(value)->value();
10691 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10692 } else {
10693 // Clamp undefined to zero (default). All other types have been
10694 // converted to a number type further up in the call chain.
10695 ASSERT(value->IsUndefined());
10696 }
10697 set(index, cast_value);
10698 }
Steve Block44f0eee2011-05-26 01:26:41 +010010699 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010700}
10701
10702
John Reck59135872010-11-02 12:39:01 -070010703MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010704 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010705 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010706 if (index < static_cast<uint32_t>(length())) {
10707 if (value->IsSmi()) {
10708 int int_value = Smi::cast(value)->value();
10709 cast_value = static_cast<float>(int_value);
10710 } else if (value->IsHeapNumber()) {
10711 double double_value = HeapNumber::cast(value)->value();
10712 cast_value = static_cast<float>(double_value);
10713 } else {
10714 // Clamp undefined to zero (default). All other types have been
10715 // converted to a number type further up in the call chain.
10716 ASSERT(value->IsUndefined());
10717 }
10718 set(index, cast_value);
10719 }
Steve Block44f0eee2011-05-26 01:26:41 +010010720 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010721}
10722
10723
Ben Murdoch257744e2011-11-30 15:57:28 +000010724MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
10725 double double_value = 0;
10726 Heap* heap = GetHeap();
10727 if (index < static_cast<uint32_t>(length())) {
10728 if (value->IsSmi()) {
10729 int int_value = Smi::cast(value)->value();
10730 double_value = static_cast<double>(int_value);
10731 } else if (value->IsHeapNumber()) {
10732 double_value = HeapNumber::cast(value)->value();
10733 } else {
10734 // Clamp undefined to zero (default). All other types have been
10735 // converted to a number type further up in the call chain.
10736 ASSERT(value->IsUndefined());
10737 }
10738 set(index, double_value);
10739 }
10740 return heap->AllocateHeapNumber(double_value);
10741}
10742
10743
Ben Murdochb0fe1622011-05-05 13:52:32 +010010744JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010745 ASSERT(!HasFastProperties());
10746 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010747 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010748}
10749
10750
John Reck59135872010-11-02 12:39:01 -070010751MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010752 ASSERT(!HasFastProperties());
10753 int entry = property_dictionary()->FindEntry(name);
10754 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010755 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070010756 Object* cell;
10757 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010010758 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070010759 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10760 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010761 PropertyDetails details(NONE, NORMAL);
10762 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070010763 Object* dictionary;
10764 { MaybeObject* maybe_dictionary =
10765 property_dictionary()->Add(name, cell, details);
10766 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10767 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010768 set_properties(StringDictionary::cast(dictionary));
10769 return cell;
10770 } else {
10771 Object* value = property_dictionary()->ValueAt(entry);
10772 ASSERT(value->IsJSGlobalPropertyCell());
10773 return value;
10774 }
10775}
10776
10777
John Reck59135872010-11-02 12:39:01 -070010778MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010779 SymbolKey key(string);
10780 return LookupKey(&key, s);
10781}
10782
10783
Steve Blockd0582a62009-12-15 09:54:21 +000010784// This class is used for looking up two character strings in the symbol table.
10785// If we don't have a hit we don't want to waste much time so we unroll the
10786// string hash calculation loop here for speed. Doesn't work if the two
10787// characters form a decimal integer, since such strings have a different hash
10788// algorithm.
10789class TwoCharHashTableKey : public HashTableKey {
10790 public:
10791 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
10792 : c1_(c1), c2_(c2) {
10793 // Char 1.
10794 uint32_t hash = c1 + (c1 << 10);
10795 hash ^= hash >> 6;
10796 // Char 2.
10797 hash += c2;
10798 hash += hash << 10;
10799 hash ^= hash >> 6;
10800 // GetHash.
10801 hash += hash << 3;
10802 hash ^= hash >> 11;
10803 hash += hash << 15;
10804 if (hash == 0) hash = 27;
10805#ifdef DEBUG
10806 StringHasher hasher(2);
10807 hasher.AddCharacter(c1);
10808 hasher.AddCharacter(c2);
10809 // If this assert fails then we failed to reproduce the two-character
10810 // version of the string hashing algorithm above. One reason could be
10811 // that we were passed two digits as characters, since the hash
10812 // algorithm is different in that case.
10813 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10814#endif
10815 hash_ = hash;
10816 }
10817
10818 bool IsMatch(Object* o) {
10819 if (!o->IsString()) return false;
10820 String* other = String::cast(o);
10821 if (other->length() != 2) return false;
10822 if (other->Get(0) != c1_) return false;
10823 return other->Get(1) == c2_;
10824 }
10825
10826 uint32_t Hash() { return hash_; }
10827 uint32_t HashForObject(Object* key) {
10828 if (!key->IsString()) return 0;
10829 return String::cast(key)->Hash();
10830 }
10831
10832 Object* AsObject() {
10833 // The TwoCharHashTableKey is only used for looking in the symbol
10834 // table, not for adding to it.
10835 UNREACHABLE();
10836 return NULL;
10837 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010838
Steve Blockd0582a62009-12-15 09:54:21 +000010839 private:
10840 uint32_t c1_;
10841 uint32_t c2_;
10842 uint32_t hash_;
10843};
10844
10845
Steve Blocka7e24c12009-10-30 11:49:00 +000010846bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10847 SymbolKey key(string);
10848 int entry = FindEntry(&key);
10849 if (entry == kNotFound) {
10850 return false;
10851 } else {
10852 String* result = String::cast(KeyAt(entry));
10853 ASSERT(StringShape(result).IsSymbol());
10854 *symbol = result;
10855 return true;
10856 }
10857}
10858
10859
Steve Blockd0582a62009-12-15 09:54:21 +000010860bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10861 uint32_t c2,
10862 String** symbol) {
10863 TwoCharHashTableKey key(c1, c2);
10864 int entry = FindEntry(&key);
10865 if (entry == kNotFound) {
10866 return false;
10867 } else {
10868 String* result = String::cast(KeyAt(entry));
10869 ASSERT(StringShape(result).IsSymbol());
10870 *symbol = result;
10871 return true;
10872 }
10873}
10874
10875
John Reck59135872010-11-02 12:39:01 -070010876MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010877 Utf8SymbolKey key(str);
10878 return LookupKey(&key, s);
10879}
10880
10881
Steve Block9fac8402011-05-12 15:51:54 +010010882MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10883 Object** s) {
10884 AsciiSymbolKey key(str);
10885 return LookupKey(&key, s);
10886}
10887
10888
Ben Murdoch257744e2011-11-30 15:57:28 +000010889MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10890 int from,
10891 int length,
10892 Object** s) {
10893 SubStringAsciiSymbolKey key(str, from, length);
10894 return LookupKey(&key, s);
10895}
10896
10897
Steve Block9fac8402011-05-12 15:51:54 +010010898MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10899 Object** s) {
10900 TwoByteSymbolKey key(str);
10901 return LookupKey(&key, s);
10902}
10903
John Reck59135872010-11-02 12:39:01 -070010904MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010905 int entry = FindEntry(key);
10906
10907 // Symbol already in table.
10908 if (entry != kNotFound) {
10909 *s = KeyAt(entry);
10910 return this;
10911 }
10912
10913 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -070010914 Object* obj;
10915 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10916 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10917 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010918
10919 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070010920 Object* symbol;
10921 { MaybeObject* maybe_symbol = key->AsObject();
10922 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10923 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010924
10925 // If the symbol table grew as part of EnsureCapacity, obj is not
10926 // the current symbol table and therefore we cannot use
10927 // SymbolTable::cast here.
10928 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10929
10930 // Add the new symbol and return it along with the symbol table.
10931 entry = table->FindInsertionEntry(key->Hash());
10932 table->set(EntryToIndex(entry), symbol);
10933 table->ElementAdded();
10934 *s = symbol;
10935 return table;
10936}
10937
10938
10939Object* CompilationCacheTable::Lookup(String* src) {
10940 StringKey key(src);
10941 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010942 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010943 return get(EntryToIndex(entry) + 1);
10944}
10945
10946
Steve Block1e0659c2011-05-24 12:43:12 +010010947Object* CompilationCacheTable::LookupEval(String* src,
10948 Context* context,
10949 StrictModeFlag strict_mode) {
10950 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010951 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010010952 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010953 return get(EntryToIndex(entry) + 1);
10954}
10955
10956
10957Object* CompilationCacheTable::LookupRegExp(String* src,
10958 JSRegExp::Flags flags) {
10959 RegExpKey key(src, flags);
10960 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010961 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010962 return get(EntryToIndex(entry) + 1);
10963}
10964
10965
John Reck59135872010-11-02 12:39:01 -070010966MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010967 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070010968 Object* obj;
10969 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10970 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10971 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010972
10973 CompilationCacheTable* cache =
10974 reinterpret_cast<CompilationCacheTable*>(obj);
10975 int entry = cache->FindInsertionEntry(key.Hash());
10976 cache->set(EntryToIndex(entry), src);
10977 cache->set(EntryToIndex(entry) + 1, value);
10978 cache->ElementAdded();
10979 return cache;
10980}
10981
10982
John Reck59135872010-11-02 12:39:01 -070010983MaybeObject* CompilationCacheTable::PutEval(String* src,
10984 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +010010985 SharedFunctionInfo* value) {
10986 StringSharedKey key(src,
10987 context->closure()->shared(),
10988 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070010989 Object* obj;
10990 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10991 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10992 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010993
10994 CompilationCacheTable* cache =
10995 reinterpret_cast<CompilationCacheTable*>(obj);
10996 int entry = cache->FindInsertionEntry(key.Hash());
10997
John Reck59135872010-11-02 12:39:01 -070010998 Object* k;
10999 { MaybeObject* maybe_k = key.AsObject();
11000 if (!maybe_k->ToObject(&k)) return maybe_k;
11001 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011002
11003 cache->set(EntryToIndex(entry), k);
11004 cache->set(EntryToIndex(entry) + 1, value);
11005 cache->ElementAdded();
11006 return cache;
11007}
11008
11009
John Reck59135872010-11-02 12:39:01 -070011010MaybeObject* CompilationCacheTable::PutRegExp(String* src,
11011 JSRegExp::Flags flags,
11012 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011013 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070011014 Object* obj;
11015 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11016 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11017 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011018
11019 CompilationCacheTable* cache =
11020 reinterpret_cast<CompilationCacheTable*>(obj);
11021 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000011022 // We store the value in the key slot, and compare the search key
11023 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000011024 cache->set(EntryToIndex(entry), value);
11025 cache->set(EntryToIndex(entry) + 1, value);
11026 cache->ElementAdded();
11027 return cache;
11028}
11029
11030
Ben Murdochb0fe1622011-05-05 13:52:32 +010011031void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +010011032 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010011033 for (int entry = 0, size = Capacity(); entry < size; entry++) {
11034 int entry_index = EntryToIndex(entry);
11035 int value_index = entry_index + 1;
11036 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +010011037 fast_set(this, entry_index, null_value);
11038 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010011039 ElementRemoved();
11040 }
11041 }
11042 return;
11043}
11044
11045
Steve Blocka7e24c12009-10-30 11:49:00 +000011046// SymbolsKey used for HashTable where key is array of symbols.
11047class SymbolsKey : public HashTableKey {
11048 public:
11049 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
11050
11051 bool IsMatch(Object* symbols) {
11052 FixedArray* o = FixedArray::cast(symbols);
11053 int len = symbols_->length();
11054 if (o->length() != len) return false;
11055 for (int i = 0; i < len; i++) {
11056 if (o->get(i) != symbols_->get(i)) return false;
11057 }
11058 return true;
11059 }
11060
11061 uint32_t Hash() { return HashForObject(symbols_); }
11062
11063 uint32_t HashForObject(Object* obj) {
11064 FixedArray* symbols = FixedArray::cast(obj);
11065 int len = symbols->length();
11066 uint32_t hash = 0;
11067 for (int i = 0; i < len; i++) {
11068 hash ^= String::cast(symbols->get(i))->Hash();
11069 }
11070 return hash;
11071 }
11072
11073 Object* AsObject() { return symbols_; }
11074
11075 private:
11076 FixedArray* symbols_;
11077};
11078
11079
11080Object* MapCache::Lookup(FixedArray* array) {
11081 SymbolsKey key(array);
11082 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010011083 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011084 return get(EntryToIndex(entry) + 1);
11085}
11086
11087
John Reck59135872010-11-02 12:39:01 -070011088MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011089 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070011090 Object* obj;
11091 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
11092 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11093 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011094
11095 MapCache* cache = reinterpret_cast<MapCache*>(obj);
11096 int entry = cache->FindInsertionEntry(key.Hash());
11097 cache->set(EntryToIndex(entry), array);
11098 cache->set(EntryToIndex(entry) + 1, value);
11099 cache->ElementAdded();
11100 return cache;
11101}
11102
11103
11104template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011105MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
11106 Object* obj;
11107 { MaybeObject* maybe_obj =
11108 HashTable<Shape, Key>::Allocate(at_least_space_for);
11109 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000011110 }
John Reck59135872010-11-02 12:39:01 -070011111 // Initialize the next enumeration index.
11112 Dictionary<Shape, Key>::cast(obj)->
11113 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000011114 return obj;
11115}
11116
11117
11118template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011119MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010011120 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011121 int length = HashTable<Shape, Key>::NumberOfElements();
11122
11123 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070011124 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010011125 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070011126 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11127 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011128 FixedArray* iteration_order = FixedArray::cast(obj);
11129 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000011130 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000011131 }
11132
11133 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010011134 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070011135 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11136 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011137 FixedArray* enumeration_order = FixedArray::cast(obj);
11138
11139 // Fill the enumeration order array with property details.
11140 int capacity = HashTable<Shape, Key>::Capacity();
11141 int pos = 0;
11142 for (int i = 0; i < capacity; i++) {
11143 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000011144 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011145 }
11146 }
11147
11148 // Sort the arrays wrt. enumeration order.
11149 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
11150
11151 // Overwrite the enumeration_order with the enumeration indices.
11152 for (int i = 0; i < length; i++) {
11153 int index = Smi::cast(iteration_order->get(i))->value();
11154 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000011155 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000011156 }
11157
11158 // Update the dictionary with new indices.
11159 capacity = HashTable<Shape, Key>::Capacity();
11160 pos = 0;
11161 for (int i = 0; i < capacity; i++) {
11162 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
11163 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
11164 PropertyDetails details = DetailsAt(i);
11165 PropertyDetails new_details =
11166 PropertyDetails(details.attributes(), details.type(), enum_index);
11167 DetailsAtPut(i, new_details);
11168 }
11169 }
11170
11171 // Set the next enumeration index.
11172 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
11173 return this;
11174}
11175
11176template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011177MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011178 // Check whether there are enough enumeration indices to add n elements.
11179 if (Shape::kIsEnumerable &&
11180 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
11181 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070011182 Object* result;
11183 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11184 if (!maybe_result->ToObject(&result)) return maybe_result;
11185 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011186 }
11187 return HashTable<Shape, Key>::EnsureCapacity(n, key);
11188}
11189
11190
11191void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
11192 // Do nothing if the interval [from, to) is empty.
11193 if (from >= to) return;
11194
Steve Block44f0eee2011-05-26 01:26:41 +010011195 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011196 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010011197 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011198 int capacity = Capacity();
11199 for (int i = 0; i < capacity; i++) {
11200 Object* key = KeyAt(i);
11201 if (key->IsNumber()) {
11202 uint32_t number = static_cast<uint32_t>(key->Number());
11203 if (from <= number && number < to) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011204 SetEntry(i, sentinel, sentinel);
Steve Blocka7e24c12009-10-30 11:49:00 +000011205 removed_entries++;
11206 }
11207 }
11208 }
11209
11210 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +000011211 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +000011212}
11213
11214
11215template<typename Shape, typename Key>
11216Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011217 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010011218 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000011219 PropertyDetails details = DetailsAt(entry);
11220 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011221 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010011222 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011223 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010011224 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011225 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010011226 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011227}
11228
11229
11230template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011231MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
11232 return HashTable<Shape, Key>::Shrink(key);
11233}
11234
11235
11236template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011237MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011238 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000011239
11240 // If the entry is present set the value;
11241 if (entry != Dictionary<Shape, Key>::kNotFound) {
11242 ValueAtPut(entry, value);
11243 return this;
11244 }
11245
11246 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070011247 Object* obj;
11248 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11249 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11250 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011251
John Reck59135872010-11-02 12:39:01 -070011252 Object* k;
11253 { MaybeObject* maybe_k = Shape::AsObject(key);
11254 if (!maybe_k->ToObject(&k)) return maybe_k;
11255 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011256 PropertyDetails details = PropertyDetails(NONE, NORMAL);
11257 return Dictionary<Shape, Key>::cast(obj)->
11258 AddEntry(key, value, details, Shape::Hash(key));
11259}
11260
11261
11262template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011263MaybeObject* Dictionary<Shape, Key>::Add(Key key,
11264 Object* value,
11265 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011266 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011267 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000011268 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070011269 Object* obj;
11270 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11271 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11272 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011273 return Dictionary<Shape, Key>::cast(obj)->
11274 AddEntry(key, value, details, Shape::Hash(key));
11275}
11276
11277
11278// Add a key, value pair to the dictionary.
11279template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070011280MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
11281 Object* value,
11282 PropertyDetails details,
11283 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011284 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070011285 Object* k;
11286 { MaybeObject* maybe_k = Shape::AsObject(key);
11287 if (!maybe_k->ToObject(&k)) return maybe_k;
11288 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011289
11290 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
11291 // Insert element at empty or deleted entry
11292 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
11293 // Assign an enumeration index to the property and update
11294 // SetNextEnumerationIndex.
11295 int index = NextEnumerationIndex();
11296 details = PropertyDetails(details.attributes(), details.type(), index);
11297 SetNextEnumerationIndex(index + 1);
11298 }
11299 SetEntry(entry, k, value, details);
11300 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
11301 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
11302 HashTable<Shape, Key>::ElementAdded();
11303 return this;
11304}
11305
11306
11307void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
11308 // If the dictionary requires slow elements an element has already
11309 // been added at a high index.
11310 if (requires_slow_elements()) return;
11311 // Check if this index is high enough that we should require slow
11312 // elements.
11313 if (key > kRequiresSlowElementsLimit) {
11314 set_requires_slow_elements();
11315 return;
11316 }
11317 // Update max key value.
11318 Object* max_index_object = get(kMaxNumberKeyIndex);
11319 if (!max_index_object->IsSmi() || max_number_key() < key) {
11320 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000011321 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000011322 }
11323}
11324
11325
John Reck59135872010-11-02 12:39:01 -070011326MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
11327 Object* value,
11328 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011329 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011330 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000011331 return Add(key, value, details);
11332}
11333
11334
John Reck59135872010-11-02 12:39:01 -070011335MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011336 UpdateMaxNumberKey(key);
11337 return AtPut(key, value);
11338}
11339
11340
John Reck59135872010-11-02 12:39:01 -070011341MaybeObject* NumberDictionary::Set(uint32_t key,
11342 Object* value,
11343 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011344 int entry = FindEntry(key);
11345 if (entry == kNotFound) return AddNumberEntry(key, value, details);
11346 // Preserve enumeration index.
11347 details = PropertyDetails(details.attributes(),
11348 details.type(),
11349 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -070011350 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
11351 Object* object_key;
11352 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010011353 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011354 return this;
11355}
11356
11357
11358
11359template<typename Shape, typename Key>
11360int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11361 PropertyAttributes filter) {
11362 int capacity = HashTable<Shape, Key>::Capacity();
11363 int result = 0;
11364 for (int i = 0; i < capacity; i++) {
11365 Object* k = HashTable<Shape, Key>::KeyAt(i);
11366 if (HashTable<Shape, Key>::IsKey(k)) {
11367 PropertyDetails details = DetailsAt(i);
11368 if (details.IsDeleted()) continue;
11369 PropertyAttributes attr = details.attributes();
11370 if ((attr & filter) == 0) result++;
11371 }
11372 }
11373 return result;
11374}
11375
11376
11377template<typename Shape, typename Key>
11378int Dictionary<Shape, Key>::NumberOfEnumElements() {
11379 return NumberOfElementsFilterAttributes(
11380 static_cast<PropertyAttributes>(DONT_ENUM));
11381}
11382
11383
11384template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011385void Dictionary<Shape, Key>::CopyKeysTo(
11386 FixedArray* storage,
11387 PropertyAttributes filter,
11388 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011389 ASSERT(storage->length() >= NumberOfEnumElements());
11390 int capacity = HashTable<Shape, Key>::Capacity();
11391 int index = 0;
11392 for (int i = 0; i < capacity; i++) {
11393 Object* k = HashTable<Shape, Key>::KeyAt(i);
11394 if (HashTable<Shape, Key>::IsKey(k)) {
11395 PropertyDetails details = DetailsAt(i);
11396 if (details.IsDeleted()) continue;
11397 PropertyAttributes attr = details.attributes();
11398 if ((attr & filter) == 0) storage->set(index++, k);
11399 }
11400 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011401 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11402 storage->SortPairs(storage, index);
11403 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011404 ASSERT(storage->length() >= index);
11405}
11406
11407
11408void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11409 FixedArray* sort_array) {
11410 ASSERT(storage->length() >= NumberOfEnumElements());
11411 int capacity = Capacity();
11412 int index = 0;
11413 for (int i = 0; i < capacity; i++) {
11414 Object* k = KeyAt(i);
11415 if (IsKey(k)) {
11416 PropertyDetails details = DetailsAt(i);
11417 if (details.IsDeleted() || details.IsDontEnum()) continue;
11418 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000011419 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011420 index++;
11421 }
11422 }
11423 storage->SortPairs(sort_array, sort_array->length());
11424 ASSERT(storage->length() >= index);
11425}
11426
11427
11428template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010011429void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000011430 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011431 int index,
11432 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011433 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11434 static_cast<PropertyAttributes>(NONE)));
11435 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011436 for (int i = 0; i < capacity; i++) {
11437 Object* k = HashTable<Shape, Key>::KeyAt(i);
11438 if (HashTable<Shape, Key>::IsKey(k)) {
11439 PropertyDetails details = DetailsAt(i);
11440 if (details.IsDeleted()) continue;
11441 storage->set(index++, k);
11442 }
11443 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011444 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11445 storage->SortPairs(storage, index);
11446 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011447 ASSERT(storage->length() >= index);
11448}
11449
11450
11451// Backwards lookup (slow).
11452template<typename Shape, typename Key>
11453Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11454 int capacity = HashTable<Shape, Key>::Capacity();
11455 for (int i = 0; i < capacity; i++) {
11456 Object* k = HashTable<Shape, Key>::KeyAt(i);
11457 if (Dictionary<Shape, Key>::IsKey(k)) {
11458 Object* e = ValueAt(i);
11459 if (e->IsJSGlobalPropertyCell()) {
11460 e = JSGlobalPropertyCell::cast(e)->value();
11461 }
11462 if (e == value) return k;
11463 }
11464 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010011465 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011466 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011467}
11468
11469
John Reck59135872010-11-02 12:39:01 -070011470MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000011471 JSObject* obj, int unused_property_fields) {
11472 // Make sure we preserve dictionary representation if there are too many
11473 // descriptors.
11474 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
11475
11476 // Figure out if it is necessary to generate new enumeration indices.
11477 int max_enumeration_index =
11478 NextEnumerationIndex() +
11479 (DescriptorArray::kMaxNumberOfDescriptors -
11480 NumberOfElements());
11481 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070011482 Object* result;
11483 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11484 if (!maybe_result->ToObject(&result)) return maybe_result;
11485 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011486 }
11487
11488 int instance_descriptor_length = 0;
11489 int number_of_fields = 0;
11490
Ben Murdoch8b112d22011-06-08 16:22:53 +010011491 Heap* heap = GetHeap();
11492
Steve Blocka7e24c12009-10-30 11:49:00 +000011493 // Compute the length of the instance descriptor.
11494 int capacity = Capacity();
11495 for (int i = 0; i < capacity; i++) {
11496 Object* k = KeyAt(i);
11497 if (IsKey(k)) {
11498 Object* value = ValueAt(i);
11499 PropertyType type = DetailsAt(i).type();
11500 ASSERT(type != FIELD);
11501 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000011502 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010011503 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000011504 number_of_fields += 1;
11505 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011506 }
11507 }
11508
11509 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011510 Object* descriptors_unchecked;
11511 { MaybeObject* maybe_descriptors_unchecked =
11512 DescriptorArray::Allocate(instance_descriptor_length);
11513 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
11514 return maybe_descriptors_unchecked;
11515 }
11516 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011517 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
11518
11519 int inobject_props = obj->map()->inobject_properties();
11520 int number_of_allocated_fields =
11521 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010011522 if (number_of_allocated_fields < 0) {
11523 // There is enough inobject space for all fields (including unused).
11524 number_of_allocated_fields = 0;
11525 unused_property_fields = inobject_props - number_of_fields;
11526 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011527
11528 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070011529 Object* fields;
11530 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010011531 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070011532 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
11533 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011534
11535 // Fill in the instance descriptor and the fields.
11536 int next_descriptor = 0;
11537 int current_offset = 0;
11538 for (int i = 0; i < capacity; i++) {
11539 Object* k = KeyAt(i);
11540 if (IsKey(k)) {
11541 Object* value = ValueAt(i);
11542 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011543 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010011544 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070011545 if (!maybe_key->ToObject(&key)) return maybe_key;
11546 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011547 PropertyDetails details = DetailsAt(i);
11548 PropertyType type = details.type();
11549
Steve Block44f0eee2011-05-26 01:26:41 +010011550 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011551 ConstantFunctionDescriptor d(String::cast(key),
11552 JSFunction::cast(value),
11553 details.attributes(),
11554 details.index());
11555 descriptors->Set(next_descriptor++, &d);
11556 } else if (type == NORMAL) {
11557 if (current_offset < inobject_props) {
11558 obj->InObjectPropertyAtPut(current_offset,
11559 value,
11560 UPDATE_WRITE_BARRIER);
11561 } else {
11562 int offset = current_offset - inobject_props;
11563 FixedArray::cast(fields)->set(offset, value);
11564 }
11565 FieldDescriptor d(String::cast(key),
11566 current_offset++,
11567 details.attributes(),
11568 details.index());
11569 descriptors->Set(next_descriptor++, &d);
11570 } else if (type == CALLBACKS) {
11571 CallbacksDescriptor d(String::cast(key),
11572 value,
11573 details.attributes(),
11574 details.index());
11575 descriptors->Set(next_descriptor++, &d);
11576 } else {
11577 UNREACHABLE();
11578 }
11579 }
11580 }
11581 ASSERT(current_offset == number_of_fields);
11582
11583 descriptors->Sort();
11584 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070011585 Object* new_map;
11586 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
11587 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
11588 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011589
11590 // Transform the object.
11591 obj->set_map(Map::cast(new_map));
11592 obj->map()->set_instance_descriptors(descriptors);
11593 obj->map()->set_unused_property_fields(unused_property_fields);
11594
11595 obj->set_properties(FixedArray::cast(fields));
11596 ASSERT(obj->IsJSObject());
11597
11598 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
11599 // Check that it really works.
11600 ASSERT(obj->HasFastProperties());
11601
11602 return obj;
11603}
11604
11605
11606#ifdef ENABLE_DEBUGGER_SUPPORT
11607// Check if there is a break point at this code position.
11608bool DebugInfo::HasBreakPoint(int code_position) {
11609 // Get the break point info object for this code position.
11610 Object* break_point_info = GetBreakPointInfo(code_position);
11611
11612 // If there is no break point info object or no break points in the break
11613 // point info object there is no break point at this code position.
11614 if (break_point_info->IsUndefined()) return false;
11615 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
11616}
11617
11618
11619// Get the break point info object for this code position.
11620Object* DebugInfo::GetBreakPointInfo(int code_position) {
11621 // Find the index of the break point info object for this code position.
11622 int index = GetBreakPointInfoIndex(code_position);
11623
11624 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011625 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011626 return BreakPointInfo::cast(break_points()->get(index));
11627}
11628
11629
11630// Clear a break point at the specified code position.
11631void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
11632 int code_position,
11633 Handle<Object> break_point_object) {
11634 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11635 if (break_point_info->IsUndefined()) return;
11636 BreakPointInfo::ClearBreakPoint(
11637 Handle<BreakPointInfo>::cast(break_point_info),
11638 break_point_object);
11639}
11640
11641
11642void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
11643 int code_position,
11644 int source_position,
11645 int statement_position,
11646 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011647 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011648 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11649 if (!break_point_info->IsUndefined()) {
11650 BreakPointInfo::SetBreakPoint(
11651 Handle<BreakPointInfo>::cast(break_point_info),
11652 break_point_object);
11653 return;
11654 }
11655
11656 // Adding a new break point for a code position which did not have any
11657 // break points before. Try to find a free slot.
11658 int index = kNoBreakPointInfo;
11659 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11660 if (debug_info->break_points()->get(i)->IsUndefined()) {
11661 index = i;
11662 break;
11663 }
11664 }
11665 if (index == kNoBreakPointInfo) {
11666 // No free slot - extend break point info array.
11667 Handle<FixedArray> old_break_points =
11668 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011669 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010011670 isolate->factory()->NewFixedArray(
11671 old_break_points->length() +
11672 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011673
11674 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000011675 for (int i = 0; i < old_break_points->length(); i++) {
11676 new_break_points->set(i, old_break_points->get(i));
11677 }
11678 index = old_break_points->length();
11679 }
11680 ASSERT(index != kNoBreakPointInfo);
11681
11682 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011683 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11684 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000011685 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11686 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11687 new_break_point_info->
11688 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010011689 new_break_point_info->set_break_point_objects(
11690 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011691 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11692 debug_info->break_points()->set(index, *new_break_point_info);
11693}
11694
11695
11696// Get the break point objects for a code position.
11697Object* DebugInfo::GetBreakPointObjects(int code_position) {
11698 Object* break_point_info = GetBreakPointInfo(code_position);
11699 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011700 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011701 }
11702 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11703}
11704
11705
11706// Get the total number of break points.
11707int DebugInfo::GetBreakPointCount() {
11708 if (break_points()->IsUndefined()) return 0;
11709 int count = 0;
11710 for (int i = 0; i < break_points()->length(); i++) {
11711 if (!break_points()->get(i)->IsUndefined()) {
11712 BreakPointInfo* break_point_info =
11713 BreakPointInfo::cast(break_points()->get(i));
11714 count += break_point_info->GetBreakPointCount();
11715 }
11716 }
11717 return count;
11718}
11719
11720
11721Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11722 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011723 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011724 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011725 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11726 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11727 Handle<BreakPointInfo> break_point_info =
11728 Handle<BreakPointInfo>(BreakPointInfo::cast(
11729 debug_info->break_points()->get(i)));
11730 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11731 break_point_object)) {
11732 return *break_point_info;
11733 }
11734 }
11735 }
Steve Block44f0eee2011-05-26 01:26:41 +010011736 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011737}
11738
11739
11740// Find the index of the break point info object for the specified code
11741// position.
11742int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11743 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11744 for (int i = 0; i < break_points()->length(); i++) {
11745 if (!break_points()->get(i)->IsUndefined()) {
11746 BreakPointInfo* break_point_info =
11747 BreakPointInfo::cast(break_points()->get(i));
11748 if (break_point_info->code_position()->value() == code_position) {
11749 return i;
11750 }
11751 }
11752 }
11753 return kNoBreakPointInfo;
11754}
11755
11756
11757// Remove the specified break point object.
11758void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11759 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011760 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011761 // If there are no break points just ignore.
11762 if (break_point_info->break_point_objects()->IsUndefined()) return;
11763 // If there is a single break point clear it if it is the same.
11764 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11765 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011766 break_point_info->set_break_point_objects(
11767 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011768 }
11769 return;
11770 }
11771 // If there are multiple break points shrink the array
11772 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11773 Handle<FixedArray> old_array =
11774 Handle<FixedArray>(
11775 FixedArray::cast(break_point_info->break_point_objects()));
11776 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011777 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011778 int found_count = 0;
11779 for (int i = 0; i < old_array->length(); i++) {
11780 if (old_array->get(i) == *break_point_object) {
11781 ASSERT(found_count == 0);
11782 found_count++;
11783 } else {
11784 new_array->set(i - found_count, old_array->get(i));
11785 }
11786 }
11787 // If the break point was found in the list change it.
11788 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11789}
11790
11791
11792// Add the specified break point object.
11793void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11794 Handle<Object> break_point_object) {
11795 // If there was no break point objects before just set it.
11796 if (break_point_info->break_point_objects()->IsUndefined()) {
11797 break_point_info->set_break_point_objects(*break_point_object);
11798 return;
11799 }
11800 // If the break point object is the same as before just ignore.
11801 if (break_point_info->break_point_objects() == *break_point_object) return;
11802 // If there was one break point object before replace with array.
11803 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011804 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000011805 array->set(0, break_point_info->break_point_objects());
11806 array->set(1, *break_point_object);
11807 break_point_info->set_break_point_objects(*array);
11808 return;
11809 }
11810 // If there was more than one break point before extend array.
11811 Handle<FixedArray> old_array =
11812 Handle<FixedArray>(
11813 FixedArray::cast(break_point_info->break_point_objects()));
11814 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011815 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011816 for (int i = 0; i < old_array->length(); i++) {
11817 // If the break point was there before just ignore.
11818 if (old_array->get(i) == *break_point_object) return;
11819 new_array->set(i, old_array->get(i));
11820 }
11821 // Add the new break point.
11822 new_array->set(old_array->length(), *break_point_object);
11823 break_point_info->set_break_point_objects(*new_array);
11824}
11825
11826
11827bool BreakPointInfo::HasBreakPointObject(
11828 Handle<BreakPointInfo> break_point_info,
11829 Handle<Object> break_point_object) {
11830 // No break point.
11831 if (break_point_info->break_point_objects()->IsUndefined()) return false;
11832 // Single beak point.
11833 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11834 return break_point_info->break_point_objects() == *break_point_object;
11835 }
11836 // Multiple break points.
11837 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11838 for (int i = 0; i < array->length(); i++) {
11839 if (array->get(i) == *break_point_object) {
11840 return true;
11841 }
11842 }
11843 return false;
11844}
11845
11846
11847// Get the number of break points.
11848int BreakPointInfo::GetBreakPointCount() {
11849 // No break point.
11850 if (break_point_objects()->IsUndefined()) return 0;
11851 // Single beak point.
11852 if (!break_point_objects()->IsFixedArray()) return 1;
11853 // Multiple break points.
11854 return FixedArray::cast(break_point_objects())->length();
11855}
11856#endif
11857
11858
11859} } // namespace v8::internal