blob: 6085b4ef2545ce87a4a0cbe29fb7d0618b22a6fe [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +01001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010033#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "deoptimizer.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000036#include "elements.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000037#include "execution.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "full-codegen.h"
39#include "hydrogen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000040#include "objects-inl.h"
Iain Merrick75681382010-08-19 15:07:18 +010041#include "objects-visiting.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042#include "macro-assembler.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010043#include "safepoint-table.h"
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() {
Ben Murdoch589d6972011-11-30 16:04:58 +000087 if (IsJSReceiver()) {
Steve Blocka7e24c12009-10-30 11:49:00 +000088 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));
Ben Murdoch589d6972011-11-30 16:04:58 +0000240 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000241 if (trap->IsUndefined()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000242 // Get the derived `get' property.
243 trap = isolate->derived_get_trap();
244 }
245
246 // Call trap function.
247 Object** args[] = { receiver.location(), name.location() };
248 bool has_exception;
249 Handle<Object> result =
250 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
251 if (has_exception) return Failure::Exception();
252
253 return *result;
254}
255
256
John Reck59135872010-11-02 12:39:01 -0700257MaybeObject* Object::GetPropertyWithDefinedGetter(Object* receiver,
258 JSFunction* getter) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000259 HandleScope scope;
260 Handle<JSFunction> fun(JSFunction::cast(getter));
261 Handle<Object> self(receiver);
262#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +0100263 Debug* debug = fun->GetHeap()->isolate()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000264 // Handle stepping into a getter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +0100265 if (debug->StepInActive()) {
266 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000267 }
268#endif
269 bool has_pending_exception;
270 Handle<Object> result =
271 Execution::Call(fun, self, 0, NULL, &has_pending_exception);
272 // Check for pending exception and return the result.
273 if (has_pending_exception) return Failure::Exception();
274 return *result;
275}
276
277
278// Only deal with CALLBACKS and INTERCEPTOR
John Reck59135872010-11-02 12:39:01 -0700279MaybeObject* JSObject::GetPropertyWithFailedAccessCheck(
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 Object* receiver,
281 LookupResult* result,
282 String* name,
283 PropertyAttributes* attributes) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000284 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 switch (result->type()) {
286 case CALLBACKS: {
287 // Only allow API accessors.
288 Object* obj = result->GetCallbackObject();
289 if (obj->IsAccessorInfo()) {
290 AccessorInfo* info = AccessorInfo::cast(obj);
291 if (info->all_can_read()) {
292 *attributes = result->GetAttributes();
293 return GetPropertyWithCallback(receiver,
294 result->GetCallbackObject(),
295 name,
296 result->holder());
297 }
298 }
299 break;
300 }
301 case NORMAL:
302 case FIELD:
303 case CONSTANT_FUNCTION: {
304 // Search ALL_CAN_READ accessors in prototype chain.
305 LookupResult r;
306 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000307 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000308 return GetPropertyWithFailedAccessCheck(receiver,
309 &r,
310 name,
311 attributes);
312 }
313 break;
314 }
315 case INTERCEPTOR: {
316 // If the object has an interceptor, try real named properties.
317 // No access check in GetPropertyAttributeWithInterceptor.
318 LookupResult r;
319 result->holder()->LookupRealNamedProperty(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000320 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000321 return GetPropertyWithFailedAccessCheck(receiver,
322 &r,
323 name,
324 attributes);
325 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000326 break;
327 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000328 default:
329 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000330 }
331 }
332
333 // No accessible property found.
334 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100335 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100336 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_GET);
337 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000338}
339
340
341PropertyAttributes JSObject::GetPropertyAttributeWithFailedAccessCheck(
342 Object* receiver,
343 LookupResult* result,
344 String* name,
345 bool continue_search) {
Andrei Popescu402d9372010-02-26 13:31:12 +0000346 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 switch (result->type()) {
348 case CALLBACKS: {
349 // Only allow API accessors.
350 Object* obj = result->GetCallbackObject();
351 if (obj->IsAccessorInfo()) {
352 AccessorInfo* info = AccessorInfo::cast(obj);
353 if (info->all_can_read()) {
354 return result->GetAttributes();
355 }
356 }
357 break;
358 }
359
360 case NORMAL:
361 case FIELD:
362 case CONSTANT_FUNCTION: {
363 if (!continue_search) break;
364 // Search ALL_CAN_READ accessors in prototype chain.
365 LookupResult r;
366 result->holder()->LookupRealNamedPropertyInPrototypes(name, &r);
Andrei Popescu402d9372010-02-26 13:31:12 +0000367 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 return GetPropertyAttributeWithFailedAccessCheck(receiver,
369 &r,
370 name,
371 continue_search);
372 }
373 break;
374 }
375
376 case INTERCEPTOR: {
377 // If the object has an interceptor, try real named properties.
378 // No access check in GetPropertyAttributeWithInterceptor.
379 LookupResult r;
380 if (continue_search) {
381 result->holder()->LookupRealNamedProperty(name, &r);
382 } else {
383 result->holder()->LocalLookupRealNamedProperty(name, &r);
384 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000385 if (r.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000386 return GetPropertyAttributeWithFailedAccessCheck(receiver,
387 &r,
388 name,
389 continue_search);
390 }
391 break;
392 }
393
Andrei Popescu402d9372010-02-26 13:31:12 +0000394 default:
395 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +0000396 }
397 }
398
Ben Murdoch8b112d22011-06-08 16:22:53 +0100399 GetHeap()->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 return ABSENT;
401}
402
403
Steve Blocka7e24c12009-10-30 11:49:00 +0000404Object* JSObject::GetNormalizedProperty(LookupResult* result) {
405 ASSERT(!HasFastProperties());
406 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
407 if (IsGlobalObject()) {
408 value = JSGlobalPropertyCell::cast(value)->value();
409 }
410 ASSERT(!value->IsJSGlobalPropertyCell());
411 return value;
412}
413
414
415Object* JSObject::SetNormalizedProperty(LookupResult* result, Object* value) {
416 ASSERT(!HasFastProperties());
417 if (IsGlobalObject()) {
418 JSGlobalPropertyCell* cell =
419 JSGlobalPropertyCell::cast(
420 property_dictionary()->ValueAt(result->GetDictionaryEntry()));
421 cell->set_value(value);
422 } else {
423 property_dictionary()->ValueAtPut(result->GetDictionaryEntry(), value);
424 }
425 return value;
426}
427
428
John Reck59135872010-11-02 12:39:01 -0700429MaybeObject* JSObject::SetNormalizedProperty(String* name,
430 Object* value,
431 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000432 ASSERT(!HasFastProperties());
433 int entry = property_dictionary()->FindEntry(name);
434 if (entry == StringDictionary::kNotFound) {
435 Object* store_value = value;
436 if (IsGlobalObject()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100437 Heap* heap = name->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100438 MaybeObject* maybe_store_value =
439 heap->AllocateJSGlobalPropertyCell(value);
440 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 }
John Reck59135872010-11-02 12:39:01 -0700442 Object* dict;
443 { MaybeObject* maybe_dict =
444 property_dictionary()->Add(name, store_value, details);
445 if (!maybe_dict->ToObject(&dict)) return maybe_dict;
446 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000447 set_properties(StringDictionary::cast(dict));
448 return value;
449 }
450 // Preserve enumeration index.
451 details = PropertyDetails(details.attributes(),
452 details.type(),
453 property_dictionary()->DetailsAt(entry).index());
454 if (IsGlobalObject()) {
455 JSGlobalPropertyCell* cell =
456 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry));
457 cell->set_value(value);
458 // Please note we have to update the property details.
459 property_dictionary()->DetailsAtPut(entry, details);
460 } else {
461 property_dictionary()->SetEntry(entry, name, value, details);
462 }
463 return value;
464}
465
466
John Reck59135872010-11-02 12:39:01 -0700467MaybeObject* JSObject::DeleteNormalizedProperty(String* name, DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 ASSERT(!HasFastProperties());
469 StringDictionary* dictionary = property_dictionary();
470 int entry = dictionary->FindEntry(name);
471 if (entry != StringDictionary::kNotFound) {
472 // If we have a global object set the cell to the hole.
473 if (IsGlobalObject()) {
474 PropertyDetails details = dictionary->DetailsAt(entry);
475 if (details.IsDontDelete()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100476 if (mode != FORCE_DELETION) return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000477 // When forced to delete global properties, we have to make a
478 // map change to invalidate any ICs that think they can load
479 // from the DontDelete cell without checking if it contains
480 // the hole value.
John Reck59135872010-11-02 12:39:01 -0700481 Object* new_map;
482 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
483 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
484 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000485 set_map(Map::cast(new_map));
486 }
487 JSGlobalPropertyCell* cell =
488 JSGlobalPropertyCell::cast(dictionary->ValueAt(entry));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100489 cell->set_value(cell->heap()->the_hole_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000490 dictionary->DetailsAtPut(entry, details.AsDeleted());
491 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000492 Object* deleted = dictionary->DeleteProperty(entry, mode);
493 if (deleted == GetHeap()->true_value()) {
494 FixedArray* new_properties = NULL;
495 MaybeObject* maybe_properties = dictionary->Shrink(name);
496 if (!maybe_properties->To(&new_properties)) {
497 return maybe_properties;
498 }
499 set_properties(new_properties);
500 }
501 return deleted;
Steve Blocka7e24c12009-10-30 11:49:00 +0000502 }
503 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100504 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000505}
506
507
508bool JSObject::IsDirty() {
509 Object* cons_obj = map()->constructor();
510 if (!cons_obj->IsJSFunction())
511 return true;
512 JSFunction* fun = JSFunction::cast(cons_obj);
Steve Block6ded16b2010-05-10 14:33:55 +0100513 if (!fun->shared()->IsApiFunction())
Steve Blocka7e24c12009-10-30 11:49:00 +0000514 return true;
515 // If the object is fully fast case and has the same map it was
516 // created with then no changes can have been made to it.
517 return map() != fun->initial_map()
518 || !HasFastElements()
519 || !HasFastProperties();
520}
521
522
John Reck59135872010-11-02 12:39:01 -0700523MaybeObject* Object::GetProperty(Object* receiver,
524 LookupResult* result,
525 String* name,
526 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 // Make sure that the top context does not change when doing
528 // callbacks or interceptor calls.
529 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +0100530 Heap* heap = name->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000531
532 // Traverse the prototype chain from the current object (this) to
Ben Murdoch257744e2011-11-30 15:57:28 +0000533 // the holder and check for access rights. This avoids traversing the
Steve Blocka7e24c12009-10-30 11:49:00 +0000534 // objects more than once in case of interceptors, because the
535 // holder will always be the interceptor holder and the search may
536 // only continue with a current object just after the interceptor
537 // holder in the prototype chain.
Ben Murdoch257744e2011-11-30 15:57:28 +0000538 // Proxy handlers do not use the proxy's prototype, so we can skip this.
539 if (!result->IsHandler()) {
540 Object* last = result->IsProperty() ? result->holder() : heap->null_value();
541 ASSERT(this != this->GetPrototype());
542 for (Object* current = this; true; current = current->GetPrototype()) {
543 if (current->IsAccessCheckNeeded()) {
544 // Check if we're allowed to read from the current object. Note
545 // that even though we may not actually end up loading the named
546 // property from the current object, we still check that we have
547 // access to it.
548 JSObject* checked = JSObject::cast(current);
549 if (!heap->isolate()->MayNamedAccess(checked, name, v8::ACCESS_GET)) {
550 return checked->GetPropertyWithFailedAccessCheck(receiver,
551 result,
552 name,
553 attributes);
554 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000555 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000556 // Stop traversing the chain once we reach the last object in the
557 // chain; either the holder of the result or null in case of an
558 // absent property.
559 if (current == last) break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000560 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000561 }
562
563 if (!result->IsProperty()) {
564 *attributes = ABSENT;
Steve Block44f0eee2011-05-26 01:26:41 +0100565 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000566 }
567 *attributes = result->GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 Object* value;
569 JSObject* holder = result->holder();
570 switch (result->type()) {
571 case NORMAL:
572 value = holder->GetNormalizedProperty(result);
573 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100574 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 case FIELD:
576 value = holder->FastPropertyAt(result->GetFieldIndex());
577 ASSERT(!value->IsTheHole() || result->IsReadOnly());
Steve Block44f0eee2011-05-26 01:26:41 +0100578 return value->IsTheHole() ? heap->undefined_value() : value;
Steve Blocka7e24c12009-10-30 11:49:00 +0000579 case CONSTANT_FUNCTION:
580 return result->GetConstantFunction();
581 case CALLBACKS:
582 return GetPropertyWithCallback(receiver,
583 result->GetCallbackObject(),
584 name,
585 holder);
Ben Murdoch257744e2011-11-30 15:57:28 +0000586 case HANDLER: {
587 JSProxy* proxy = JSProxy::cast(this);
588 return GetPropertyWithHandler(receiver, name, proxy->handler());
589 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 case INTERCEPTOR: {
591 JSObject* recvr = JSObject::cast(receiver);
592 return holder->GetPropertyWithInterceptor(recvr, name, attributes);
593 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000594 case MAP_TRANSITION:
Ben Murdoch589d6972011-11-30 16:04:58 +0000595 case ELEMENTS_TRANSITION:
Ben Murdoch257744e2011-11-30 15:57:28 +0000596 case CONSTANT_TRANSITION:
597 case NULL_DESCRIPTOR:
598 break;
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 }
Ben Murdoch257744e2011-11-30 15:57:28 +0000600 UNREACHABLE();
601 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000602}
603
604
John Reck59135872010-11-02 12:39:01 -0700605MaybeObject* Object::GetElementWithReceiver(Object* receiver, uint32_t index) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000606 Heap* heap = IsSmi()
607 ? Isolate::Current()->heap()
608 : HeapObject::cast(this)->GetHeap();
609 Object* holder = this;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100610
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000611 // Iterate up the prototype chain until an element is found or the null
612 // prototype is encountered.
613 for (holder = this;
614 holder != heap->null_value();
615 holder = holder->GetPrototype()) {
616 if (holder->IsSmi()) {
617 Context* global_context = Isolate::Current()->context()->global_context();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100618 holder = global_context->number_function()->instance_prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100619 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000620 HeapObject* heap_object = HeapObject::cast(holder);
621 if (!heap_object->IsJSObject()) {
622 Isolate* isolate = heap->isolate();
623 Context* global_context = isolate->context()->global_context();
624 if (heap_object->IsString()) {
625 holder = global_context->string_function()->instance_prototype();
626 } else if (heap_object->IsHeapNumber()) {
627 holder = global_context->number_function()->instance_prototype();
628 } else if (heap_object->IsBoolean()) {
629 holder = global_context->boolean_function()->instance_prototype();
630 } else if (heap_object->IsJSProxy()) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000631 // TODO(rossberg): do something
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000632 return heap->undefined_value(); // For now...
633 } else {
634 // Undefined and null have no indexed properties.
635 ASSERT(heap_object->IsUndefined() || heap_object->IsNull());
636 return heap->undefined_value();
637 }
638 }
639 }
640
641 // Inline the case for JSObjects. Doing so significantly improves the
642 // performance of fetching elements where checking the prototype chain is
643 // necessary.
644 JSObject* js_object = JSObject::cast(holder);
645
646 // Check access rights if needed.
647 if (js_object->IsAccessCheckNeeded()) {
648 Isolate* isolate = heap->isolate();
649 if (!isolate->MayIndexedAccess(js_object, index, v8::ACCESS_GET)) {
650 isolate->ReportFailedAccessCheck(js_object, v8::ACCESS_GET);
651 return heap->undefined_value();
652 }
653 }
654
655 if (js_object->HasIndexedInterceptor()) {
656 return js_object->GetElementWithInterceptor(receiver, index);
657 }
658
659 if (js_object->elements() != heap->empty_fixed_array()) {
660 MaybeObject* result = js_object->GetElementsAccessor()->Get(
661 js_object->elements(),
662 index,
663 js_object,
664 receiver);
665 if (result != heap->the_hole_value()) return result;
Ben Murdoch8b112d22011-06-08 16:22:53 +0100666 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100667 }
668
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000669 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000670}
671
672
673Object* Object::GetPrototype() {
Ben Murdoch8b112d22011-06-08 16:22:53 +0100674 if (IsSmi()) {
675 Heap* heap = Isolate::Current()->heap();
676 Context* context = heap->isolate()->context()->global_context();
677 return context->number_function()->instance_prototype();
678 }
679
680 HeapObject* heap_object = HeapObject::cast(this);
681
Ben Murdoch257744e2011-11-30 15:57:28 +0000682 // The object is either a number, a string, a boolean,
683 // a real JS object, or a Harmony proxy.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000684 if (heap_object->IsJSReceiver()) {
Ben Murdoch257744e2011-11-30 15:57:28 +0000685 return heap_object->map()->prototype();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100686 }
687 Heap* heap = heap_object->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +0100688 Context* context = heap->isolate()->context()->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000689
Ben Murdoch8b112d22011-06-08 16:22:53 +0100690 if (heap_object->IsHeapNumber()) {
691 return context->number_function()->instance_prototype();
692 }
693 if (heap_object->IsString()) {
694 return context->string_function()->instance_prototype();
695 }
696 if (heap_object->IsBoolean()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000697 return context->boolean_function()->instance_prototype();
698 } else {
Steve Block44f0eee2011-05-26 01:26:41 +0100699 return heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000700 }
701}
702
703
Ben Murdochb0fe1622011-05-05 13:52:32 +0100704void Object::ShortPrint(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000705 HeapStringAllocator allocator;
706 StringStream accumulator(&allocator);
707 ShortPrint(&accumulator);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100708 accumulator.OutputToFile(out);
Steve Blocka7e24c12009-10-30 11:49:00 +0000709}
710
711
712void Object::ShortPrint(StringStream* accumulator) {
713 if (IsSmi()) {
714 Smi::cast(this)->SmiPrint(accumulator);
715 } else if (IsFailure()) {
716 Failure::cast(this)->FailurePrint(accumulator);
717 } else {
718 HeapObject::cast(this)->HeapObjectShortPrint(accumulator);
719 }
720}
721
722
Ben Murdochb0fe1622011-05-05 13:52:32 +0100723void Smi::SmiPrint(FILE* out) {
724 PrintF(out, "%d", value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000725}
726
727
728void Smi::SmiPrint(StringStream* accumulator) {
729 accumulator->Add("%d", value());
730}
731
732
733void Failure::FailurePrint(StringStream* accumulator) {
Steve Block3ce2e202009-11-05 08:53:23 +0000734 accumulator->Add("Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000735}
736
737
Ben Murdochb0fe1622011-05-05 13:52:32 +0100738void Failure::FailurePrint(FILE* out) {
739 PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000740}
741
742
Steve Blocka7e24c12009-10-30 11:49:00 +0000743// Should a word be prefixed by 'a' or 'an' in order to read naturally in
744// English? Returns false for non-ASCII or words that don't start with
745// a capital letter. The a/an rule follows pronunciation in English.
746// We don't use the BBC's overcorrect "an historic occasion" though if
747// you speak a dialect you may well say "an 'istoric occasion".
748static bool AnWord(String* str) {
749 if (str->length() == 0) return false; // A nothing.
750 int c0 = str->Get(0);
751 int c1 = str->length() > 1 ? str->Get(1) : 0;
752 if (c0 == 'U') {
753 if (c1 > 'Z') {
754 return true; // An Umpire, but a UTF8String, a U.
755 }
756 } else if (c0 == 'A' || c0 == 'E' || c0 == 'I' || c0 == 'O') {
757 return true; // An Ape, an ABCBook.
758 } else if ((c1 == 0 || (c1 >= 'A' && c1 <= 'Z')) &&
759 (c0 == 'F' || c0 == 'H' || c0 == 'M' || c0 == 'N' || c0 == 'R' ||
760 c0 == 'S' || c0 == 'X')) {
761 return true; // An MP3File, an M.
762 }
763 return false;
764}
765
766
John Reck59135872010-11-02 12:39:01 -0700767MaybeObject* String::SlowTryFlatten(PretenureFlag pretenure) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000768#ifdef DEBUG
769 // Do not attempt to flatten in debug mode when allocation is not
770 // allowed. This is to avoid an assertion failure when allocating.
771 // Flattening strings is the only case where we always allow
772 // allocation because no GC is performed if the allocation fails.
Steve Block44f0eee2011-05-26 01:26:41 +0100773 if (!HEAP->IsAllocationAllowed()) return this;
Steve Blocka7e24c12009-10-30 11:49:00 +0000774#endif
775
Steve Block44f0eee2011-05-26 01:26:41 +0100776 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000777 switch (StringShape(this).representation_tag()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000778 case kConsStringTag: {
779 ConsString* cs = ConsString::cast(this);
780 if (cs->second()->length() == 0) {
Leon Clarkef7060e22010-06-03 12:02:55 +0100781 return cs->first();
Steve Blocka7e24c12009-10-30 11:49:00 +0000782 }
783 // There's little point in putting the flat string in new space if the
784 // cons string is in old space. It can never get GCed until there is
785 // an old space GC.
Steve Block44f0eee2011-05-26 01:26:41 +0100786 PretenureFlag tenure = heap->InNewSpace(this) ? pretenure : TENURED;
Steve Blocka7e24c12009-10-30 11:49:00 +0000787 int len = length();
788 Object* object;
789 String* result;
790 if (IsAsciiRepresentation()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100791 { MaybeObject* maybe_object = heap->AllocateRawAsciiString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700792 if (!maybe_object->ToObject(&object)) return maybe_object;
793 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000794 result = String::cast(object);
795 String* first = cs->first();
796 int first_length = first->length();
797 char* dest = SeqAsciiString::cast(result)->GetChars();
798 WriteToFlat(first, dest, 0, first_length);
799 String* second = cs->second();
800 WriteToFlat(second,
801 dest + first_length,
802 0,
803 len - first_length);
804 } else {
John Reck59135872010-11-02 12:39:01 -0700805 { MaybeObject* maybe_object =
Steve Block44f0eee2011-05-26 01:26:41 +0100806 heap->AllocateRawTwoByteString(len, tenure);
John Reck59135872010-11-02 12:39:01 -0700807 if (!maybe_object->ToObject(&object)) return maybe_object;
808 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000809 result = String::cast(object);
810 uc16* dest = SeqTwoByteString::cast(result)->GetChars();
811 String* first = cs->first();
812 int first_length = first->length();
813 WriteToFlat(first, dest, 0, first_length);
814 String* second = cs->second();
815 WriteToFlat(second,
816 dest + first_length,
817 0,
818 len - first_length);
819 }
820 cs->set_first(result);
Steve Block44f0eee2011-05-26 01:26:41 +0100821 cs->set_second(heap->empty_string());
Leon Clarkef7060e22010-06-03 12:02:55 +0100822 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +0000823 }
824 default:
825 return this;
826 }
827}
828
829
830bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
Steve Block8defd9f2010-07-08 12:39:36 +0100831 // Externalizing twice leaks the external resource, so it's
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100832 // prohibited by the API.
833 ASSERT(!this->IsExternalString());
Steve Blocka7e24c12009-10-30 11:49:00 +0000834#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000835 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000836 // Assert that the resource and the string are equivalent.
837 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100838 ScopedVector<uc16> smart_chars(this->length());
839 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
840 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000841 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100842 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000843 }
844#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100845 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000846 int size = this->Size(); // Byte size of the original string.
847 if (size < ExternalString::kSize) {
848 // The string is too small to fit an external String in its place. This can
849 // only happen for zero length strings.
850 return false;
851 }
852 ASSERT(size >= ExternalString::kSize);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100853 bool is_ascii = this->IsAsciiRepresentation();
Steve Blocka7e24c12009-10-30 11:49:00 +0000854 bool is_symbol = this->IsSymbol();
855 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000856 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000857
858 // Morph the object to an external string by adjusting the map and
859 // reinitializing the fields.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100860 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100861 heap->external_string_with_ascii_data_map() :
862 heap->external_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 ExternalTwoByteString* self = ExternalTwoByteString::cast(this);
864 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000865 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000866 self->set_resource(resource);
867 // Additionally make the object into an external symbol if the original string
868 // was a symbol to start with.
869 if (is_symbol) {
870 self->Hash(); // Force regeneration of the hash value.
871 // Now morph this external string into a external symbol.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100872 this->set_map(is_ascii ?
Steve Block44f0eee2011-05-26 01:26:41 +0100873 heap->external_symbol_with_ascii_data_map() :
874 heap->external_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 }
876
877 // Fill the remainder of the string with dead wood.
878 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100879 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 return true;
881}
882
883
884bool String::MakeExternal(v8::String::ExternalAsciiStringResource* resource) {
885#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000886 if (FLAG_enable_slow_asserts) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000887 // Assert that the resource and the string are equivalent.
888 ASSERT(static_cast<size_t>(this->length()) == resource->length());
Kristian Monsen25f61362010-05-21 11:50:48 +0100889 ScopedVector<char> smart_chars(this->length());
890 String::WriteToFlat(this, smart_chars.start(), 0, this->length());
891 ASSERT(memcmp(smart_chars.start(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000892 resource->data(),
Kristian Monsen25f61362010-05-21 11:50:48 +0100893 resource->length() * sizeof(smart_chars[0])) == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000894 }
895#endif // DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100896 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +0000897 int size = this->Size(); // Byte size of the original string.
898 if (size < ExternalString::kSize) {
899 // The string is too small to fit an external String in its place. This can
900 // only happen for zero length strings.
901 return false;
902 }
903 ASSERT(size >= ExternalString::kSize);
904 bool is_symbol = this->IsSymbol();
905 int length = this->length();
Steve Blockd0582a62009-12-15 09:54:21 +0000906 int hash_field = this->hash_field();
Steve Blocka7e24c12009-10-30 11:49:00 +0000907
908 // Morph the object to an external string by adjusting the map and
909 // reinitializing the fields.
Steve Block44f0eee2011-05-26 01:26:41 +0100910 this->set_map(heap->external_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000911 ExternalAsciiString* self = ExternalAsciiString::cast(this);
912 self->set_length(length);
Steve Blockd0582a62009-12-15 09:54:21 +0000913 self->set_hash_field(hash_field);
Steve Blocka7e24c12009-10-30 11:49:00 +0000914 self->set_resource(resource);
915 // Additionally make the object into an external symbol if the original string
916 // was a symbol to start with.
917 if (is_symbol) {
918 self->Hash(); // Force regeneration of the hash value.
919 // Now morph this external string into a external symbol.
Steve Block44f0eee2011-05-26 01:26:41 +0100920 this->set_map(heap->external_ascii_symbol_map());
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 }
922
923 // Fill the remainder of the string with dead wood.
924 int new_size = this->Size(); // Byte size of the external String object.
Steve Block44f0eee2011-05-26 01:26:41 +0100925 heap->CreateFillerObjectAt(this->address() + new_size, size - new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +0000926 return true;
927}
928
929
930void String::StringShortPrint(StringStream* accumulator) {
931 int len = length();
Steve Blockd0582a62009-12-15 09:54:21 +0000932 if (len > kMaxShortPrintLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 accumulator->Add("<Very long string[%u]>", len);
934 return;
935 }
936
937 if (!LooksValid()) {
938 accumulator->Add("<Invalid String>");
939 return;
940 }
941
942 StringInputBuffer buf(this);
943
944 bool truncated = false;
945 if (len > kMaxShortPrintLength) {
946 len = kMaxShortPrintLength;
947 truncated = true;
948 }
949 bool ascii = true;
950 for (int i = 0; i < len; i++) {
951 int c = buf.GetNext();
952
953 if (c < 32 || c >= 127) {
954 ascii = false;
955 }
956 }
957 buf.Reset(this);
958 if (ascii) {
959 accumulator->Add("<String[%u]: ", length());
960 for (int i = 0; i < len; i++) {
961 accumulator->Put(buf.GetNext());
962 }
963 accumulator->Put('>');
964 } else {
965 // Backslash indicates that the string contains control
966 // characters and that backslashes are therefore escaped.
967 accumulator->Add("<String[%u]\\: ", length());
968 for (int i = 0; i < len; i++) {
969 int c = buf.GetNext();
970 if (c == '\n') {
971 accumulator->Add("\\n");
972 } else if (c == '\r') {
973 accumulator->Add("\\r");
974 } else if (c == '\\') {
975 accumulator->Add("\\\\");
976 } else if (c < 32 || c > 126) {
977 accumulator->Add("\\x%02x", c);
978 } else {
979 accumulator->Put(c);
980 }
981 }
982 if (truncated) {
983 accumulator->Put('.');
984 accumulator->Put('.');
985 accumulator->Put('.');
986 }
987 accumulator->Put('>');
988 }
989 return;
990}
991
992
993void JSObject::JSObjectShortPrint(StringStream* accumulator) {
994 switch (map()->instance_type()) {
995 case JS_ARRAY_TYPE: {
996 double length = JSArray::cast(this)->length()->Number();
997 accumulator->Add("<JS array[%u]>", static_cast<uint32_t>(length));
998 break;
999 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001000 case JS_WEAK_MAP_TYPE: {
1001 int elements = JSWeakMap::cast(this)->table()->NumberOfElements();
1002 accumulator->Add("<JS WeakMap[%d]>", elements);
1003 break;
1004 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001005 case JS_REGEXP_TYPE: {
1006 accumulator->Add("<JS RegExp>");
1007 break;
1008 }
1009 case JS_FUNCTION_TYPE: {
1010 Object* fun_name = JSFunction::cast(this)->shared()->name();
1011 bool printed = false;
1012 if (fun_name->IsString()) {
1013 String* str = String::cast(fun_name);
1014 if (str->length() > 0) {
1015 accumulator->Add("<JS Function ");
1016 accumulator->Put(str);
1017 accumulator->Put('>');
1018 printed = true;
1019 }
1020 }
1021 if (!printed) {
1022 accumulator->Add("<JS Function>");
1023 }
1024 break;
1025 }
1026 // All other JSObjects are rather similar to each other (JSObject,
1027 // JSGlobalProxy, JSGlobalObject, JSUndetectableObject, JSValue).
1028 default: {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001029 Map* map_of_this = map();
1030 Heap* heap = map_of_this->heap();
1031 Object* constructor = map_of_this->constructor();
Steve Blocka7e24c12009-10-30 11:49:00 +00001032 bool printed = false;
1033 if (constructor->IsHeapObject() &&
Steve Block44f0eee2011-05-26 01:26:41 +01001034 !heap->Contains(HeapObject::cast(constructor))) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 accumulator->Add("!!!INVALID CONSTRUCTOR!!!");
1036 } else {
1037 bool global_object = IsJSGlobalProxy();
1038 if (constructor->IsJSFunction()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001039 if (!heap->Contains(JSFunction::cast(constructor)->shared())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001040 accumulator->Add("!!!INVALID SHARED ON CONSTRUCTOR!!!");
1041 } else {
1042 Object* constructor_name =
1043 JSFunction::cast(constructor)->shared()->name();
1044 if (constructor_name->IsString()) {
1045 String* str = String::cast(constructor_name);
1046 if (str->length() > 0) {
1047 bool vowel = AnWord(str);
1048 accumulator->Add("<%sa%s ",
1049 global_object ? "Global Object: " : "",
1050 vowel ? "n" : "");
1051 accumulator->Put(str);
Ben Murdoch589d6972011-11-30 16:04:58 +00001052 accumulator->Put('>');
Steve Blocka7e24c12009-10-30 11:49:00 +00001053 printed = true;
1054 }
1055 }
1056 }
1057 }
1058 if (!printed) {
1059 accumulator->Add("<JS %sObject", global_object ? "Global " : "");
1060 }
1061 }
1062 if (IsJSValue()) {
1063 accumulator->Add(" value = ");
1064 JSValue::cast(this)->value()->ShortPrint(accumulator);
1065 }
1066 accumulator->Put('>');
1067 break;
1068 }
1069 }
1070}
1071
1072
1073void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
Steve Block44f0eee2011-05-26 01:26:41 +01001074 // if (!HEAP->InNewSpace(this)) PrintF("*", this);
1075 Heap* heap = GetHeap();
1076 if (!heap->Contains(this)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001077 accumulator->Add("!!!INVALID POINTER!!!");
1078 return;
1079 }
Steve Block44f0eee2011-05-26 01:26:41 +01001080 if (!heap->Contains(map())) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001081 accumulator->Add("!!!INVALID MAP!!!");
1082 return;
1083 }
1084
1085 accumulator->Add("%p ", this);
1086
1087 if (IsString()) {
1088 String::cast(this)->StringShortPrint(accumulator);
1089 return;
1090 }
1091 if (IsJSObject()) {
1092 JSObject::cast(this)->JSObjectShortPrint(accumulator);
1093 return;
1094 }
1095 switch (map()->instance_type()) {
1096 case MAP_TYPE:
1097 accumulator->Add("<Map>");
1098 break;
1099 case FIXED_ARRAY_TYPE:
1100 accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
1101 break;
1102 case BYTE_ARRAY_TYPE:
1103 accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
1104 break;
Steve Block44f0eee2011-05-26 01:26:41 +01001105 case EXTERNAL_PIXEL_ARRAY_TYPE:
1106 accumulator->Add("<ExternalPixelArray[%u]>",
1107 ExternalPixelArray::cast(this)->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001108 break;
Steve Block3ce2e202009-11-05 08:53:23 +00001109 case EXTERNAL_BYTE_ARRAY_TYPE:
1110 accumulator->Add("<ExternalByteArray[%u]>",
1111 ExternalByteArray::cast(this)->length());
1112 break;
1113 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1114 accumulator->Add("<ExternalUnsignedByteArray[%u]>",
1115 ExternalUnsignedByteArray::cast(this)->length());
1116 break;
1117 case EXTERNAL_SHORT_ARRAY_TYPE:
1118 accumulator->Add("<ExternalShortArray[%u]>",
1119 ExternalShortArray::cast(this)->length());
1120 break;
1121 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1122 accumulator->Add("<ExternalUnsignedShortArray[%u]>",
1123 ExternalUnsignedShortArray::cast(this)->length());
1124 break;
1125 case EXTERNAL_INT_ARRAY_TYPE:
1126 accumulator->Add("<ExternalIntArray[%u]>",
1127 ExternalIntArray::cast(this)->length());
1128 break;
1129 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1130 accumulator->Add("<ExternalUnsignedIntArray[%u]>",
1131 ExternalUnsignedIntArray::cast(this)->length());
1132 break;
1133 case EXTERNAL_FLOAT_ARRAY_TYPE:
1134 accumulator->Add("<ExternalFloatArray[%u]>",
1135 ExternalFloatArray::cast(this)->length());
1136 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001137 case EXTERNAL_DOUBLE_ARRAY_TYPE:
1138 accumulator->Add("<ExternalDoubleArray[%u]>",
1139 ExternalDoubleArray::cast(this)->length());
1140 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001141 case SHARED_FUNCTION_INFO_TYPE:
1142 accumulator->Add("<SharedFunctionInfo>");
1143 break;
Steve Block1e0659c2011-05-24 12:43:12 +01001144 case JS_MESSAGE_OBJECT_TYPE:
1145 accumulator->Add("<JSMessageObject>");
1146 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001147#define MAKE_STRUCT_CASE(NAME, Name, name) \
1148 case NAME##_TYPE: \
1149 accumulator->Put('<'); \
1150 accumulator->Add(#Name); \
1151 accumulator->Put('>'); \
1152 break;
1153 STRUCT_LIST(MAKE_STRUCT_CASE)
1154#undef MAKE_STRUCT_CASE
1155 case CODE_TYPE:
1156 accumulator->Add("<Code>");
1157 break;
1158 case ODDBALL_TYPE: {
1159 if (IsUndefined())
1160 accumulator->Add("<undefined>");
1161 else if (IsTheHole())
1162 accumulator->Add("<the hole>");
1163 else if (IsNull())
1164 accumulator->Add("<null>");
1165 else if (IsTrue())
1166 accumulator->Add("<true>");
1167 else if (IsFalse())
1168 accumulator->Add("<false>");
1169 else
1170 accumulator->Add("<Odd Oddball>");
1171 break;
1172 }
1173 case HEAP_NUMBER_TYPE:
1174 accumulator->Add("<Number: ");
1175 HeapNumber::cast(this)->HeapNumberPrint(accumulator);
1176 accumulator->Put('>');
1177 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001178 case JS_PROXY_TYPE:
1179 accumulator->Add("<JSProxy>");
1180 break;
1181 case JS_FUNCTION_PROXY_TYPE:
1182 accumulator->Add("<JSFunctionProxy>");
1183 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001184 case FOREIGN_TYPE:
1185 accumulator->Add("<Foreign>");
Steve Blocka7e24c12009-10-30 11:49:00 +00001186 break;
1187 case JS_GLOBAL_PROPERTY_CELL_TYPE:
1188 accumulator->Add("Cell for ");
1189 JSGlobalPropertyCell::cast(this)->value()->ShortPrint(accumulator);
1190 break;
1191 default:
1192 accumulator->Add("<Other heap object (%d)>", map()->instance_type());
1193 break;
1194 }
1195}
1196
1197
Steve Blocka7e24c12009-10-30 11:49:00 +00001198void HeapObject::Iterate(ObjectVisitor* v) {
1199 // Handle header
1200 IteratePointer(v, kMapOffset);
1201 // Handle object body
1202 Map* m = map();
1203 IterateBody(m->instance_type(), SizeFromMap(m), v);
1204}
1205
1206
1207void HeapObject::IterateBody(InstanceType type, int object_size,
1208 ObjectVisitor* v) {
1209 // Avoiding <Type>::cast(this) because it accesses the map pointer field.
1210 // During GC, the map pointer field is encoded.
1211 if (type < FIRST_NONSTRING_TYPE) {
1212 switch (type & kStringRepresentationMask) {
1213 case kSeqStringTag:
1214 break;
1215 case kConsStringTag:
Iain Merrick75681382010-08-19 15:07:18 +01001216 ConsString::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001217 break;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001218 case kSlicedStringTag:
1219 SlicedString::BodyDescriptor::IterateBody(this, v);
1220 break;
Steve Blockd0582a62009-12-15 09:54:21 +00001221 case kExternalStringTag:
1222 if ((type & kStringEncodingMask) == kAsciiStringTag) {
1223 reinterpret_cast<ExternalAsciiString*>(this)->
1224 ExternalAsciiStringIterateBody(v);
1225 } else {
1226 reinterpret_cast<ExternalTwoByteString*>(this)->
1227 ExternalTwoByteStringIterateBody(v);
1228 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001229 break;
1230 }
1231 return;
1232 }
1233
1234 switch (type) {
1235 case FIXED_ARRAY_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001236 FixedArray::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001237 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001238 case FIXED_DOUBLE_ARRAY_TYPE:
1239 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 case JS_OBJECT_TYPE:
1241 case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
1242 case JS_VALUE_TYPE:
1243 case JS_ARRAY_TYPE:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001244 case JS_WEAK_MAP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001245 case JS_REGEXP_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001246 case JS_GLOBAL_PROXY_TYPE:
1247 case JS_GLOBAL_OBJECT_TYPE:
1248 case JS_BUILTINS_OBJECT_TYPE:
Steve Block1e0659c2011-05-24 12:43:12 +01001249 case JS_MESSAGE_OBJECT_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001250 JSObject::BodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 break;
Steve Block791712a2010-08-27 10:21:07 +01001252 case JS_FUNCTION_TYPE:
1253 reinterpret_cast<JSFunction*>(this)
1254 ->JSFunctionIterateBody(object_size, v);
1255 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001256 case ODDBALL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001257 Oddball::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001258 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001259 case JS_PROXY_TYPE:
1260 JSProxy::BodyDescriptor::IterateBody(this, v);
1261 break;
Ben Murdoch589d6972011-11-30 16:04:58 +00001262 case JS_FUNCTION_PROXY_TYPE:
1263 JSFunctionProxy::BodyDescriptor::IterateBody(this, v);
1264 break;
Ben Murdoch257744e2011-11-30 15:57:28 +00001265 case FOREIGN_TYPE:
1266 reinterpret_cast<Foreign*>(this)->ForeignIterateBody(v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001267 break;
1268 case MAP_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001269 Map::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001270 break;
1271 case CODE_TYPE:
1272 reinterpret_cast<Code*>(this)->CodeIterateBody(v);
1273 break;
1274 case JS_GLOBAL_PROPERTY_CELL_TYPE:
Iain Merrick75681382010-08-19 15:07:18 +01001275 JSGlobalPropertyCell::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001276 break;
1277 case HEAP_NUMBER_TYPE:
1278 case FILLER_TYPE:
1279 case BYTE_ARRAY_TYPE:
Steve Block44f0eee2011-05-26 01:26:41 +01001280 case EXTERNAL_PIXEL_ARRAY_TYPE:
Steve Block3ce2e202009-11-05 08:53:23 +00001281 case EXTERNAL_BYTE_ARRAY_TYPE:
1282 case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
1283 case EXTERNAL_SHORT_ARRAY_TYPE:
1284 case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
1285 case EXTERNAL_INT_ARRAY_TYPE:
1286 case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
1287 case EXTERNAL_FLOAT_ARRAY_TYPE:
Ben Murdoch257744e2011-11-30 15:57:28 +00001288 case EXTERNAL_DOUBLE_ARRAY_TYPE:
Steve Blocka7e24c12009-10-30 11:49:00 +00001289 break;
Iain Merrick75681382010-08-19 15:07:18 +01001290 case SHARED_FUNCTION_INFO_TYPE:
1291 SharedFunctionInfo::BodyDescriptor::IterateBody(this, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001292 break;
Iain Merrick75681382010-08-19 15:07:18 +01001293
Steve Blocka7e24c12009-10-30 11:49:00 +00001294#define MAKE_STRUCT_CASE(NAME, Name, name) \
1295 case NAME##_TYPE:
1296 STRUCT_LIST(MAKE_STRUCT_CASE)
1297#undef MAKE_STRUCT_CASE
Iain Merrick75681382010-08-19 15:07:18 +01001298 StructBodyDescriptor::IterateBody(this, object_size, v);
Steve Blocka7e24c12009-10-30 11:49:00 +00001299 break;
1300 default:
1301 PrintF("Unknown type: %d\n", type);
1302 UNREACHABLE();
1303 }
1304}
1305
1306
Steve Blocka7e24c12009-10-30 11:49:00 +00001307Object* HeapNumber::HeapNumberToBoolean() {
1308 // NaN, +0, and -0 should return the false object
Iain Merrick75681382010-08-19 15:07:18 +01001309#if __BYTE_ORDER == __LITTLE_ENDIAN
1310 union IeeeDoubleLittleEndianArchType u;
1311#elif __BYTE_ORDER == __BIG_ENDIAN
1312 union IeeeDoubleBigEndianArchType u;
1313#endif
1314 u.d = value();
1315 if (u.bits.exp == 2047) {
1316 // Detect NaN for IEEE double precision floating point.
1317 if ((u.bits.man_low | u.bits.man_high) != 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001318 return GetHeap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001319 }
Iain Merrick75681382010-08-19 15:07:18 +01001320 if (u.bits.exp == 0) {
1321 // Detect +0, and -0 for IEEE double precision floating point.
1322 if ((u.bits.man_low | u.bits.man_high) == 0)
Steve Block44f0eee2011-05-26 01:26:41 +01001323 return GetHeap()->false_value();
Iain Merrick75681382010-08-19 15:07:18 +01001324 }
Steve Block44f0eee2011-05-26 01:26:41 +01001325 return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001326}
1327
1328
Ben Murdochb0fe1622011-05-05 13:52:32 +01001329void HeapNumber::HeapNumberPrint(FILE* out) {
1330 PrintF(out, "%.16g", Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00001331}
1332
1333
1334void HeapNumber::HeapNumberPrint(StringStream* accumulator) {
1335 // The Windows version of vsnprintf can allocate when printing a %g string
1336 // into a buffer that may not be big enough. We don't want random memory
1337 // allocation when producing post-crash stack traces, so we print into a
1338 // buffer that is plenty big enough for any floating point number, then
1339 // print that using vsnprintf (which may truncate but never allocate if
1340 // there is no more space in the buffer).
1341 EmbeddedVector<char, 100> buffer;
1342 OS::SNPrintF(buffer, "%.16g", Number());
1343 accumulator->Add("%s", buffer.start());
1344}
1345
1346
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001347String* JSReceiver::class_name() {
1348 if (IsJSFunction() && IsJSFunctionProxy()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001349 return GetHeap()->function_class_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 }
1351 if (map()->constructor()->IsJSFunction()) {
1352 JSFunction* constructor = JSFunction::cast(map()->constructor());
1353 return String::cast(constructor->shared()->instance_class_name());
1354 }
1355 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001356 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001357}
1358
1359
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001360String* JSReceiver::constructor_name() {
Steve Blocka7e24c12009-10-30 11:49:00 +00001361 if (map()->constructor()->IsJSFunction()) {
1362 JSFunction* constructor = JSFunction::cast(map()->constructor());
1363 String* name = String::cast(constructor->shared()->name());
Ben Murdochf87a2032010-10-22 12:50:53 +01001364 if (name->length() > 0) return name;
1365 String* inferred_name = constructor->shared()->inferred_name();
1366 if (inferred_name->length() > 0) return inferred_name;
1367 Object* proto = GetPrototype();
1368 if (proto->IsJSObject()) return JSObject::cast(proto)->constructor_name();
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001370 // TODO(rossberg): what about proxies?
Steve Blocka7e24c12009-10-30 11:49:00 +00001371 // If the constructor is not present, return "Object".
Steve Block44f0eee2011-05-26 01:26:41 +01001372 return GetHeap()->Object_symbol();
Steve Blocka7e24c12009-10-30 11:49:00 +00001373}
1374
1375
John Reck59135872010-11-02 12:39:01 -07001376MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map,
1377 String* name,
1378 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001379 int index = new_map->PropertyIndexFor(name);
1380 if (map()->unused_property_fields() == 0) {
1381 ASSERT(map()->unused_property_fields() == 0);
1382 int new_unused = new_map->unused_property_fields();
John Reck59135872010-11-02 12:39:01 -07001383 Object* values;
1384 { MaybeObject* maybe_values =
1385 properties()->CopySize(properties()->length() + new_unused + 1);
1386 if (!maybe_values->ToObject(&values)) return maybe_values;
1387 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001388 set_properties(FixedArray::cast(values));
1389 }
1390 set_map(new_map);
1391 return FastPropertyAtPut(index, value);
1392}
1393
1394
Ben Murdoch8b112d22011-06-08 16:22:53 +01001395static bool IsIdentifier(UnicodeCache* cache,
1396 unibrow::CharacterStream* buffer) {
1397 // Checks whether the buffer contains an identifier (no escape).
1398 if (!buffer->has_more()) return false;
1399 if (!cache->IsIdentifierStart(buffer->GetNext())) {
1400 return false;
1401 }
1402 while (buffer->has_more()) {
1403 if (!cache->IsIdentifierPart(buffer->GetNext())) {
1404 return false;
1405 }
1406 }
1407 return true;
1408}
1409
1410
John Reck59135872010-11-02 12:39:01 -07001411MaybeObject* JSObject::AddFastProperty(String* name,
1412 Object* value,
1413 PropertyAttributes attributes) {
Steve Block1e0659c2011-05-24 12:43:12 +01001414 ASSERT(!IsJSGlobalProxy());
1415
Steve Blocka7e24c12009-10-30 11:49:00 +00001416 // Normalize the object if the name is an actual string (not the
1417 // hidden symbols) and is not a real identifier.
Steve Block44f0eee2011-05-26 01:26:41 +01001418 Isolate* isolate = GetHeap()->isolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00001419 StringInputBuffer buffer(name);
Ben Murdoch8b112d22011-06-08 16:22:53 +01001420 if (!IsIdentifier(isolate->unicode_cache(), &buffer)
Steve Block44f0eee2011-05-26 01:26:41 +01001421 && name != isolate->heap()->hidden_symbol()) {
John Reck59135872010-11-02 12:39:01 -07001422 Object* obj;
1423 { MaybeObject* maybe_obj =
1424 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1425 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1426 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001427 return AddSlowProperty(name, value, attributes);
1428 }
1429
1430 DescriptorArray* old_descriptors = map()->instance_descriptors();
1431 // Compute the new index for new field.
1432 int index = map()->NextFreePropertyIndex();
1433
1434 // Allocate new instance descriptors with (name, index) added
1435 FieldDescriptor new_field(name, index, attributes);
John Reck59135872010-11-02 12:39:01 -07001436 Object* new_descriptors;
1437 { MaybeObject* maybe_new_descriptors =
1438 old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
1439 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1440 return maybe_new_descriptors;
1441 }
1442 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001443
Steve Block44f0eee2011-05-26 01:26:41 +01001444 // Only allow map transition if the object isn't the global object and there
1445 // is not a transition for the name, or there's a transition for the name but
1446 // it's unrelated to properties.
1447 int descriptor_index = old_descriptors->Search(name);
1448
Ben Murdoch589d6972011-11-30 16:04:58 +00001449 // Element transitions are stored in the descriptor for property "", which is
1450 // not a identifier and should have forced a switch to slow properties above.
Steve Block44f0eee2011-05-26 01:26:41 +01001451 ASSERT(descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001452 old_descriptors->GetType(descriptor_index) != ELEMENTS_TRANSITION);
Steve Block44f0eee2011-05-26 01:26:41 +01001453 bool can_insert_transition = descriptor_index == DescriptorArray::kNotFound ||
Ben Murdoch589d6972011-11-30 16:04:58 +00001454 old_descriptors->GetType(descriptor_index) == ELEMENTS_TRANSITION;
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 bool allow_map_transition =
Steve Block44f0eee2011-05-26 01:26:41 +01001456 can_insert_transition &&
1457 (isolate->context()->global_context()->object_function()->map() != map());
Steve Blocka7e24c12009-10-30 11:49:00 +00001458
1459 ASSERT(index < map()->inobject_properties() ||
1460 (index - map()->inobject_properties()) < properties()->length() ||
1461 map()->unused_property_fields() == 0);
1462 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001463 Object* r;
1464 { MaybeObject* maybe_r = map()->CopyDropDescriptors();
1465 if (!maybe_r->ToObject(&r)) return maybe_r;
1466 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001467 Map* new_map = Map::cast(r);
1468 if (allow_map_transition) {
1469 // Allocate new instance descriptors for the old map with map transition.
1470 MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
John Reck59135872010-11-02 12:39:01 -07001471 Object* r;
1472 { MaybeObject* maybe_r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
1473 if (!maybe_r->ToObject(&r)) return maybe_r;
1474 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001475 old_descriptors = DescriptorArray::cast(r);
1476 }
1477
1478 if (map()->unused_property_fields() == 0) {
Steve Block8defd9f2010-07-08 12:39:36 +01001479 if (properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001480 Object* obj;
1481 { MaybeObject* maybe_obj =
1482 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1483 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1484 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 return AddSlowProperty(name, value, attributes);
1486 }
1487 // Make room for the new value
John Reck59135872010-11-02 12:39:01 -07001488 Object* values;
1489 { MaybeObject* maybe_values =
1490 properties()->CopySize(properties()->length() + kFieldsAdded);
1491 if (!maybe_values->ToObject(&values)) return maybe_values;
1492 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001493 set_properties(FixedArray::cast(values));
1494 new_map->set_unused_property_fields(kFieldsAdded - 1);
1495 } else {
1496 new_map->set_unused_property_fields(map()->unused_property_fields() - 1);
1497 }
1498 // We have now allocated all the necessary objects.
1499 // All the changes can be applied at once, so they are atomic.
1500 map()->set_instance_descriptors(old_descriptors);
1501 new_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1502 set_map(new_map);
1503 return FastPropertyAtPut(index, value);
1504}
1505
1506
John Reck59135872010-11-02 12:39:01 -07001507MaybeObject* JSObject::AddConstantFunctionProperty(
1508 String* name,
1509 JSFunction* function,
1510 PropertyAttributes attributes) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01001511 ASSERT(!GetHeap()->InNewSpace(function));
Leon Clarkee46be812010-01-19 14:06:41 +00001512
Steve Blocka7e24c12009-10-30 11:49:00 +00001513 // Allocate new instance descriptors with (name, function) added
1514 ConstantFunctionDescriptor d(name, function, attributes);
John Reck59135872010-11-02 12:39:01 -07001515 Object* new_descriptors;
1516 { MaybeObject* maybe_new_descriptors =
1517 map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
1518 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1519 return maybe_new_descriptors;
1520 }
1521 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001522
1523 // Allocate a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001524 Object* new_map;
1525 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
1526 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1527 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001528
1529 DescriptorArray* descriptors = DescriptorArray::cast(new_descriptors);
1530 Map::cast(new_map)->set_instance_descriptors(descriptors);
1531 Map* old_map = map();
1532 set_map(Map::cast(new_map));
1533
1534 // If the old map is the global object map (from new Object()),
1535 // then transitions are not added to it, so we are done.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001536 Heap* heap = old_map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01001537 if (old_map == heap->isolate()->context()->global_context()->
1538 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001539 return function;
1540 }
1541
1542 // Do not add CONSTANT_TRANSITIONS to global objects
1543 if (IsGlobalObject()) {
1544 return function;
1545 }
1546
1547 // Add a CONSTANT_TRANSITION descriptor to the old map,
1548 // so future assignments to this property on other objects
1549 // of the same type will create a normal field, not a constant function.
1550 // Don't do this for special properties, with non-trival attributes.
1551 if (attributes != NONE) {
1552 return function;
1553 }
Iain Merrick75681382010-08-19 15:07:18 +01001554 ConstTransitionDescriptor mark(name, Map::cast(new_map));
John Reck59135872010-11-02 12:39:01 -07001555 { MaybeObject* maybe_new_descriptors =
1556 old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
1557 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1558 // We have accomplished the main goal, so return success.
1559 return function;
1560 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001561 }
1562 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1563
1564 return function;
1565}
1566
1567
1568// Add property in slow mode
John Reck59135872010-11-02 12:39:01 -07001569MaybeObject* JSObject::AddSlowProperty(String* name,
1570 Object* value,
1571 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001572 ASSERT(!HasFastProperties());
1573 StringDictionary* dict = property_dictionary();
1574 Object* store_value = value;
1575 if (IsGlobalObject()) {
1576 // In case name is an orphaned property reuse the cell.
1577 int entry = dict->FindEntry(name);
1578 if (entry != StringDictionary::kNotFound) {
1579 store_value = dict->ValueAt(entry);
1580 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1581 // Assign an enumeration index to the property and update
1582 // SetNextEnumerationIndex.
1583 int index = dict->NextEnumerationIndex();
1584 PropertyDetails details = PropertyDetails(attributes, NORMAL, index);
1585 dict->SetNextEnumerationIndex(index + 1);
1586 dict->SetEntry(entry, name, store_value, details);
1587 return value;
1588 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001589 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07001590 { MaybeObject* maybe_store_value =
Steve Block44f0eee2011-05-26 01:26:41 +01001591 heap->AllocateJSGlobalPropertyCell(value);
John Reck59135872010-11-02 12:39:01 -07001592 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value;
1593 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001594 JSGlobalPropertyCell::cast(store_value)->set_value(value);
1595 }
1596 PropertyDetails details = PropertyDetails(attributes, NORMAL);
John Reck59135872010-11-02 12:39:01 -07001597 Object* result;
1598 { MaybeObject* maybe_result = dict->Add(name, store_value, details);
1599 if (!maybe_result->ToObject(&result)) return maybe_result;
1600 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001601 if (dict != result) set_properties(StringDictionary::cast(result));
1602 return value;
1603}
1604
1605
John Reck59135872010-11-02 12:39:01 -07001606MaybeObject* JSObject::AddProperty(String* name,
1607 Object* value,
Steve Block44f0eee2011-05-26 01:26:41 +01001608 PropertyAttributes attributes,
1609 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001610 ASSERT(!IsJSGlobalProxy());
Ben Murdoch8b112d22011-06-08 16:22:53 +01001611 Map* map_of_this = map();
1612 Heap* heap = map_of_this->heap();
1613 if (!map_of_this->is_extensible()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001614 if (strict_mode == kNonStrictMode) {
1615 return heap->undefined_value();
1616 } else {
1617 Handle<Object> args[1] = {Handle<String>(name)};
1618 return heap->isolate()->Throw(
1619 *FACTORY->NewTypeError("object_not_extensible",
1620 HandleVector(args, 1)));
1621 }
Steve Block8defd9f2010-07-08 12:39:36 +01001622 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001623 if (HasFastProperties()) {
1624 // Ensure the descriptor array does not get too big.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001625 if (map_of_this->instance_descriptors()->number_of_descriptors() <
Steve Blocka7e24c12009-10-30 11:49:00 +00001626 DescriptorArray::kMaxNumberOfDescriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01001627 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001628 return AddConstantFunctionProperty(name,
1629 JSFunction::cast(value),
1630 attributes);
1631 } else {
1632 return AddFastProperty(name, value, attributes);
1633 }
1634 } else {
1635 // Normalize the object to prevent very large instance descriptors.
1636 // This eliminates unwanted N^2 allocation and lookup behavior.
John Reck59135872010-11-02 12:39:01 -07001637 Object* obj;
1638 { MaybeObject* maybe_obj =
1639 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1640 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1641 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001642 }
1643 }
1644 return AddSlowProperty(name, value, attributes);
1645}
1646
1647
John Reck59135872010-11-02 12:39:01 -07001648MaybeObject* JSObject::SetPropertyPostInterceptor(
1649 String* name,
1650 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001651 PropertyAttributes attributes,
1652 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001653 // Check local property, ignore interceptor.
1654 LookupResult result;
1655 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001656 if (result.IsFound()) {
1657 // An existing property, a map transition or a null descriptor was
1658 // found. Use set property to handle all these cases.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001659 return SetProperty(&result, name, value, attributes, strict_mode);
Andrei Popescu402d9372010-02-26 13:31:12 +00001660 }
1661 // Add a new real property.
Steve Block44f0eee2011-05-26 01:26:41 +01001662 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001663}
1664
1665
John Reck59135872010-11-02 12:39:01 -07001666MaybeObject* JSObject::ReplaceSlowProperty(String* name,
1667 Object* value,
1668 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001669 StringDictionary* dictionary = property_dictionary();
1670 int old_index = dictionary->FindEntry(name);
1671 int new_enumeration_index = 0; // 0 means "Use the next available index."
1672 if (old_index != -1) {
1673 // All calls to ReplaceSlowProperty have had all transitions removed.
1674 ASSERT(!dictionary->DetailsAt(old_index).IsTransition());
1675 new_enumeration_index = dictionary->DetailsAt(old_index).index();
1676 }
1677
1678 PropertyDetails new_details(attributes, NORMAL, new_enumeration_index);
1679 return SetNormalizedProperty(name, value, new_details);
1680}
1681
Steve Blockd0582a62009-12-15 09:54:21 +00001682
John Reck59135872010-11-02 12:39:01 -07001683MaybeObject* JSObject::ConvertDescriptorToFieldAndMapTransition(
Steve Blocka7e24c12009-10-30 11:49:00 +00001684 String* name,
1685 Object* new_value,
1686 PropertyAttributes attributes) {
1687 Map* old_map = map();
John Reck59135872010-11-02 12:39:01 -07001688 Object* result;
1689 { MaybeObject* maybe_result =
1690 ConvertDescriptorToField(name, new_value, attributes);
1691 if (!maybe_result->ToObject(&result)) return maybe_result;
1692 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001693 // If we get to this point we have succeeded - do not return failure
1694 // after this point. Later stuff is optional.
1695 if (!HasFastProperties()) {
1696 return result;
1697 }
1698 // Do not add transitions to the map of "new Object()".
Ben Murdoch8b112d22011-06-08 16:22:53 +01001699 if (map() == old_map->heap()->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01001700 object_function()->map()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001701 return result;
1702 }
1703
1704 MapTransitionDescriptor transition(name,
1705 map(),
1706 attributes);
John Reck59135872010-11-02 12:39:01 -07001707 Object* new_descriptors;
1708 { MaybeObject* maybe_new_descriptors = old_map->instance_descriptors()->
1709 CopyInsert(&transition, KEEP_TRANSITIONS);
1710 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
1711 return result; // Yes, return _result_.
1712 }
1713 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001714 old_map->set_instance_descriptors(DescriptorArray::cast(new_descriptors));
1715 return result;
1716}
1717
1718
John Reck59135872010-11-02 12:39:01 -07001719MaybeObject* JSObject::ConvertDescriptorToField(String* name,
1720 Object* new_value,
1721 PropertyAttributes attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001722 if (map()->unused_property_fields() == 0 &&
Steve Block8defd9f2010-07-08 12:39:36 +01001723 properties()->length() > MaxFastProperties()) {
John Reck59135872010-11-02 12:39:01 -07001724 Object* obj;
1725 { MaybeObject* maybe_obj =
1726 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
1727 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1728 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001729 return ReplaceSlowProperty(name, new_value, attributes);
1730 }
1731
1732 int index = map()->NextFreePropertyIndex();
1733 FieldDescriptor new_field(name, index, attributes);
1734 // Make a new DescriptorArray replacing an entry with FieldDescriptor.
John Reck59135872010-11-02 12:39:01 -07001735 Object* descriptors_unchecked;
1736 { MaybeObject* maybe_descriptors_unchecked = map()->instance_descriptors()->
1737 CopyInsert(&new_field, REMOVE_TRANSITIONS);
1738 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
1739 return maybe_descriptors_unchecked;
1740 }
1741 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001742 DescriptorArray* new_descriptors =
1743 DescriptorArray::cast(descriptors_unchecked);
1744
1745 // Make a new map for the object.
John Reck59135872010-11-02 12:39:01 -07001746 Object* new_map_unchecked;
1747 { MaybeObject* maybe_new_map_unchecked = map()->CopyDropDescriptors();
1748 if (!maybe_new_map_unchecked->ToObject(&new_map_unchecked)) {
1749 return maybe_new_map_unchecked;
1750 }
1751 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001752 Map* new_map = Map::cast(new_map_unchecked);
1753 new_map->set_instance_descriptors(new_descriptors);
1754
1755 // Make new properties array if necessary.
1756 FixedArray* new_properties = 0; // Will always be NULL or a valid pointer.
1757 int new_unused_property_fields = map()->unused_property_fields() - 1;
1758 if (map()->unused_property_fields() == 0) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001759 new_unused_property_fields = kFieldsAdded - 1;
John Reck59135872010-11-02 12:39:01 -07001760 Object* new_properties_object;
1761 { MaybeObject* maybe_new_properties_object =
1762 properties()->CopySize(properties()->length() + kFieldsAdded);
1763 if (!maybe_new_properties_object->ToObject(&new_properties_object)) {
1764 return maybe_new_properties_object;
1765 }
1766 }
1767 new_properties = FixedArray::cast(new_properties_object);
Steve Blocka7e24c12009-10-30 11:49:00 +00001768 }
1769
1770 // Update pointers to commit changes.
1771 // Object points to the new map.
1772 new_map->set_unused_property_fields(new_unused_property_fields);
1773 set_map(new_map);
1774 if (new_properties) {
1775 set_properties(FixedArray::cast(new_properties));
1776 }
1777 return FastPropertyAtPut(index, new_value);
1778}
1779
1780
1781
John Reck59135872010-11-02 12:39:01 -07001782MaybeObject* JSObject::SetPropertyWithInterceptor(
1783 String* name,
1784 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001785 PropertyAttributes attributes,
1786 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001787 Isolate* isolate = GetIsolate();
1788 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001789 Handle<JSObject> this_handle(this);
1790 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001791 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001792 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
1793 if (!interceptor->setter()->IsUndefined()) {
Steve Block44f0eee2011-05-26 01:26:41 +01001794 LOG(isolate, ApiNamedPropertyAccess("interceptor-named-set", this, name));
1795 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00001796 v8::AccessorInfo info(args.end());
1797 v8::NamedPropertySetter setter =
1798 v8::ToCData<v8::NamedPropertySetter>(interceptor->setter());
1799 v8::Handle<v8::Value> result;
1800 {
1801 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001802 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001803 Handle<Object> value_unhole(value->IsTheHole() ?
Steve Block44f0eee2011-05-26 01:26:41 +01001804 isolate->heap()->undefined_value() :
1805 value,
1806 isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001807 result = setter(v8::Utils::ToLocal(name_handle),
1808 v8::Utils::ToLocal(value_unhole),
1809 info);
1810 }
Steve Block44f0eee2011-05-26 01:26:41 +01001811 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001812 if (!result.IsEmpty()) return *value_handle;
1813 }
John Reck59135872010-11-02 12:39:01 -07001814 MaybeObject* raw_result =
1815 this_handle->SetPropertyPostInterceptor(*name_handle,
1816 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001817 attributes,
1818 strict_mode);
Steve Block44f0eee2011-05-26 01:26:41 +01001819 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001820 return raw_result;
1821}
1822
1823
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001824MaybeObject* JSReceiver::SetProperty(String* name,
1825 Object* value,
1826 PropertyAttributes attributes,
1827 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001828 LookupResult result;
1829 LocalLookup(name, &result);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01001830 return SetProperty(&result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001831}
1832
1833
John Reck59135872010-11-02 12:39:01 -07001834MaybeObject* JSObject::SetPropertyWithCallback(Object* structure,
1835 String* name,
1836 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001837 JSObject* holder,
1838 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001839 Isolate* isolate = GetIsolate();
1840 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001841
1842 // We should never get here to initialize a const with the hole
1843 // value since a const declaration would conflict with the setter.
1844 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01001845 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001846
1847 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00001848 // data structure used to store the callbacks. Eventually foreign
Steve Blocka7e24c12009-10-30 11:49:00 +00001849 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00001850 if (structure->IsForeign()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001851 AccessorDescriptor* callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00001852 reinterpret_cast<AccessorDescriptor*>(
1853 Foreign::cast(structure)->address());
John Reck59135872010-11-02 12:39:01 -07001854 MaybeObject* obj = (callback->setter)(this, value, callback->data);
Steve Block44f0eee2011-05-26 01:26:41 +01001855 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001856 if (obj->IsFailure()) return obj;
1857 return *value_handle;
1858 }
1859
1860 if (structure->IsAccessorInfo()) {
1861 // api style callbacks
1862 AccessorInfo* data = AccessorInfo::cast(structure);
1863 Object* call_obj = data->setter();
1864 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
1865 if (call_fun == NULL) return value;
1866 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001867 LOG(isolate, ApiNamedPropertyAccess("store", this, name));
1868 CustomArguments args(isolate, data->data(), this, JSObject::cast(holder));
Steve Blocka7e24c12009-10-30 11:49:00 +00001869 v8::AccessorInfo info(args.end());
1870 {
1871 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01001872 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00001873 call_fun(v8::Utils::ToLocal(key),
1874 v8::Utils::ToLocal(value_handle),
1875 info);
1876 }
Steve Block44f0eee2011-05-26 01:26:41 +01001877 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001878 return *value_handle;
1879 }
1880
1881 if (structure->IsFixedArray()) {
1882 Object* setter = FixedArray::cast(structure)->get(kSetterIndex);
1883 if (setter->IsJSFunction()) {
1884 return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value);
1885 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001886 if (strict_mode == kNonStrictMode) {
1887 return value;
1888 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001889 Handle<String> key(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001890 Handle<Object> holder_handle(holder, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001891 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01001892 return isolate->Throw(
1893 *isolate->factory()->NewTypeError("no_setter_in_callback",
1894 HandleVector(args, 2)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001895 }
1896 }
1897
1898 UNREACHABLE();
Leon Clarkef7060e22010-06-03 12:02:55 +01001899 return NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001900}
1901
1902
John Reck59135872010-11-02 12:39:01 -07001903MaybeObject* JSObject::SetPropertyWithDefinedSetter(JSFunction* setter,
1904 Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +01001905 Isolate* isolate = GetIsolate();
1906 Handle<Object> value_handle(value, isolate);
1907 Handle<JSFunction> fun(JSFunction::cast(setter), isolate);
1908 Handle<JSObject> self(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00001909#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Block44f0eee2011-05-26 01:26:41 +01001910 Debug* debug = isolate->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00001911 // Handle stepping into a setter if step into is active.
Steve Block44f0eee2011-05-26 01:26:41 +01001912 if (debug->StepInActive()) {
1913 debug->HandleStepIn(fun, Handle<Object>::null(), 0, false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001914 }
1915#endif
1916 bool has_pending_exception;
1917 Object** argv[] = { value_handle.location() };
1918 Execution::Call(fun, self, 1, argv, &has_pending_exception);
1919 // Check for pending exception and return the result.
1920 if (has_pending_exception) return Failure::Exception();
1921 return *value_handle;
1922}
1923
1924
1925void JSObject::LookupCallbackSetterInPrototypes(String* name,
1926 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01001927 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001928 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001929 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001930 pt = pt->GetPrototype()) {
1931 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00001932 if (result->IsProperty()) {
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01001933 if (result->type() == CALLBACKS && !result->IsReadOnly()) return;
1934 // Found non-callback or read-only callback, stop looking.
1935 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001936 }
1937 }
1938 result->NotFound();
1939}
1940
1941
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001942MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
1943 uint32_t index,
1944 Object* value,
1945 bool* found,
1946 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01001947 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00001948 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01001949 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001950 pt = pt->GetPrototype()) {
1951 if (!JSObject::cast(pt)->HasDictionaryElements()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001952 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +00001953 }
1954 NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary();
1955 int entry = dictionary->FindEntry(index);
1956 if (entry != NumberDictionary::kNotFound) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001957 PropertyDetails details = dictionary->DetailsAt(entry);
1958 if (details.type() == CALLBACKS) {
Steve Block1e0659c2011-05-24 12:43:12 +01001959 *found = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001960 return SetElementWithCallback(dictionary->ValueAt(entry),
1961 index,
1962 value,
1963 JSObject::cast(pt),
1964 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00001965 }
1966 }
1967 }
Steve Block1e0659c2011-05-24 12:43:12 +01001968 *found = false;
Steve Block44f0eee2011-05-26 01:26:41 +01001969 return heap->the_hole_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001970}
1971
1972
1973void JSObject::LookupInDescriptor(String* name, LookupResult* result) {
1974 DescriptorArray* descriptors = map()->instance_descriptors();
Iain Merrick75681382010-08-19 15:07:18 +01001975 int number = descriptors->SearchWithCache(name);
Steve Blocka7e24c12009-10-30 11:49:00 +00001976 if (number != DescriptorArray::kNotFound) {
1977 result->DescriptorResult(this, descriptors->GetDetails(number), number);
1978 } else {
1979 result->NotFound();
1980 }
1981}
1982
1983
Ben Murdochb0fe1622011-05-05 13:52:32 +01001984void Map::LookupInDescriptors(JSObject* holder,
1985 String* name,
1986 LookupResult* result) {
1987 DescriptorArray* descriptors = instance_descriptors();
Steve Block44f0eee2011-05-26 01:26:41 +01001988 DescriptorLookupCache* cache = heap()->isolate()->descriptor_lookup_cache();
1989 int number = cache->Lookup(descriptors, name);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001990 if (number == DescriptorLookupCache::kAbsent) {
1991 number = descriptors->Search(name);
Steve Block44f0eee2011-05-26 01:26:41 +01001992 cache->Update(descriptors, name, number);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001993 }
1994 if (number != DescriptorArray::kNotFound) {
1995 result->DescriptorResult(holder, descriptors->GetDetails(number), number);
1996 } else {
1997 result->NotFound();
1998 }
1999}
2000
2001
Ben Murdoch589d6972011-11-30 16:04:58 +00002002MaybeObject* Map::GetElementsTransitionMap(ElementsKind elements_kind,
2003 bool safe_to_add_transition) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002004 Heap* current_heap = heap();
Steve Block44f0eee2011-05-26 01:26:41 +01002005 DescriptorArray* descriptors = instance_descriptors();
Ben Murdoch589d6972011-11-30 16:04:58 +00002006 String* elements_transition_sentinel_name = current_heap->empty_symbol();
Steve Block44f0eee2011-05-26 01:26:41 +01002007
2008 if (safe_to_add_transition) {
2009 // It's only safe to manipulate the descriptor array if it would be
2010 // safe to add a transition.
2011
2012 ASSERT(!is_shared()); // no transitions can be added to shared maps.
Ben Murdoch589d6972011-11-30 16:04:58 +00002013 // Check if the elements transition already exists.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002014 DescriptorLookupCache* cache =
2015 current_heap->isolate()->descriptor_lookup_cache();
Ben Murdoch589d6972011-11-30 16:04:58 +00002016 int index = cache->Lookup(descriptors, elements_transition_sentinel_name);
Steve Block44f0eee2011-05-26 01:26:41 +01002017 if (index == DescriptorLookupCache::kAbsent) {
Ben Murdoch589d6972011-11-30 16:04:58 +00002018 index = descriptors->Search(elements_transition_sentinel_name);
Steve Block44f0eee2011-05-26 01:26:41 +01002019 cache->Update(descriptors,
Ben Murdoch589d6972011-11-30 16:04:58 +00002020 elements_transition_sentinel_name,
Steve Block44f0eee2011-05-26 01:26:41 +01002021 index);
2022 }
2023
2024 // If the transition already exists, check the type. If there is a match,
2025 // return it.
2026 if (index != DescriptorArray::kNotFound) {
2027 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index)));
Ben Murdoch589d6972011-11-30 16:04:58 +00002028 if (details.type() == ELEMENTS_TRANSITION &&
2029 details.elements_kind() == elements_kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01002030 return descriptors->GetValue(index);
2031 } else {
2032 safe_to_add_transition = false;
2033 }
2034 }
2035 }
2036
Ben Murdoch589d6972011-11-30 16:04:58 +00002037 // No transition to an existing map for the given ElementsKind. Make a new
2038 // one.
Steve Block44f0eee2011-05-26 01:26:41 +01002039 Object* obj;
2040 { MaybeObject* maybe_map = CopyDropTransitions();
2041 if (!maybe_map->ToObject(&obj)) return maybe_map;
2042 }
2043 Map* new_map = Map::cast(obj);
2044
Ben Murdoch589d6972011-11-30 16:04:58 +00002045 new_map->set_elements_kind(elements_kind);
Steve Block44f0eee2011-05-26 01:26:41 +01002046 GetIsolate()->counters()->map_to_external_array_elements()->Increment();
2047
2048 // Only remember the map transition if the object's map is NOT equal to the
2049 // global object_function's map and there is not an already existing
Ben Murdoch589d6972011-11-30 16:04:58 +00002050 // non-matching element transition.
Steve Block44f0eee2011-05-26 01:26:41 +01002051 bool allow_map_transition =
2052 safe_to_add_transition &&
2053 (GetIsolate()->context()->global_context()->object_function()->map() !=
2054 map());
2055 if (allow_map_transition) {
2056 // Allocate new instance descriptors for the old map with map transition.
Ben Murdoch589d6972011-11-30 16:04:58 +00002057 ElementsTransitionDescriptor desc(elements_transition_sentinel_name,
2058 Map::cast(new_map),
2059 elements_kind);
Steve Block44f0eee2011-05-26 01:26:41 +01002060 Object* new_descriptors;
2061 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert(
2062 &desc,
2063 KEEP_TRANSITIONS);
2064 if (!maybe_new_descriptors->ToObject(&new_descriptors)) {
2065 return maybe_new_descriptors;
2066 }
2067 descriptors = DescriptorArray::cast(new_descriptors);
2068 set_instance_descriptors(descriptors);
2069 }
2070
2071 return new_map;
2072}
2073
2074
Steve Blocka7e24c12009-10-30 11:49:00 +00002075void JSObject::LocalLookupRealNamedProperty(String* name,
2076 LookupResult* result) {
2077 if (IsJSGlobalProxy()) {
2078 Object* proto = GetPrototype();
2079 if (proto->IsNull()) return result->NotFound();
2080 ASSERT(proto->IsJSGlobalObject());
2081 return JSObject::cast(proto)->LocalLookupRealNamedProperty(name, result);
2082 }
2083
2084 if (HasFastProperties()) {
2085 LookupInDescriptor(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002086 if (result->IsFound()) {
2087 // A property, a map transition or a null descriptor was found.
2088 // We return all of these result types because
2089 // LocalLookupRealNamedProperty is used when setting properties
2090 // where map transitions and null descriptors are handled.
Steve Blocka7e24c12009-10-30 11:49:00 +00002091 ASSERT(result->holder() == this && result->type() != NORMAL);
2092 // Disallow caching for uninitialized constants. These can only
2093 // occur as fields.
2094 if (result->IsReadOnly() && result->type() == FIELD &&
2095 FastPropertyAt(result->GetFieldIndex())->IsTheHole()) {
2096 result->DisallowCaching();
2097 }
2098 return;
2099 }
2100 } else {
2101 int entry = property_dictionary()->FindEntry(name);
2102 if (entry != StringDictionary::kNotFound) {
2103 Object* value = property_dictionary()->ValueAt(entry);
2104 if (IsGlobalObject()) {
2105 PropertyDetails d = property_dictionary()->DetailsAt(entry);
2106 if (d.IsDeleted()) {
2107 result->NotFound();
2108 return;
2109 }
2110 value = JSGlobalPropertyCell::cast(value)->value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002111 }
2112 // Make sure to disallow caching for uninitialized constants
2113 // found in the dictionary-mode objects.
2114 if (value->IsTheHole()) result->DisallowCaching();
2115 result->DictionaryResult(this, entry);
2116 return;
2117 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002118 }
2119 result->NotFound();
2120}
2121
2122
2123void JSObject::LookupRealNamedProperty(String* name, LookupResult* result) {
2124 LocalLookupRealNamedProperty(name, result);
2125 if (result->IsProperty()) return;
2126
2127 LookupRealNamedPropertyInPrototypes(name, result);
2128}
2129
2130
2131void JSObject::LookupRealNamedPropertyInPrototypes(String* name,
2132 LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01002133 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002134 for (Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002135 pt != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002136 pt = JSObject::cast(pt)->GetPrototype()) {
2137 JSObject::cast(pt)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002138 if (result->IsProperty() && (result->type() != INTERCEPTOR)) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002139 }
2140 result->NotFound();
2141}
2142
2143
2144// We only need to deal with CALLBACKS and INTERCEPTORS
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002145MaybeObject* JSObject::SetPropertyWithFailedAccessCheck(
2146 LookupResult* result,
2147 String* name,
2148 Object* value,
2149 bool check_prototype,
2150 StrictModeFlag strict_mode) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002151 if (check_prototype && !result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002152 LookupCallbackSetterInPrototypes(name, result);
2153 }
2154
2155 if (result->IsProperty()) {
2156 if (!result->IsReadOnly()) {
2157 switch (result->type()) {
2158 case CALLBACKS: {
2159 Object* obj = result->GetCallbackObject();
2160 if (obj->IsAccessorInfo()) {
2161 AccessorInfo* info = AccessorInfo::cast(obj);
2162 if (info->all_can_write()) {
2163 return SetPropertyWithCallback(result->GetCallbackObject(),
2164 name,
2165 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002166 result->holder(),
2167 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002168 }
2169 }
2170 break;
2171 }
2172 case INTERCEPTOR: {
2173 // Try lookup real named properties. Note that only property can be
2174 // set is callbacks marked as ALL_CAN_WRITE on the prototype chain.
2175 LookupResult r;
2176 LookupRealNamedProperty(name, &r);
2177 if (r.IsProperty()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002178 return SetPropertyWithFailedAccessCheck(&r,
2179 name,
2180 value,
2181 check_prototype,
2182 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002183 }
2184 break;
2185 }
2186 default: {
2187 break;
2188 }
2189 }
2190 }
2191 }
2192
Ben Murdoch8b112d22011-06-08 16:22:53 +01002193 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002194 HandleScope scope(heap->isolate());
2195 Handle<Object> value_handle(value);
Steve Block44f0eee2011-05-26 01:26:41 +01002196 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
Iain Merrick75681382010-08-19 15:07:18 +01002197 return *value_handle;
Steve Blocka7e24c12009-10-30 11:49:00 +00002198}
2199
2200
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002201MaybeObject* JSReceiver::SetProperty(LookupResult* result,
2202 String* key,
2203 Object* value,
2204 PropertyAttributes attributes,
2205 StrictModeFlag strict_mode) {
2206 if (result->IsFound() && result->type() == HANDLER) {
2207 return JSProxy::cast(this)->SetPropertyWithHandler(
2208 key, value, attributes, strict_mode);
2209 } else {
2210 return JSObject::cast(this)->SetPropertyForResult(
2211 result, key, value, attributes, strict_mode);
2212 }
2213}
2214
2215
2216bool JSProxy::HasPropertyWithHandler(String* name_raw) {
2217 Isolate* isolate = GetIsolate();
2218 HandleScope scope(isolate);
2219 Handle<Object> receiver(this);
2220 Handle<Object> name(name_raw);
2221 Handle<Object> handler(this->handler());
2222
2223 // Extract trap function.
2224 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("has");
2225 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002226 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002227 if (trap->IsUndefined()) {
2228 trap = isolate->derived_has_trap();
2229 }
2230
2231 // Call trap function.
2232 Object** args[] = { name.location() };
2233 bool has_exception;
2234 Handle<Object> result =
2235 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2236 if (has_exception) return Failure::Exception();
2237
2238 return result->ToBoolean()->IsTrue();
2239}
2240
2241
2242MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
2243 String* name_raw,
2244 Object* value_raw,
2245 PropertyAttributes attributes,
2246 StrictModeFlag strict_mode) {
2247 Isolate* isolate = GetIsolate();
2248 HandleScope scope(isolate);
2249 Handle<Object> receiver(this);
2250 Handle<Object> name(name_raw);
2251 Handle<Object> value(value_raw);
2252 Handle<Object> handler(this->handler());
2253
2254 // Extract trap function.
2255 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("set");
2256 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002257 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002258 if (trap->IsUndefined()) {
2259 trap = isolate->derived_set_trap();
2260 }
2261
2262 // Call trap function.
2263 Object** args[] = {
2264 receiver.location(), name.location(), value.location()
2265 };
2266 bool has_exception;
2267 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2268 if (has_exception) return Failure::Exception();
2269
2270 return *value;
2271}
2272
2273
2274MUST_USE_RESULT MaybeObject* JSProxy::DeletePropertyWithHandler(
2275 String* name_raw, DeleteMode mode) {
2276 Isolate* isolate = GetIsolate();
2277 HandleScope scope(isolate);
2278 Handle<Object> receiver(this);
2279 Handle<Object> name(name_raw);
2280 Handle<Object> handler(this->handler());
2281
2282 // Extract trap function.
2283 Handle<String> trap_name = isolate->factory()->LookupAsciiSymbol("delete");
2284 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002285 if (isolate->has_pending_exception()) return Failure::Exception();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002286 if (trap->IsUndefined()) {
2287 Handle<Object> args[] = { handler, trap_name };
2288 Handle<Object> error = isolate->factory()->NewTypeError(
2289 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2290 isolate->Throw(*error);
2291 return Failure::Exception();
2292 }
2293
2294 // Call trap function.
2295 Object** args[] = { name.location() };
2296 bool has_exception;
2297 Handle<Object> result =
2298 Execution::Call(trap, handler, ARRAY_SIZE(args), args, &has_exception);
2299 if (has_exception) return Failure::Exception();
2300
2301 Object* bool_result = result->ToBoolean();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002302 if (mode == STRICT_DELETION &&
2303 bool_result == isolate->heap()->false_value()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002304 Handle<Object> args[] = { handler, trap_name };
2305 Handle<Object> error = isolate->factory()->NewTypeError(
2306 "handler_failed", HandleVector(args, ARRAY_SIZE(args)));
2307 isolate->Throw(*error);
2308 return Failure::Exception();
2309 }
2310 return bool_result;
2311}
2312
2313
2314MUST_USE_RESULT PropertyAttributes JSProxy::GetPropertyAttributeWithHandler(
2315 JSReceiver* receiver_raw,
2316 String* name_raw,
2317 bool* has_exception) {
2318 Isolate* isolate = GetIsolate();
2319 HandleScope scope(isolate);
2320 Handle<JSReceiver> receiver(receiver_raw);
2321 Handle<Object> name(name_raw);
2322 Handle<Object> handler(this->handler());
2323
2324 // Extract trap function.
2325 Handle<String> trap_name =
2326 isolate->factory()->LookupAsciiSymbol("getPropertyDescriptor");
2327 Handle<Object> trap(v8::internal::GetProperty(handler, trap_name));
Ben Murdoch589d6972011-11-30 16:04:58 +00002328 if (isolate->has_pending_exception()) return NONE;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002329 if (trap->IsUndefined()) {
2330 Handle<Object> args[] = { handler, trap_name };
2331 Handle<Object> error = isolate->factory()->NewTypeError(
2332 "handler_trap_missing", HandleVector(args, ARRAY_SIZE(args)));
2333 isolate->Throw(*error);
2334 *has_exception = true;
2335 return NONE;
2336 }
2337
2338 // Call trap function.
2339 Object** args[] = { name.location() };
2340 Handle<Object> result =
2341 Execution::Call(trap, handler, ARRAY_SIZE(args), args, has_exception);
2342 if (has_exception) return NONE;
2343
2344 // TODO(rossberg): convert result to PropertyAttributes
2345 USE(result);
2346 return NONE;
2347}
2348
2349
2350void JSProxy::Fix() {
2351 Isolate* isolate = GetIsolate();
2352 HandleScope scope(isolate);
2353 Handle<JSProxy> self(this);
2354
Ben Murdoch589d6972011-11-30 16:04:58 +00002355 if (IsJSFunctionProxy()) {
2356 isolate->factory()->BecomeJSFunction(self);
2357 // Code will be set on the JavaScript side.
2358 } else {
2359 isolate->factory()->BecomeJSObject(self);
2360 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002361 ASSERT(self->IsJSObject());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002362}
2363
2364
2365
2366MaybeObject* JSObject::SetPropertyForResult(LookupResult* result,
2367 String* name,
2368 Object* value,
2369 PropertyAttributes attributes,
2370 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002371 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00002372 // Make sure that the top context does not change when doing callbacks or
2373 // interceptor calls.
2374 AssertNoContextChange ncc;
2375
Steve Blockd0582a62009-12-15 09:54:21 +00002376 // Optimization for 2-byte strings often used as keys in a decompression
2377 // dictionary. We make these short keys into symbols to avoid constantly
2378 // reallocating them.
2379 if (!name->IsSymbol() && name->length() <= 2) {
John Reck59135872010-11-02 12:39:01 -07002380 Object* symbol_version;
Steve Block44f0eee2011-05-26 01:26:41 +01002381 { MaybeObject* maybe_symbol_version = heap->LookupSymbol(name);
John Reck59135872010-11-02 12:39:01 -07002382 if (maybe_symbol_version->ToObject(&symbol_version)) {
2383 name = String::cast(symbol_version);
2384 }
2385 }
Steve Blockd0582a62009-12-15 09:54:21 +00002386 }
2387
Steve Blocka7e24c12009-10-30 11:49:00 +00002388 // Check access rights if needed.
2389 if (IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01002390 && !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002391 return SetPropertyWithFailedAccessCheck(result,
2392 name,
2393 value,
2394 true,
2395 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002396 }
2397
2398 if (IsJSGlobalProxy()) {
2399 Object* proto = GetPrototype();
2400 if (proto->IsNull()) return value;
2401 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002402 return JSObject::cast(proto)->SetProperty(
2403 result, name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002404 }
2405
2406 if (!result->IsProperty() && !IsJSContextExtensionObject()) {
2407 // We could not find a local property so let's check whether there is an
2408 // accessor that wants to handle the property.
2409 LookupResult accessor_result;
2410 LookupCallbackSetterInPrototypes(name, &accessor_result);
Andrei Popescu402d9372010-02-26 13:31:12 +00002411 if (accessor_result.IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002412 return SetPropertyWithCallback(accessor_result.GetCallbackObject(),
2413 name,
2414 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002415 accessor_result.holder(),
2416 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002417 }
2418 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002419 if (!result->IsFound()) {
2420 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002421 return AddProperty(name, value, attributes, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002422 }
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002423 if (result->IsReadOnly() && result->IsProperty()) {
2424 if (strict_mode == kStrictMode) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002425 HandleScope scope(heap->isolate());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002426 Handle<String> key(name);
2427 Handle<Object> holder(this);
2428 Handle<Object> args[2] = { key, holder };
Steve Block44f0eee2011-05-26 01:26:41 +01002429 return heap->isolate()->Throw(*heap->isolate()->factory()->NewTypeError(
2430 "strict_read_only_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002431 } else {
2432 return value;
2433 }
2434 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002435 // This is a real property that is not read-only, or it is a
2436 // transition or null descriptor and there are no setters in the prototypes.
2437 switch (result->type()) {
2438 case NORMAL:
2439 return SetNormalizedProperty(result, value);
2440 case FIELD:
2441 return FastPropertyAtPut(result->GetFieldIndex(), value);
2442 case MAP_TRANSITION:
2443 if (attributes == result->GetAttributes()) {
2444 // Only use map transition if the attributes match.
2445 return AddFastPropertyUsingMap(result->GetTransitionMap(),
2446 name,
2447 value);
2448 }
2449 return ConvertDescriptorToField(name, value, attributes);
2450 case CONSTANT_FUNCTION:
2451 // Only replace the function if necessary.
2452 if (value == result->GetConstantFunction()) return value;
2453 // Preserve the attributes of this existing property.
2454 attributes = result->GetAttributes();
2455 return ConvertDescriptorToField(name, value, attributes);
2456 case CALLBACKS:
2457 return SetPropertyWithCallback(result->GetCallbackObject(),
2458 name,
2459 value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002460 result->holder(),
2461 strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002462 case INTERCEPTOR:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01002463 return SetPropertyWithInterceptor(name, value, attributes, strict_mode);
Iain Merrick75681382010-08-19 15:07:18 +01002464 case CONSTANT_TRANSITION: {
2465 // If the same constant function is being added we can simply
2466 // transition to the target map.
2467 Map* target_map = result->GetTransitionMap();
2468 DescriptorArray* target_descriptors = target_map->instance_descriptors();
2469 int number = target_descriptors->SearchWithCache(name);
2470 ASSERT(number != DescriptorArray::kNotFound);
2471 ASSERT(target_descriptors->GetType(number) == CONSTANT_FUNCTION);
2472 JSFunction* function =
2473 JSFunction::cast(target_descriptors->GetValue(number));
Steve Block44f0eee2011-05-26 01:26:41 +01002474 ASSERT(!HEAP->InNewSpace(function));
Iain Merrick75681382010-08-19 15:07:18 +01002475 if (value == function) {
2476 set_map(target_map);
2477 return value;
2478 }
2479 // Otherwise, replace with a MAP_TRANSITION to a new map with a
2480 // FIELD, even if the value is a constant function.
Steve Blocka7e24c12009-10-30 11:49:00 +00002481 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
Iain Merrick75681382010-08-19 15:07:18 +01002482 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002483 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002484 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002485 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2486 default:
2487 UNREACHABLE();
2488 }
2489 UNREACHABLE();
2490 return value;
2491}
2492
2493
2494// Set a real local property, even if it is READ_ONLY. If the property is not
2495// present, add it with attributes NONE. This code is an exact clone of
2496// SetProperty, with the check for IsReadOnly and the check for a
2497// callback setter removed. The two lines looking up the LookupResult
2498// result are also added. If one of the functions is changed, the other
2499// should be.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002500// Note that this method cannot be used to set the prototype of a function
2501// because ConvertDescriptorToField() which is called in "case CALLBACKS:"
2502// doesn't handle function prototypes correctly.
Ben Murdoch086aeea2011-05-13 15:57:08 +01002503MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002504 String* name,
2505 Object* value,
2506 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01002507
Steve Blocka7e24c12009-10-30 11:49:00 +00002508 // Make sure that the top context does not change when doing callbacks or
2509 // interceptor calls.
2510 AssertNoContextChange ncc;
Andrei Popescu402d9372010-02-26 13:31:12 +00002511 LookupResult result;
2512 LocalLookup(name, &result);
Steve Blocka7e24c12009-10-30 11:49:00 +00002513 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002514 if (IsAccessCheckNeeded()) {
2515 Heap* heap = GetHeap();
2516 if (!heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002517 return SetPropertyWithFailedAccessCheck(&result,
2518 name,
2519 value,
2520 false,
2521 kNonStrictMode);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002522 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002523 }
2524
2525 if (IsJSGlobalProxy()) {
2526 Object* proto = GetPrototype();
2527 if (proto->IsNull()) return value;
2528 ASSERT(proto->IsJSGlobalObject());
Ben Murdoch086aeea2011-05-13 15:57:08 +01002529 return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
Steve Blocka7e24c12009-10-30 11:49:00 +00002530 name,
2531 value,
2532 attributes);
2533 }
2534
2535 // Check for accessor in prototype chain removed here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002536 if (!result.IsFound()) {
2537 // Neither properties nor transitions found.
Steve Block44f0eee2011-05-26 01:26:41 +01002538 return AddProperty(name, value, attributes, kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00002539 }
Steve Block6ded16b2010-05-10 14:33:55 +01002540
Andrei Popescu402d9372010-02-26 13:31:12 +00002541 PropertyDetails details = PropertyDetails(attributes, NORMAL);
2542
Steve Blocka7e24c12009-10-30 11:49:00 +00002543 // Check of IsReadOnly removed from here in clone.
Andrei Popescu402d9372010-02-26 13:31:12 +00002544 switch (result.type()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002545 case NORMAL:
Andrei Popescu402d9372010-02-26 13:31:12 +00002546 return SetNormalizedProperty(name, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +00002547 case FIELD:
Andrei Popescu402d9372010-02-26 13:31:12 +00002548 return FastPropertyAtPut(result.GetFieldIndex(), value);
Steve Blocka7e24c12009-10-30 11:49:00 +00002549 case MAP_TRANSITION:
Andrei Popescu402d9372010-02-26 13:31:12 +00002550 if (attributes == result.GetAttributes()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002551 // Only use map transition if the attributes match.
Andrei Popescu402d9372010-02-26 13:31:12 +00002552 return AddFastPropertyUsingMap(result.GetTransitionMap(),
Steve Blocka7e24c12009-10-30 11:49:00 +00002553 name,
2554 value);
2555 }
2556 return ConvertDescriptorToField(name, value, attributes);
2557 case CONSTANT_FUNCTION:
2558 // Only replace the function if necessary.
Andrei Popescu402d9372010-02-26 13:31:12 +00002559 if (value == result.GetConstantFunction()) return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00002560 // Preserve the attributes of this existing property.
Andrei Popescu402d9372010-02-26 13:31:12 +00002561 attributes = result.GetAttributes();
Steve Blocka7e24c12009-10-30 11:49:00 +00002562 return ConvertDescriptorToField(name, value, attributes);
2563 case CALLBACKS:
2564 case INTERCEPTOR:
2565 // Override callback in clone
2566 return ConvertDescriptorToField(name, value, attributes);
2567 case CONSTANT_TRANSITION:
2568 // Replace with a MAP_TRANSITION to a new map with a FIELD, even
2569 // if the value is a function.
2570 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2571 case NULL_DESCRIPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002572 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002573 return ConvertDescriptorToFieldAndMapTransition(name, value, attributes);
2574 default:
2575 UNREACHABLE();
2576 }
2577 UNREACHABLE();
2578 return value;
2579}
2580
2581
2582PropertyAttributes JSObject::GetPropertyAttributePostInterceptor(
2583 JSObject* receiver,
2584 String* name,
2585 bool continue_search) {
2586 // Check local property, ignore interceptor.
2587 LookupResult result;
2588 LocalLookupRealNamedProperty(name, &result);
2589 if (result.IsProperty()) return result.GetAttributes();
2590
2591 if (continue_search) {
2592 // Continue searching via the prototype chain.
2593 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01002594 if (!pt->IsNull()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002595 return JSObject::cast(pt)->
2596 GetPropertyAttributeWithReceiver(receiver, name);
2597 }
2598 }
2599 return ABSENT;
2600}
2601
2602
2603PropertyAttributes JSObject::GetPropertyAttributeWithInterceptor(
2604 JSObject* receiver,
2605 String* name,
2606 bool continue_search) {
Steve Block44f0eee2011-05-26 01:26:41 +01002607 Isolate* isolate = GetIsolate();
2608
Steve Blocka7e24c12009-10-30 11:49:00 +00002609 // Make sure that the top context does not change when doing
2610 // callbacks or interceptor calls.
2611 AssertNoContextChange ncc;
2612
Steve Block44f0eee2011-05-26 01:26:41 +01002613 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002614 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
2615 Handle<JSObject> receiver_handle(receiver);
2616 Handle<JSObject> holder_handle(this);
2617 Handle<String> name_handle(name);
Steve Block44f0eee2011-05-26 01:26:41 +01002618 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00002619 v8::AccessorInfo info(args.end());
2620 if (!interceptor->query()->IsUndefined()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002621 v8::NamedPropertyQuery query =
2622 v8::ToCData<v8::NamedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01002623 LOG(isolate,
2624 ApiNamedPropertyAccess("interceptor-named-has", *holder_handle, name));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002625 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002626 {
2627 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002628 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002629 result = query(v8::Utils::ToLocal(name_handle), info);
2630 }
2631 if (!result.IsEmpty()) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002632 ASSERT(result->IsInt32());
2633 return static_cast<PropertyAttributes>(result->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00002634 }
2635 } else if (!interceptor->getter()->IsUndefined()) {
2636 v8::NamedPropertyGetter getter =
2637 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01002638 LOG(isolate,
2639 ApiNamedPropertyAccess("interceptor-named-get-has", this, name));
Steve Blocka7e24c12009-10-30 11:49:00 +00002640 v8::Handle<v8::Value> result;
2641 {
2642 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01002643 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00002644 result = getter(v8::Utils::ToLocal(name_handle), info);
2645 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002646 if (!result.IsEmpty()) return DONT_ENUM;
Steve Blocka7e24c12009-10-30 11:49:00 +00002647 }
2648 return holder_handle->GetPropertyAttributePostInterceptor(*receiver_handle,
2649 *name_handle,
2650 continue_search);
2651}
2652
2653
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002654PropertyAttributes JSReceiver::GetPropertyAttributeWithReceiver(
2655 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00002656 String* key) {
2657 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002658 if (IsJSObject() && key->AsArrayIndex(&index)) {
2659 if (JSObject::cast(this)->HasElementWithReceiver(receiver, index))
2660 return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002661 return ABSENT;
2662 }
2663 // Named property.
2664 LookupResult result;
2665 Lookup(key, &result);
2666 return GetPropertyAttribute(receiver, &result, key, true);
2667}
2668
2669
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002670PropertyAttributes JSReceiver::GetPropertyAttribute(JSReceiver* receiver,
2671 LookupResult* result,
2672 String* name,
2673 bool continue_search) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002674 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002675 if (IsAccessCheckNeeded()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002676 JSObject* this_obj = JSObject::cast(this);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002677 Heap* heap = GetHeap();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002678 if (!heap->isolate()->MayNamedAccess(this_obj, name, v8::ACCESS_HAS)) {
2679 return this_obj->GetPropertyAttributeWithFailedAccessCheck(
2680 receiver, result, name, continue_search);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002681 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002682 }
Andrei Popescu402d9372010-02-26 13:31:12 +00002683 if (result->IsProperty()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002684 switch (result->type()) {
2685 case NORMAL: // fall through
2686 case FIELD:
2687 case CONSTANT_FUNCTION:
2688 case CALLBACKS:
2689 return result->GetAttributes();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002690 case HANDLER: {
2691 // TODO(rossberg): propagate exceptions properly.
2692 bool has_exception = false;
2693 return JSProxy::cast(this)->GetPropertyAttributeWithHandler(
2694 receiver, name, &has_exception);
2695 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002696 case INTERCEPTOR:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002697 return result->holder()->GetPropertyAttributeWithInterceptor(
2698 JSObject::cast(receiver), name, continue_search);
Steve Blocka7e24c12009-10-30 11:49:00 +00002699 default:
2700 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00002701 }
2702 }
2703 return ABSENT;
2704}
2705
2706
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002707PropertyAttributes JSReceiver::GetLocalPropertyAttribute(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002708 // Check whether the name is an array index.
2709 uint32_t index = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002710 if (IsJSObject() && name->AsArrayIndex(&index)) {
2711 if (JSObject::cast(this)->HasLocalElement(index)) return NONE;
Steve Blocka7e24c12009-10-30 11:49:00 +00002712 return ABSENT;
2713 }
2714 // Named property.
2715 LookupResult result;
2716 LocalLookup(name, &result);
2717 return GetPropertyAttribute(this, &result, name, false);
2718}
2719
2720
John Reck59135872010-11-02 12:39:01 -07002721MaybeObject* NormalizedMapCache::Get(JSObject* obj,
2722 PropertyNormalizationMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01002723 Isolate* isolate = obj->GetIsolate();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002724 Map* fast = obj->map();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002725 int index = fast->Hash() % kEntries;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002726 Object* result = get(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002727 if (result->IsMap() &&
2728 Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002729#ifdef DEBUG
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002730 Map::cast(result)->SharedMapVerify();
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002731 if (FLAG_enable_slow_asserts) {
2732 // The cached map should match newly created normalized map bit-by-bit.
John Reck59135872010-11-02 12:39:01 -07002733 Object* fresh;
2734 { MaybeObject* maybe_fresh =
2735 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2736 if (maybe_fresh->ToObject(&fresh)) {
2737 ASSERT(memcmp(Map::cast(fresh)->address(),
2738 Map::cast(result)->address(),
2739 Map::kSize) == 0);
2740 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002741 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002742 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002743#endif
2744 return result;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002745 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002746
John Reck59135872010-11-02 12:39:01 -07002747 { MaybeObject* maybe_result =
2748 fast->CopyNormalized(mode, SHARED_NORMALIZED_MAP);
2749 if (!maybe_result->ToObject(&result)) return maybe_result;
2750 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002751 set(index, result);
Steve Block44f0eee2011-05-26 01:26:41 +01002752 isolate->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002753
2754 return result;
2755}
2756
2757
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002758void NormalizedMapCache::Clear() {
2759 int entries = length();
2760 for (int i = 0; i != entries; i++) {
2761 set_undefined(i);
2762 }
2763}
2764
2765
John Reck59135872010-11-02 12:39:01 -07002766MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002767 if (map()->is_shared()) {
2768 // Fast case maps are never marked as shared.
2769 ASSERT(!HasFastProperties());
2770 // Replace the map with an identical copy that can be safely modified.
John Reck59135872010-11-02 12:39:01 -07002771 Object* obj;
2772 { MaybeObject* maybe_obj = map()->CopyNormalized(KEEP_INOBJECT_PROPERTIES,
2773 UNIQUE_NORMALIZED_MAP);
2774 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2775 }
Steve Block44f0eee2011-05-26 01:26:41 +01002776 GetIsolate()->counters()->normalized_maps()->Increment();
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002777
2778 set_map(Map::cast(obj));
2779 }
2780 return map()->UpdateCodeCache(name, code);
2781}
2782
2783
John Reck59135872010-11-02 12:39:01 -07002784MaybeObject* JSObject::NormalizeProperties(PropertyNormalizationMode mode,
2785 int expected_additional_properties) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002786 if (!HasFastProperties()) return this;
2787
2788 // The global object is always normalized.
2789 ASSERT(!IsGlobalObject());
Steve Block1e0659c2011-05-24 12:43:12 +01002790 // JSGlobalProxy must never be normalized
2791 ASSERT(!IsJSGlobalProxy());
2792
Ben Murdoch8b112d22011-06-08 16:22:53 +01002793 Map* map_of_this = map();
Steve Block44f0eee2011-05-26 01:26:41 +01002794
Steve Blocka7e24c12009-10-30 11:49:00 +00002795 // Allocate new content.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002796 int property_count = map_of_this->NumberOfDescribedProperties();
Steve Blocka7e24c12009-10-30 11:49:00 +00002797 if (expected_additional_properties > 0) {
2798 property_count += expected_additional_properties;
2799 } else {
2800 property_count += 2; // Make space for two more properties.
2801 }
John Reck59135872010-11-02 12:39:01 -07002802 Object* obj;
2803 { MaybeObject* maybe_obj =
2804 StringDictionary::Allocate(property_count);
2805 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2806 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002807 StringDictionary* dictionary = StringDictionary::cast(obj);
2808
Ben Murdoch8b112d22011-06-08 16:22:53 +01002809 DescriptorArray* descs = map_of_this->instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002810 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01002811 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00002812 switch (details.type()) {
2813 case CONSTANT_FUNCTION: {
2814 PropertyDetails d =
2815 PropertyDetails(details.attributes(), NORMAL, details.index());
2816 Object* value = descs->GetConstantFunction(i);
John Reck59135872010-11-02 12:39:01 -07002817 Object* result;
2818 { MaybeObject* maybe_result =
2819 dictionary->Add(descs->GetKey(i), value, d);
2820 if (!maybe_result->ToObject(&result)) return maybe_result;
2821 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002822 dictionary = StringDictionary::cast(result);
2823 break;
2824 }
2825 case FIELD: {
2826 PropertyDetails d =
2827 PropertyDetails(details.attributes(), NORMAL, details.index());
2828 Object* value = FastPropertyAt(descs->GetFieldIndex(i));
John Reck59135872010-11-02 12:39:01 -07002829 Object* result;
2830 { MaybeObject* maybe_result =
2831 dictionary->Add(descs->GetKey(i), value, d);
2832 if (!maybe_result->ToObject(&result)) return maybe_result;
2833 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002834 dictionary = StringDictionary::cast(result);
2835 break;
2836 }
2837 case CALLBACKS: {
2838 PropertyDetails d =
2839 PropertyDetails(details.attributes(), CALLBACKS, details.index());
2840 Object* value = descs->GetCallbacksObject(i);
John Reck59135872010-11-02 12:39:01 -07002841 Object* result;
2842 { MaybeObject* maybe_result =
2843 dictionary->Add(descs->GetKey(i), value, d);
2844 if (!maybe_result->ToObject(&result)) return maybe_result;
2845 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002846 dictionary = StringDictionary::cast(result);
2847 break;
2848 }
2849 case MAP_TRANSITION:
2850 case CONSTANT_TRANSITION:
2851 case NULL_DESCRIPTOR:
2852 case INTERCEPTOR:
Ben Murdoch589d6972011-11-30 16:04:58 +00002853 case ELEMENTS_TRANSITION:
Steve Blocka7e24c12009-10-30 11:49:00 +00002854 break;
2855 default:
2856 UNREACHABLE();
2857 }
2858 }
2859
Ben Murdoch8b112d22011-06-08 16:22:53 +01002860 Heap* current_heap = map_of_this->heap();
2861
Steve Blocka7e24c12009-10-30 11:49:00 +00002862 // Copy the next enumeration index from instance descriptor.
Ben Murdoch8b112d22011-06-08 16:22:53 +01002863 int index = map_of_this->instance_descriptors()->NextEnumerationIndex();
Steve Blocka7e24c12009-10-30 11:49:00 +00002864 dictionary->SetNextEnumerationIndex(index);
2865
Ben Murdoch8b112d22011-06-08 16:22:53 +01002866 { MaybeObject* maybe_obj =
2867 current_heap->isolate()->context()->global_context()->
Steve Block44f0eee2011-05-26 01:26:41 +01002868 normalized_map_cache()->Get(this, mode);
John Reck59135872010-11-02 12:39:01 -07002869 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2870 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002871 Map* new_map = Map::cast(obj);
2872
Steve Blocka7e24c12009-10-30 11:49:00 +00002873 // We have now successfully allocated all the necessary objects.
2874 // Changes can now be made with the guarantee that all of them take effect.
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002875
2876 // Resize the object in the heap if necessary.
2877 int new_instance_size = new_map->instance_size();
Ben Murdoch8b112d22011-06-08 16:22:53 +01002878 int instance_size_delta = map_of_this->instance_size() - new_instance_size;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002879 ASSERT(instance_size_delta >= 0);
Ben Murdoch8b112d22011-06-08 16:22:53 +01002880 current_heap->CreateFillerObjectAt(this->address() + new_instance_size,
2881 instance_size_delta);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01002882
Steve Blocka7e24c12009-10-30 11:49:00 +00002883 set_map(new_map);
Ben Murdoch257744e2011-11-30 15:57:28 +00002884 new_map->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00002885
2886 set_properties(dictionary);
2887
Ben Murdoch8b112d22011-06-08 16:22:53 +01002888 current_heap->isolate()->counters()->props_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002889
2890#ifdef DEBUG
2891 if (FLAG_trace_normalization) {
2892 PrintF("Object properties have been normalized:\n");
2893 Print();
2894 }
2895#endif
2896 return this;
2897}
2898
2899
John Reck59135872010-11-02 12:39:01 -07002900MaybeObject* JSObject::TransformToFastProperties(int unused_property_fields) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002901 if (HasFastProperties()) return this;
2902 ASSERT(!IsGlobalObject());
2903 return property_dictionary()->
2904 TransformPropertiesToFastFor(this, unused_property_fields);
2905}
2906
2907
John Reck59135872010-11-02 12:39:01 -07002908MaybeObject* JSObject::NormalizeElements() {
Steve Block44f0eee2011-05-26 01:26:41 +01002909 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01002910
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002911 // Find the backing store.
2912 FixedArrayBase* array = FixedArrayBase::cast(elements());
2913 Map* old_map = array->map();
2914 bool is_arguments =
2915 (old_map == old_map->heap()->non_strict_arguments_elements_map());
2916 if (is_arguments) {
2917 array = FixedArrayBase::cast(FixedArray::cast(array)->get(1));
John Reck59135872010-11-02 12:39:01 -07002918 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002919 if (array->IsDictionary()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00002920
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002921 ASSERT(HasFastElements() ||
2922 HasFastDoubleElements() ||
2923 HasFastArgumentsElements());
2924 // Compute the effective length and allocate a new backing store.
2925 int length = IsJSArray()
2926 ? Smi::cast(JSArray::cast(this)->length())->value()
2927 : array->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002928 int old_capacity = 0;
2929 int used_elements = 0;
2930 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002931 NumberDictionary* dictionary = NULL;
2932 { Object* object;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002933 MaybeObject* maybe = NumberDictionary::Allocate(used_elements);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002934 if (!maybe->ToObject(&object)) return maybe;
2935 dictionary = NumberDictionary::cast(object);
John Reck59135872010-11-02 12:39:01 -07002936 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002937
2938 // Copy the elements to the new backing store.
2939 bool has_double_elements = array->IsFixedDoubleArray();
Steve Blocka7e24c12009-10-30 11:49:00 +00002940 for (int i = 0; i < length; i++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002941 Object* value = NULL;
2942 if (has_double_elements) {
2943 FixedDoubleArray* double_array = FixedDoubleArray::cast(array);
2944 if (double_array->is_the_hole(i)) {
2945 value = GetIsolate()->heap()->the_hole_value();
2946 } else {
2947 // Objects must be allocated in the old object space, since the
2948 // overall number of HeapNumbers needed for the conversion might
2949 // exceed the capacity of new space, and we would fail repeatedly
2950 // trying to convert the FixedDoubleArray.
2951 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002952 GetHeap()->AllocateHeapNumber(double_array->get_scalar(i), TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002953 if (!maybe_value_object->ToObject(&value)) return maybe_value_object;
John Reck59135872010-11-02 12:39:01 -07002954 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002955 } else {
2956 ASSERT(old_map->has_fast_elements());
2957 value = FixedArray::cast(array)->get(i);
2958 }
2959 PropertyDetails details = PropertyDetails(NONE, NORMAL);
2960 if (!value->IsTheHole()) {
2961 Object* result;
2962 MaybeObject* maybe_result =
2963 dictionary->AddNumberEntry(i, value, details);
2964 if (!maybe_result->ToObject(&result)) return maybe_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00002965 dictionary = NumberDictionary::cast(result);
2966 }
2967 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002968
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002969 // Switch to using the dictionary as the backing storage for elements.
2970 if (is_arguments) {
2971 FixedArray::cast(elements())->set(1, dictionary);
2972 } else {
2973 // Set the new map first to satify the elements type assert in
2974 // set_elements().
2975 Object* new_map;
2976 MaybeObject* maybe = map()->GetSlowElementsMap();
2977 if (!maybe->ToObject(&new_map)) return maybe;
2978 set_map(Map::cast(new_map));
2979 set_elements(dictionary);
2980 }
2981
2982 old_map->isolate()->counters()->elements_to_dictionary()->Increment();
Steve Blocka7e24c12009-10-30 11:49:00 +00002983
2984#ifdef DEBUG
2985 if (FLAG_trace_normalization) {
2986 PrintF("Object elements have been normalized:\n");
2987 Print();
2988 }
2989#endif
2990
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002991 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
2992 return dictionary;
Steve Blocka7e24c12009-10-30 11:49:00 +00002993}
2994
2995
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002996MaybeObject* JSObject::GetHiddenProperties(HiddenPropertiesFlag flag) {
2997 Isolate* isolate = GetIsolate();
2998 Heap* heap = isolate->heap();
2999 Object* holder = BypassGlobalProxy();
3000 if (holder->IsUndefined()) return heap->undefined_value();
3001 JSObject* obj = JSObject::cast(holder);
3002 if (obj->HasFastProperties()) {
3003 // If the object has fast properties, check whether the first slot
3004 // in the descriptor array matches the hidden symbol. Since the
3005 // hidden symbols hash code is zero (and no other string has hash
3006 // code zero) it will always occupy the first entry if present.
3007 DescriptorArray* descriptors = obj->map()->instance_descriptors();
3008 if ((descriptors->number_of_descriptors() > 0) &&
3009 (descriptors->GetKey(0) == heap->hidden_symbol()) &&
3010 descriptors->IsProperty(0)) {
3011 ASSERT(descriptors->GetType(0) == FIELD);
3012 return obj->FastPropertyAt(descriptors->GetFieldIndex(0));
3013 }
3014 }
3015
3016 // Only attempt to find the hidden properties in the local object and not
3017 // in the prototype chain.
3018 if (!obj->HasHiddenPropertiesObject()) {
3019 // Hidden properties object not found. Allocate a new hidden properties
3020 // object if requested. Otherwise return the undefined value.
3021 if (flag == ALLOW_CREATION) {
3022 Object* hidden_obj;
3023 { MaybeObject* maybe_obj = heap->AllocateJSObject(
3024 isolate->context()->global_context()->object_function());
3025 if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj;
3026 }
3027 // Don't allow leakage of the hidden object through accessors
3028 // on Object.prototype.
3029 {
3030 MaybeObject* maybe_obj =
3031 JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false);
3032 if (maybe_obj->IsFailure()) return maybe_obj;
3033 }
3034 return obj->SetHiddenPropertiesObject(hidden_obj);
3035 } else {
3036 return heap->undefined_value();
3037 }
3038 }
3039 return obj->GetHiddenPropertiesObject();
3040}
3041
3042
3043MaybeObject* JSObject::GetIdentityHash(HiddenPropertiesFlag flag) {
3044 Isolate* isolate = GetIsolate();
3045 Object* hidden_props_obj;
3046 { MaybeObject* maybe_obj = GetHiddenProperties(flag);
3047 if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj;
3048 }
3049 if (!hidden_props_obj->IsJSObject()) {
3050 // We failed to create hidden properties. That's a detached
3051 // global proxy.
3052 ASSERT(hidden_props_obj->IsUndefined());
3053 return Smi::FromInt(0);
3054 }
3055 JSObject* hidden_props = JSObject::cast(hidden_props_obj);
3056 String* hash_symbol = isolate->heap()->identity_hash_symbol();
3057 {
3058 // Note that HasLocalProperty() can cause a GC in the general case in the
3059 // presence of interceptors.
3060 AssertNoAllocation no_alloc;
3061 if (hidden_props->HasLocalProperty(hash_symbol)) {
3062 MaybeObject* hash = hidden_props->GetProperty(hash_symbol);
3063 return Smi::cast(hash->ToObjectChecked());
3064 }
3065 }
3066
3067 int hash_value;
3068 int attempts = 0;
3069 do {
3070 // Generate a random 32-bit hash value but limit range to fit
3071 // within a smi.
3072 hash_value = V8::Random(isolate) & Smi::kMaxValue;
3073 attempts++;
3074 } while (hash_value == 0 && attempts < 30);
3075 hash_value = hash_value != 0 ? hash_value : 1; // never return 0
3076
3077 Smi* hash = Smi::FromInt(hash_value);
3078 { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes(
3079 hash_symbol,
3080 hash,
3081 static_cast<PropertyAttributes>(None));
3082 if (result->IsFailure()) return result;
3083 }
3084 return hash;
3085}
3086
3087
John Reck59135872010-11-02 12:39:01 -07003088MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name,
3089 DeleteMode mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003090 // Check local property, ignore interceptor.
3091 LookupResult result;
3092 LocalLookupRealNamedProperty(name, &result);
Ben Murdoch8b112d22011-06-08 16:22:53 +01003093 if (!result.IsProperty()) return GetHeap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003094
3095 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003096 Object* obj;
3097 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3098 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3099 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003100
3101 return DeleteNormalizedProperty(name, mode);
3102}
3103
3104
John Reck59135872010-11-02 12:39:01 -07003105MaybeObject* JSObject::DeletePropertyWithInterceptor(String* name) {
Steve Block44f0eee2011-05-26 01:26:41 +01003106 Isolate* isolate = GetIsolate();
3107 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003108 Handle<InterceptorInfo> interceptor(GetNamedInterceptor());
3109 Handle<String> name_handle(name);
3110 Handle<JSObject> this_handle(this);
3111 if (!interceptor->deleter()->IsUndefined()) {
3112 v8::NamedPropertyDeleter deleter =
3113 v8::ToCData<v8::NamedPropertyDeleter>(interceptor->deleter());
Steve Block44f0eee2011-05-26 01:26:41 +01003114 LOG(isolate,
3115 ApiNamedPropertyAccess("interceptor-named-delete", *this_handle, name));
3116 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003117 v8::AccessorInfo info(args.end());
3118 v8::Handle<v8::Boolean> result;
3119 {
3120 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003121 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003122 result = deleter(v8::Utils::ToLocal(name_handle), info);
3123 }
Steve Block44f0eee2011-05-26 01:26:41 +01003124 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003125 if (!result.IsEmpty()) {
3126 ASSERT(result->IsBoolean());
3127 return *v8::Utils::OpenHandle(*result);
3128 }
3129 }
John Reck59135872010-11-02 12:39:01 -07003130 MaybeObject* raw_result =
Steve Blocka7e24c12009-10-30 11:49:00 +00003131 this_handle->DeletePropertyPostInterceptor(*name_handle, NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003132 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003133 return raw_result;
3134}
3135
3136
John Reck59135872010-11-02 12:39:01 -07003137MaybeObject* JSObject::DeleteElementWithInterceptor(uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01003138 Isolate* isolate = GetIsolate();
3139 Heap* heap = isolate->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003140 // Make sure that the top context does not change when doing
3141 // callbacks or interceptor calls.
3142 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01003143 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003144 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Steve Block44f0eee2011-05-26 01:26:41 +01003145 if (interceptor->deleter()->IsUndefined()) return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003146 v8::IndexedPropertyDeleter deleter =
3147 v8::ToCData<v8::IndexedPropertyDeleter>(interceptor->deleter());
3148 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01003149 LOG(isolate,
3150 ApiIndexedPropertyAccess("interceptor-indexed-delete", this, index));
3151 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00003152 v8::AccessorInfo info(args.end());
3153 v8::Handle<v8::Boolean> result;
3154 {
3155 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01003156 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00003157 result = deleter(index, info);
3158 }
Steve Block44f0eee2011-05-26 01:26:41 +01003159 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003160 if (!result.IsEmpty()) {
3161 ASSERT(result->IsBoolean());
3162 return *v8::Utils::OpenHandle(*result);
3163 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003164 MaybeObject* raw_result = this_handle->GetElementsAccessor()->Delete(
3165 *this_handle,
3166 index,
3167 NORMAL_DELETION);
Steve Block44f0eee2011-05-26 01:26:41 +01003168 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00003169 return raw_result;
3170}
3171
3172
John Reck59135872010-11-02 12:39:01 -07003173MaybeObject* JSObject::DeleteElement(uint32_t index, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003174 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003175 // Check access rights if needed.
3176 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003177 !isolate->MayIndexedAccess(this, index, v8::ACCESS_DELETE)) {
3178 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3179 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003180 }
3181
3182 if (IsJSGlobalProxy()) {
3183 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003184 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003185 ASSERT(proto->IsJSGlobalObject());
3186 return JSGlobalObject::cast(proto)->DeleteElement(index, mode);
3187 }
3188
3189 if (HasIndexedInterceptor()) {
3190 // Skip interceptor if forcing deletion.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003191 if (mode != FORCE_DELETION) {
3192 return DeleteElementWithInterceptor(index);
3193 }
3194 mode = JSReceiver::FORCE_DELETION;
Steve Blocka7e24c12009-10-30 11:49:00 +00003195 }
3196
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003197 return GetElementsAccessor()->Delete(this, index, mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00003198}
3199
3200
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003201MaybeObject* JSReceiver::DeleteProperty(String* name, DeleteMode mode) {
3202 if (IsJSProxy()) {
3203 return JSProxy::cast(this)->DeletePropertyWithHandler(name, mode);
3204 } else {
3205 return JSObject::cast(this)->DeleteProperty(name, mode);
3206 }
3207}
3208
3209
John Reck59135872010-11-02 12:39:01 -07003210MaybeObject* JSObject::DeleteProperty(String* name, DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01003211 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003212 // ECMA-262, 3rd, 8.6.2.5
3213 ASSERT(name->IsString());
3214
3215 // Check access rights if needed.
3216 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003217 !isolate->MayNamedAccess(this, name, v8::ACCESS_DELETE)) {
3218 isolate->ReportFailedAccessCheck(this, v8::ACCESS_DELETE);
3219 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003220 }
3221
3222 if (IsJSGlobalProxy()) {
3223 Object* proto = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01003224 if (proto->IsNull()) return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003225 ASSERT(proto->IsJSGlobalObject());
3226 return JSGlobalObject::cast(proto)->DeleteProperty(name, mode);
3227 }
3228
3229 uint32_t index = 0;
3230 if (name->AsArrayIndex(&index)) {
3231 return DeleteElement(index, mode);
3232 } else {
3233 LookupResult result;
3234 LocalLookup(name, &result);
Steve Block44f0eee2011-05-26 01:26:41 +01003235 if (!result.IsProperty()) return isolate->heap()->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003236 // Ignore attributes if forcing a deletion.
3237 if (result.IsDontDelete() && mode != FORCE_DELETION) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003238 if (mode == STRICT_DELETION) {
3239 // Deleting a non-configurable property in strict mode.
Steve Block44f0eee2011-05-26 01:26:41 +01003240 HandleScope scope(isolate);
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003241 Handle<Object> args[2] = { Handle<Object>(name), Handle<Object>(this) };
Steve Block44f0eee2011-05-26 01:26:41 +01003242 return isolate->Throw(*isolate->factory()->NewTypeError(
3243 "strict_delete_property", HandleVector(args, 2)));
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003244 }
Steve Block44f0eee2011-05-26 01:26:41 +01003245 return isolate->heap()->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003246 }
3247 // Check for interceptor.
3248 if (result.type() == INTERCEPTOR) {
3249 // Skip interceptor if forcing a deletion.
3250 if (mode == FORCE_DELETION) {
3251 return DeletePropertyPostInterceptor(name, mode);
3252 }
3253 return DeletePropertyWithInterceptor(name);
3254 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003255 // Normalize object if needed.
John Reck59135872010-11-02 12:39:01 -07003256 Object* obj;
3257 { MaybeObject* maybe_obj =
3258 NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3259 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
3260 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003261 // Make sure the properties are normalized before removing the entry.
3262 return DeleteNormalizedProperty(name, mode);
3263 }
3264}
3265
3266
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003267bool JSObject::ReferencesObjectFromElements(FixedArray* elements,
3268 ElementsKind kind,
3269 Object* object) {
3270 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
3271 if (kind == FAST_ELEMENTS) {
3272 int length = IsJSArray()
3273 ? Smi::cast(JSArray::cast(this)->length())->value()
3274 : elements->length();
3275 for (int i = 0; i < length; ++i) {
3276 Object* element = elements->get(i);
3277 if (!element->IsTheHole() && element == object) return true;
3278 }
3279 } else {
3280 Object* key = NumberDictionary::cast(elements)->SlowReverseLookup(object);
3281 if (!key->IsUndefined()) return true;
3282 }
3283 return false;
3284}
3285
3286
Steve Blocka7e24c12009-10-30 11:49:00 +00003287// Check whether this object references another object.
3288bool JSObject::ReferencesObject(Object* obj) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01003289 Map* map_of_this = map();
3290 Heap* heap = map_of_this->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003291 AssertNoAllocation no_alloc;
3292
3293 // Is the object the constructor for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003294 if (map_of_this->constructor() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003295 return true;
3296 }
3297
3298 // Is the object the prototype for this object?
Ben Murdoch8b112d22011-06-08 16:22:53 +01003299 if (map_of_this->prototype() == obj) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003300 return true;
3301 }
3302
3303 // Check if the object is among the named properties.
3304 Object* key = SlowReverseLookup(obj);
Steve Block44f0eee2011-05-26 01:26:41 +01003305 if (!key->IsUndefined()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003306 return true;
3307 }
3308
3309 // Check if the object is among the indexed properties.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003310 ElementsKind kind = GetElementsKind();
3311 switch (kind) {
Steve Block44f0eee2011-05-26 01:26:41 +01003312 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003313 case EXTERNAL_BYTE_ELEMENTS:
3314 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3315 case EXTERNAL_SHORT_ELEMENTS:
3316 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3317 case EXTERNAL_INT_ELEMENTS:
3318 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3319 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003320 case EXTERNAL_DOUBLE_ELEMENTS:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003321 case FAST_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003322 // Raw pixels and external arrays do not reference other
3323 // objects.
Steve Blocka7e24c12009-10-30 11:49:00 +00003324 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003325 case FAST_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00003326 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003327 FixedArray* elements = FixedArray::cast(this->elements());
3328 if (ReferencesObjectFromElements(elements, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003329 break;
3330 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003331 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3332 FixedArray* parameter_map = FixedArray::cast(elements());
3333 // Check the mapped parameters.
3334 int length = parameter_map->length();
3335 for (int i = 2; i < length; ++i) {
3336 Object* value = parameter_map->get(i);
3337 if (!value->IsTheHole() && value == obj) return true;
3338 }
3339 // Check the arguments.
3340 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3341 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
3342 if (ReferencesObjectFromElements(arguments, kind, obj)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00003343 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003344 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003345 }
3346
Steve Block6ded16b2010-05-10 14:33:55 +01003347 // For functions check the context.
3348 if (IsJSFunction()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003349 // Get the constructor function for arguments array.
3350 JSObject* arguments_boilerplate =
Steve Block44f0eee2011-05-26 01:26:41 +01003351 heap->isolate()->context()->global_context()->
3352 arguments_boilerplate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003353 JSFunction* arguments_function =
3354 JSFunction::cast(arguments_boilerplate->map()->constructor());
3355
3356 // Get the context and don't check if it is the global context.
3357 JSFunction* f = JSFunction::cast(this);
3358 Context* context = f->context();
3359 if (context->IsGlobalContext()) {
3360 return false;
3361 }
3362
3363 // Check the non-special context slots.
3364 for (int i = Context::MIN_CONTEXT_SLOTS; i < context->length(); i++) {
3365 // Only check JS objects.
3366 if (context->get(i)->IsJSObject()) {
3367 JSObject* ctxobj = JSObject::cast(context->get(i));
3368 // If it is an arguments array check the content.
3369 if (ctxobj->map()->constructor() == arguments_function) {
3370 if (ctxobj->ReferencesObject(obj)) {
3371 return true;
3372 }
3373 } else if (ctxobj == obj) {
3374 return true;
3375 }
3376 }
3377 }
3378
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003379 // Check the context extension (if any) if it can have references.
3380 if (context->has_extension() && !context->IsCatchContext()) {
3381 return JSObject::cast(context->extension())->ReferencesObject(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +00003382 }
3383 }
3384
3385 // No references to object.
3386 return false;
3387}
3388
3389
John Reck59135872010-11-02 12:39:01 -07003390MaybeObject* JSObject::PreventExtensions() {
Steve Block44f0eee2011-05-26 01:26:41 +01003391 Isolate* isolate = GetIsolate();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003392 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003393 !isolate->MayNamedAccess(this,
3394 isolate->heap()->undefined_value(),
3395 v8::ACCESS_KEYS)) {
3396 isolate->ReportFailedAccessCheck(this, v8::ACCESS_KEYS);
3397 return isolate->heap()->false_value();
Ben Murdoche0cee9b2011-05-25 10:26:03 +01003398 }
3399
Steve Block1e0659c2011-05-24 12:43:12 +01003400 if (IsJSGlobalProxy()) {
3401 Object* proto = GetPrototype();
3402 if (proto->IsNull()) return this;
3403 ASSERT(proto->IsJSGlobalObject());
3404 return JSObject::cast(proto)->PreventExtensions();
3405 }
3406
Ben Murdoch257744e2011-11-30 15:57:28 +00003407 // It's not possible to seal objects with external array elements
3408 if (HasExternalArrayElements()) {
3409 HandleScope scope(isolate);
3410 Handle<Object> object(this);
3411 Handle<Object> error =
3412 isolate->factory()->NewTypeError(
3413 "cant_prevent_ext_external_array_elements",
3414 HandleVector(&object, 1));
3415 return isolate->Throw(*error);
3416 }
3417
Steve Block8defd9f2010-07-08 12:39:36 +01003418 // If there are fast elements we normalize.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003419 NumberDictionary* dictionary = NULL;
3420 { MaybeObject* maybe = NormalizeElements();
3421 if (!maybe->To<NumberDictionary>(&dictionary)) return maybe;
Steve Block8defd9f2010-07-08 12:39:36 +01003422 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003423 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Block8defd9f2010-07-08 12:39:36 +01003424 // Make sure that we never go back to fast case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003425 dictionary->set_requires_slow_elements();
Steve Block8defd9f2010-07-08 12:39:36 +01003426
3427 // Do a map transition, other objects with this map may still
3428 // be extensible.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003429 Map* new_map;
3430 { MaybeObject* maybe = map()->CopyDropTransitions();
3431 if (!maybe->To<Map>(&new_map)) return maybe;
John Reck59135872010-11-02 12:39:01 -07003432 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003433 new_map->set_is_extensible(false);
3434 set_map(new_map);
Steve Block8defd9f2010-07-08 12:39:36 +01003435 ASSERT(!map()->is_extensible());
3436 return new_map;
3437}
3438
3439
Steve Blocka7e24c12009-10-30 11:49:00 +00003440// Tests for the fast common case for property enumeration:
Steve Blockd0582a62009-12-15 09:54:21 +00003441// - This object and all prototypes has an enum cache (which means that it has
3442// no interceptors and needs no access checks).
3443// - This object has no elements.
3444// - No prototype has enumerable properties/elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00003445bool JSObject::IsSimpleEnum() {
Steve Block44f0eee2011-05-26 01:26:41 +01003446 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003447 for (Object* o = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003448 o != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003449 o = JSObject::cast(o)->GetPrototype()) {
3450 JSObject* curr = JSObject::cast(o);
Steve Blocka7e24c12009-10-30 11:49:00 +00003451 if (!curr->map()->instance_descriptors()->HasEnumCache()) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00003452 ASSERT(!curr->HasNamedInterceptor());
3453 ASSERT(!curr->HasIndexedInterceptor());
3454 ASSERT(!curr->IsAccessCheckNeeded());
Steve Blocka7e24c12009-10-30 11:49:00 +00003455 if (curr->NumberOfEnumElements() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003456 if (curr != this) {
3457 FixedArray* curr_fixed_array =
3458 FixedArray::cast(curr->map()->instance_descriptors()->GetEnumCache());
Steve Blockd0582a62009-12-15 09:54:21 +00003459 if (curr_fixed_array->length() > 0) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00003460 }
3461 }
3462 return true;
3463}
3464
3465
3466int Map::NumberOfDescribedProperties() {
3467 int result = 0;
3468 DescriptorArray* descs = instance_descriptors();
3469 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3470 if (descs->IsProperty(i)) result++;
3471 }
3472 return result;
3473}
3474
3475
3476int Map::PropertyIndexFor(String* name) {
3477 DescriptorArray* descs = instance_descriptors();
3478 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3479 if (name->Equals(descs->GetKey(i)) && !descs->IsNullDescriptor(i)) {
3480 return descs->GetFieldIndex(i);
3481 }
3482 }
3483 return -1;
3484}
3485
3486
3487int Map::NextFreePropertyIndex() {
3488 int max_index = -1;
3489 DescriptorArray* descs = instance_descriptors();
3490 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3491 if (descs->GetType(i) == FIELD) {
3492 int current_index = descs->GetFieldIndex(i);
3493 if (current_index > max_index) max_index = current_index;
3494 }
3495 }
3496 return max_index + 1;
3497}
3498
3499
3500AccessorDescriptor* Map::FindAccessor(String* name) {
3501 DescriptorArray* descs = instance_descriptors();
3502 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3503 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) {
3504 return descs->GetCallbacks(i);
3505 }
3506 }
3507 return NULL;
3508}
3509
3510
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003511void JSReceiver::LocalLookup(String* name, LookupResult* result) {
3512 if (IsJSProxy()) {
3513 result->HandlerResult();
3514 } else {
3515 JSObject::cast(this)->LocalLookup(name, result);
3516 }
3517}
3518
3519
Steve Blocka7e24c12009-10-30 11:49:00 +00003520void JSObject::LocalLookup(String* name, LookupResult* result) {
3521 ASSERT(name->IsString());
3522
Steve Block44f0eee2011-05-26 01:26:41 +01003523 Heap* heap = GetHeap();
3524
Steve Blocka7e24c12009-10-30 11:49:00 +00003525 if (IsJSGlobalProxy()) {
3526 Object* proto = GetPrototype();
3527 if (proto->IsNull()) return result->NotFound();
3528 ASSERT(proto->IsJSGlobalObject());
3529 return JSObject::cast(proto)->LocalLookup(name, result);
3530 }
3531
3532 // Do not use inline caching if the object is a non-global object
3533 // that requires access checks.
3534 if (!IsJSGlobalProxy() && IsAccessCheckNeeded()) {
3535 result->DisallowCaching();
3536 }
3537
3538 // Check __proto__ before interceptor.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003539 if (name->Equals(heap->Proto_symbol()) && !IsJSContextExtensionObject()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003540 result->ConstantResult(this);
3541 return;
3542 }
3543
3544 // Check for lookup interceptor except when bootstrapping.
Steve Block44f0eee2011-05-26 01:26:41 +01003545 if (HasNamedInterceptor() && !heap->isolate()->bootstrapper()->IsActive()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003546 result->InterceptorResult(this);
3547 return;
3548 }
3549
3550 LocalLookupRealNamedProperty(name, result);
3551}
3552
3553
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003554void JSReceiver::Lookup(String* name, LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +00003555 // Ecma-262 3rd 8.6.2.4
Steve Block44f0eee2011-05-26 01:26:41 +01003556 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003557 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003558 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003559 current = JSObject::cast(current)->GetPrototype()) {
3560 JSObject::cast(current)->LocalLookup(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003561 if (result->IsProperty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003562 }
3563 result->NotFound();
3564}
3565
3566
3567// Search object and it's prototype chain for callback properties.
3568void JSObject::LookupCallback(String* name, LookupResult* result) {
Steve Block44f0eee2011-05-26 01:26:41 +01003569 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003570 for (Object* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003571 current != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003572 current = JSObject::cast(current)->GetPrototype()) {
3573 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003574 if (result->IsProperty() && result->type() == CALLBACKS) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00003575 }
3576 result->NotFound();
3577}
3578
3579
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003580// Search for a getter or setter in an elements dictionary. Returns either
3581// undefined if the element is read-only, or the getter/setter pair (fixed
3582// array) if there is an existing one, or the hole value if the element does
3583// not exist or is a normal non-getter/setter data element.
3584static Object* FindGetterSetterInDictionary(NumberDictionary* dictionary,
3585 uint32_t index,
3586 Heap* heap) {
3587 int entry = dictionary->FindEntry(index);
3588 if (entry != NumberDictionary::kNotFound) {
3589 Object* result = dictionary->ValueAt(entry);
3590 PropertyDetails details = dictionary->DetailsAt(entry);
3591 if (details.IsReadOnly()) return heap->undefined_value();
3592 if (details.type() == CALLBACKS && result->IsFixedArray()) return result;
3593 }
3594 return heap->the_hole_value();
3595}
3596
3597
John Reck59135872010-11-02 12:39:01 -07003598MaybeObject* JSObject::DefineGetterSetter(String* name,
3599 PropertyAttributes attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01003600 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00003601 // Make sure that the top context does not change when doing callbacks or
3602 // interceptor calls.
3603 AssertNoContextChange ncc;
3604
Steve Blocka7e24c12009-10-30 11:49:00 +00003605 // Try to flatten before operating on the string.
Steve Block6ded16b2010-05-10 14:33:55 +01003606 name->TryFlatten();
Steve Blocka7e24c12009-10-30 11:49:00 +00003607
Leon Clarkef7060e22010-06-03 12:02:55 +01003608 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003609 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003610 }
3611
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003612 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003613 bool is_element = name->AsArrayIndex(&index);
Steve Blocka7e24c12009-10-30 11:49:00 +00003614
3615 if (is_element) {
3616 switch (GetElementsKind()) {
3617 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003618 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00003619 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003620 case EXTERNAL_PIXEL_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003621 case EXTERNAL_BYTE_ELEMENTS:
3622 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3623 case EXTERNAL_SHORT_ELEMENTS:
3624 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3625 case EXTERNAL_INT_ELEMENTS:
3626 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3627 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003628 case EXTERNAL_DOUBLE_ELEMENTS:
Steve Block3ce2e202009-11-05 08:53:23 +00003629 // Ignore getters and setters on pixel and external array
3630 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003631 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003632 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003633 Object* probe =
3634 FindGetterSetterInDictionary(element_dictionary(), index, heap);
3635 if (!probe->IsTheHole()) return probe;
3636 // Otherwise allow to override it.
3637 break;
3638 }
3639 case NON_STRICT_ARGUMENTS_ELEMENTS: {
3640 // Ascertain whether we have read-only properties or an existing
3641 // getter/setter pair in an arguments elements dictionary backing
3642 // store.
3643 FixedArray* parameter_map = FixedArray::cast(elements());
3644 uint32_t length = parameter_map->length();
3645 Object* probe =
3646 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
3647 if (probe == NULL || probe->IsTheHole()) {
3648 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
3649 if (arguments->IsDictionary()) {
3650 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
3651 probe = FindGetterSetterInDictionary(dictionary, index, heap);
3652 if (!probe->IsTheHole()) return probe;
Steve Blocka7e24c12009-10-30 11:49:00 +00003653 }
3654 }
3655 break;
3656 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003657 }
3658 } else {
3659 // Lookup the name.
3660 LookupResult result;
3661 LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003662 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003663 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003664 if (result.type() == CALLBACKS) {
3665 Object* obj = result.GetCallbackObject();
Leon Clarkef7060e22010-06-03 12:02:55 +01003666 // Need to preserve old getters/setters.
Leon Clarked91b9f72010-01-27 17:25:45 +00003667 if (obj->IsFixedArray()) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003668 // Use set to update attributes.
3669 return SetPropertyCallback(name, obj, attributes);
Leon Clarked91b9f72010-01-27 17:25:45 +00003670 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003671 }
3672 }
3673 }
3674
3675 // Allocate the fixed array to hold getter and setter.
John Reck59135872010-11-02 12:39:01 -07003676 Object* structure;
Steve Block44f0eee2011-05-26 01:26:41 +01003677 { MaybeObject* maybe_structure = heap->AllocateFixedArray(2, TENURED);
John Reck59135872010-11-02 12:39:01 -07003678 if (!maybe_structure->ToObject(&structure)) return maybe_structure;
3679 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003680
3681 if (is_element) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003682 return SetElementCallback(index, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003683 } else {
Leon Clarkef7060e22010-06-03 12:02:55 +01003684 return SetPropertyCallback(name, structure, attributes);
Steve Blocka7e24c12009-10-30 11:49:00 +00003685 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003686}
3687
3688
3689bool JSObject::CanSetCallback(String* name) {
3690 ASSERT(!IsAccessCheckNeeded()
Steve Block44f0eee2011-05-26 01:26:41 +01003691 || Isolate::Current()->MayNamedAccess(this, name, v8::ACCESS_SET));
Leon Clarkef7060e22010-06-03 12:02:55 +01003692
3693 // Check if there is an API defined callback object which prohibits
3694 // callback overwriting in this object or it's prototype chain.
3695 // This mechanism is needed for instance in a browser setting, where
3696 // certain accessors such as window.location should not be allowed
3697 // to be overwritten because allowing overwriting could potentially
3698 // cause security problems.
3699 LookupResult callback_result;
3700 LookupCallback(name, &callback_result);
3701 if (callback_result.IsProperty()) {
3702 Object* obj = callback_result.GetCallbackObject();
3703 if (obj->IsAccessorInfo() &&
3704 AccessorInfo::cast(obj)->prohibits_overwriting()) {
3705 return false;
3706 }
3707 }
3708
3709 return true;
3710}
3711
3712
John Reck59135872010-11-02 12:39:01 -07003713MaybeObject* JSObject::SetElementCallback(uint32_t index,
3714 Object* structure,
3715 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003716 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3717
3718 // Normalize elements to make this operation simple.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003719 NumberDictionary* dictionary = NULL;
3720 { Object* result;
3721 MaybeObject* maybe = NormalizeElements();
3722 if (!maybe->ToObject(&result)) return maybe;
3723 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003724 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003725 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Leon Clarkef7060e22010-06-03 12:02:55 +01003726
3727 // Update the dictionary with the new CALLBACKS property.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003728 { Object* result;
3729 MaybeObject* maybe = dictionary->Set(index, structure, details);
3730 if (!maybe->ToObject(&result)) return maybe;
3731 dictionary = NumberDictionary::cast(result);
John Reck59135872010-11-02 12:39:01 -07003732 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003733
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003734 dictionary->set_requires_slow_elements();
3735 // Update the dictionary backing store on the object.
3736 if (elements()->map() == GetHeap()->non_strict_arguments_elements_map()) {
3737 // Also delete any parameter alias.
3738 //
3739 // TODO(kmillikin): when deleting the last parameter alias we could
3740 // switch to a direct backing store without the parameter map. This
3741 // would allow GC of the context.
3742 FixedArray* parameter_map = FixedArray::cast(elements());
3743 uint32_t length = parameter_map->length();
3744 if (index < length - 2) {
3745 parameter_map->set(index + 2, GetHeap()->the_hole_value());
3746 }
3747 parameter_map->set(1, dictionary);
3748 } else {
3749 set_elements(dictionary);
3750 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003751
3752 return structure;
3753}
3754
3755
John Reck59135872010-11-02 12:39:01 -07003756MaybeObject* JSObject::SetPropertyCallback(String* name,
3757 Object* structure,
3758 PropertyAttributes attributes) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003759 PropertyDetails details = PropertyDetails(attributes, CALLBACKS);
3760
3761 bool convert_back_to_fast = HasFastProperties() &&
3762 (map()->instance_descriptors()->number_of_descriptors()
3763 < DescriptorArray::kMaxNumberOfDescriptors);
3764
3765 // Normalize object to make this operation simple.
John Reck59135872010-11-02 12:39:01 -07003766 Object* ok;
3767 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
3768 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3769 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003770
3771 // For the global object allocate a new map to invalidate the global inline
3772 // caches which have a global property cell reference directly in the code.
3773 if (IsGlobalObject()) {
John Reck59135872010-11-02 12:39:01 -07003774 Object* new_map;
3775 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors();
3776 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
3777 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003778 set_map(Map::cast(new_map));
Ben Murdochb0fe1622011-05-05 13:52:32 +01003779 // When running crankshaft, changing the map is not enough. We
3780 // need to deoptimize all functions that rely on this global
3781 // object.
3782 Deoptimizer::DeoptimizeGlobalObject(this);
Leon Clarkef7060e22010-06-03 12:02:55 +01003783 }
3784
3785 // Update the dictionary with the new CALLBACKS property.
John Reck59135872010-11-02 12:39:01 -07003786 Object* result;
3787 { MaybeObject* maybe_result = SetNormalizedProperty(name, structure, details);
3788 if (!maybe_result->ToObject(&result)) return maybe_result;
3789 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003790
3791 if (convert_back_to_fast) {
John Reck59135872010-11-02 12:39:01 -07003792 { MaybeObject* maybe_ok = TransformToFastProperties(0);
3793 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3794 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003795 }
3796 return result;
3797}
3798
John Reck59135872010-11-02 12:39:01 -07003799MaybeObject* JSObject::DefineAccessor(String* name,
3800 bool is_getter,
Ben Murdochb0fe1622011-05-05 13:52:32 +01003801 Object* fun,
John Reck59135872010-11-02 12:39:01 -07003802 PropertyAttributes attributes) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01003803 ASSERT(fun->IsJSFunction() || fun->IsUndefined());
Steve Block44f0eee2011-05-26 01:26:41 +01003804 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00003805 // Check access rights if needed.
3806 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003807 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3808 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3809 return isolate->heap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003810 }
3811
3812 if (IsJSGlobalProxy()) {
3813 Object* proto = GetPrototype();
3814 if (proto->IsNull()) return this;
3815 ASSERT(proto->IsJSGlobalObject());
3816 return JSObject::cast(proto)->DefineAccessor(name, is_getter,
3817 fun, attributes);
3818 }
3819
John Reck59135872010-11-02 12:39:01 -07003820 Object* array;
3821 { MaybeObject* maybe_array = DefineGetterSetter(name, attributes);
3822 if (!maybe_array->ToObject(&array)) return maybe_array;
3823 }
3824 if (array->IsUndefined()) return array;
Steve Blocka7e24c12009-10-30 11:49:00 +00003825 FixedArray::cast(array)->set(is_getter ? 0 : 1, fun);
3826 return this;
3827}
3828
3829
John Reck59135872010-11-02 12:39:01 -07003830MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) {
Steve Block44f0eee2011-05-26 01:26:41 +01003831 Isolate* isolate = GetIsolate();
Leon Clarkef7060e22010-06-03 12:02:55 +01003832 String* name = String::cast(info->name());
3833 // Check access rights if needed.
3834 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003835 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) {
3836 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET);
3837 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003838 }
3839
3840 if (IsJSGlobalProxy()) {
3841 Object* proto = GetPrototype();
3842 if (proto->IsNull()) return this;
3843 ASSERT(proto->IsJSGlobalObject());
3844 return JSObject::cast(proto)->DefineAccessor(info);
3845 }
3846
3847 // Make sure that the top context does not change when doing callbacks or
3848 // interceptor calls.
3849 AssertNoContextChange ncc;
3850
3851 // Try to flatten before operating on the string.
3852 name->TryFlatten();
3853
3854 if (!CanSetCallback(name)) {
Steve Block44f0eee2011-05-26 01:26:41 +01003855 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003856 }
3857
3858 uint32_t index = 0;
3859 bool is_element = name->AsArrayIndex(&index);
3860
3861 if (is_element) {
Steve Block44f0eee2011-05-26 01:26:41 +01003862 if (IsJSArray()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003863
3864 // Accessors overwrite previous callbacks (cf. with getters/setters).
3865 switch (GetElementsKind()) {
3866 case FAST_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00003867 case FAST_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003868 break;
Steve Block44f0eee2011-05-26 01:26:41 +01003869 case EXTERNAL_PIXEL_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003870 case EXTERNAL_BYTE_ELEMENTS:
3871 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
3872 case EXTERNAL_SHORT_ELEMENTS:
3873 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
3874 case EXTERNAL_INT_ELEMENTS:
3875 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
3876 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00003877 case EXTERNAL_DOUBLE_ELEMENTS:
Leon Clarkef7060e22010-06-03 12:02:55 +01003878 // Ignore getters and setters on pixel and external array
3879 // elements.
Steve Block44f0eee2011-05-26 01:26:41 +01003880 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003881 case DICTIONARY_ELEMENTS:
3882 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00003883 case NON_STRICT_ARGUMENTS_ELEMENTS:
3884 UNIMPLEMENTED();
Leon Clarkef7060e22010-06-03 12:02:55 +01003885 break;
3886 }
3887
John Reck59135872010-11-02 12:39:01 -07003888 Object* ok;
3889 { MaybeObject* maybe_ok =
3890 SetElementCallback(index, info, info->property_attributes());
3891 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3892 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003893 } else {
3894 // Lookup the name.
3895 LookupResult result;
3896 LocalLookup(name, &result);
3897 // ES5 forbids turning a property into an accessor if it's not
3898 // configurable (that is IsDontDelete in ES3 and v8), see 8.6.1 (Table 5).
3899 if (result.IsProperty() && (result.IsReadOnly() || result.IsDontDelete())) {
Steve Block44f0eee2011-05-26 01:26:41 +01003900 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01003901 }
John Reck59135872010-11-02 12:39:01 -07003902 Object* ok;
3903 { MaybeObject* maybe_ok =
3904 SetPropertyCallback(name, info, info->property_attributes());
3905 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3906 }
Leon Clarkef7060e22010-06-03 12:02:55 +01003907 }
3908
3909 return this;
3910}
3911
3912
Steve Blocka7e24c12009-10-30 11:49:00 +00003913Object* JSObject::LookupAccessor(String* name, bool is_getter) {
Steve Block44f0eee2011-05-26 01:26:41 +01003914 Heap* heap = GetHeap();
3915
Steve Blocka7e24c12009-10-30 11:49:00 +00003916 // Make sure that the top context does not change when doing callbacks or
3917 // interceptor calls.
3918 AssertNoContextChange ncc;
3919
3920 // Check access rights if needed.
3921 if (IsAccessCheckNeeded() &&
Steve Block44f0eee2011-05-26 01:26:41 +01003922 !heap->isolate()->MayNamedAccess(this, name, v8::ACCESS_HAS)) {
3923 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
3924 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003925 }
3926
3927 // Make the lookup and include prototypes.
3928 int accessor_index = is_getter ? kGetterIndex : kSetterIndex;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003929 uint32_t index = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00003930 if (name->AsArrayIndex(&index)) {
3931 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003932 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003933 obj = JSObject::cast(obj)->GetPrototype()) {
3934 JSObject* js_object = JSObject::cast(obj);
3935 if (js_object->HasDictionaryElements()) {
3936 NumberDictionary* dictionary = js_object->element_dictionary();
3937 int entry = dictionary->FindEntry(index);
3938 if (entry != NumberDictionary::kNotFound) {
3939 Object* element = dictionary->ValueAt(entry);
3940 PropertyDetails details = dictionary->DetailsAt(entry);
3941 if (details.type() == CALLBACKS) {
Leon Clarkef7060e22010-06-03 12:02:55 +01003942 if (element->IsFixedArray()) {
3943 return FixedArray::cast(element)->get(accessor_index);
3944 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003945 }
3946 }
3947 }
3948 }
3949 } else {
3950 for (Object* obj = this;
Steve Block44f0eee2011-05-26 01:26:41 +01003951 obj != heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003952 obj = JSObject::cast(obj)->GetPrototype()) {
3953 LookupResult result;
3954 JSObject::cast(obj)->LocalLookup(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00003955 if (result.IsProperty()) {
Steve Block44f0eee2011-05-26 01:26:41 +01003956 if (result.IsReadOnly()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003957 if (result.type() == CALLBACKS) {
3958 Object* obj = result.GetCallbackObject();
3959 if (obj->IsFixedArray()) {
3960 return FixedArray::cast(obj)->get(accessor_index);
3961 }
3962 }
3963 }
3964 }
3965 }
Steve Block44f0eee2011-05-26 01:26:41 +01003966 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003967}
3968
3969
3970Object* JSObject::SlowReverseLookup(Object* value) {
3971 if (HasFastProperties()) {
3972 DescriptorArray* descs = map()->instance_descriptors();
3973 for (int i = 0; i < descs->number_of_descriptors(); i++) {
3974 if (descs->GetType(i) == FIELD) {
3975 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) {
3976 return descs->GetKey(i);
3977 }
3978 } else if (descs->GetType(i) == CONSTANT_FUNCTION) {
3979 if (descs->GetConstantFunction(i) == value) {
3980 return descs->GetKey(i);
3981 }
3982 }
3983 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01003984 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00003985 } else {
3986 return property_dictionary()->SlowReverseLookup(value);
3987 }
3988}
3989
3990
John Reck59135872010-11-02 12:39:01 -07003991MaybeObject* Map::CopyDropDescriptors() {
Steve Block44f0eee2011-05-26 01:26:41 +01003992 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -07003993 Object* result;
3994 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01003995 heap->AllocateMap(instance_type(), instance_size());
John Reck59135872010-11-02 12:39:01 -07003996 if (!maybe_result->ToObject(&result)) return maybe_result;
3997 }
Steve Blocka7e24c12009-10-30 11:49:00 +00003998 Map::cast(result)->set_prototype(prototype());
3999 Map::cast(result)->set_constructor(constructor());
4000 // Don't copy descriptors, so map transitions always remain a forest.
4001 // If we retained the same descriptors we would have two maps
4002 // pointing to the same transition which is bad because the garbage
4003 // collector relies on being able to reverse pointers from transitions
4004 // to maps. If properties need to be retained use CopyDropTransitions.
Ben Murdoch257744e2011-11-30 15:57:28 +00004005 Map::cast(result)->clear_instance_descriptors();
Steve Blocka7e24c12009-10-30 11:49:00 +00004006 // Please note instance_type and instance_size are set when allocated.
4007 Map::cast(result)->set_inobject_properties(inobject_properties());
4008 Map::cast(result)->set_unused_property_fields(unused_property_fields());
4009
4010 // If the map has pre-allocated properties always start out with a descriptor
4011 // array describing these properties.
4012 if (pre_allocated_property_fields() > 0) {
4013 ASSERT(constructor()->IsJSFunction());
4014 JSFunction* ctor = JSFunction::cast(constructor());
John Reck59135872010-11-02 12:39:01 -07004015 Object* descriptors;
4016 { MaybeObject* maybe_descriptors =
4017 ctor->initial_map()->instance_descriptors()->RemoveTransitions();
4018 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4019 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004020 Map::cast(result)->set_instance_descriptors(
4021 DescriptorArray::cast(descriptors));
4022 Map::cast(result)->set_pre_allocated_property_fields(
4023 pre_allocated_property_fields());
4024 }
4025 Map::cast(result)->set_bit_field(bit_field());
4026 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004027 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004028 Map::cast(result)->set_is_shared(false);
Steve Block44f0eee2011-05-26 01:26:41 +01004029 Map::cast(result)->ClearCodeCache(heap);
Steve Blocka7e24c12009-10-30 11:49:00 +00004030 return result;
4031}
4032
4033
John Reck59135872010-11-02 12:39:01 -07004034MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode,
4035 NormalizedMapSharingMode sharing) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004036 int new_instance_size = instance_size();
4037 if (mode == CLEAR_INOBJECT_PROPERTIES) {
4038 new_instance_size -= inobject_properties() * kPointerSize;
4039 }
4040
John Reck59135872010-11-02 12:39:01 -07004041 Object* result;
4042 { MaybeObject* maybe_result =
Steve Block44f0eee2011-05-26 01:26:41 +01004043 GetHeap()->AllocateMap(instance_type(), new_instance_size);
John Reck59135872010-11-02 12:39:01 -07004044 if (!maybe_result->ToObject(&result)) return maybe_result;
4045 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004046
4047 if (mode != CLEAR_INOBJECT_PROPERTIES) {
4048 Map::cast(result)->set_inobject_properties(inobject_properties());
4049 }
4050
4051 Map::cast(result)->set_prototype(prototype());
4052 Map::cast(result)->set_constructor(constructor());
4053
4054 Map::cast(result)->set_bit_field(bit_field());
4055 Map::cast(result)->set_bit_field2(bit_field2());
Ben Murdoch257744e2011-11-30 15:57:28 +00004056 Map::cast(result)->set_bit_field3(bit_field3());
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004057
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004058 Map::cast(result)->set_is_shared(sharing == SHARED_NORMALIZED_MAP);
4059
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004060#ifdef DEBUG
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004061 if (Map::cast(result)->is_shared()) {
4062 Map::cast(result)->SharedMapVerify();
4063 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01004064#endif
4065
4066 return result;
4067}
4068
4069
John Reck59135872010-11-02 12:39:01 -07004070MaybeObject* Map::CopyDropTransitions() {
4071 Object* new_map;
4072 { MaybeObject* maybe_new_map = CopyDropDescriptors();
4073 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
4074 }
4075 Object* descriptors;
4076 { MaybeObject* maybe_descriptors =
4077 instance_descriptors()->RemoveTransitions();
4078 if (!maybe_descriptors->ToObject(&descriptors)) return maybe_descriptors;
4079 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004080 cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
Steve Block8defd9f2010-07-08 12:39:36 +01004081 return new_map;
Steve Blocka7e24c12009-10-30 11:49:00 +00004082}
4083
4084
John Reck59135872010-11-02 12:39:01 -07004085MaybeObject* Map::UpdateCodeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004086 // Allocate the code cache if not present.
4087 if (code_cache()->IsFixedArray()) {
John Reck59135872010-11-02 12:39:01 -07004088 Object* result;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004089 { MaybeObject* maybe_result = code->heap()->AllocateCodeCache();
John Reck59135872010-11-02 12:39:01 -07004090 if (!maybe_result->ToObject(&result)) return maybe_result;
4091 }
Steve Block6ded16b2010-05-10 14:33:55 +01004092 set_code_cache(result);
4093 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004094
Steve Block6ded16b2010-05-10 14:33:55 +01004095 // Update the code cache.
4096 return CodeCache::cast(code_cache())->Update(name, code);
4097}
4098
4099
4100Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
4101 // Do a lookup if a code cache exists.
4102 if (!code_cache()->IsFixedArray()) {
4103 return CodeCache::cast(code_cache())->Lookup(name, flags);
4104 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004105 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004106 }
4107}
4108
4109
4110int Map::IndexInCodeCache(Object* name, Code* code) {
4111 // Get the internal index if a code cache exists.
4112 if (!code_cache()->IsFixedArray()) {
4113 return CodeCache::cast(code_cache())->GetIndex(name, code);
4114 }
4115 return -1;
4116}
4117
4118
4119void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
4120 // No GC is supposed to happen between a call to IndexInCodeCache and
4121 // RemoveFromCodeCache so the code cache must be there.
4122 ASSERT(!code_cache()->IsFixedArray());
4123 CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
4124}
4125
4126
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004127void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
Steve Block053d10c2011-06-13 19:13:29 +01004128 // Traverse the transition tree without using a stack. We do this by
4129 // reversing the pointers in the maps and descriptor arrays.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004130 Map* current = this;
Steve Block44f0eee2011-05-26 01:26:41 +01004131 Map* meta_map = heap()->meta_map();
Steve Block053d10c2011-06-13 19:13:29 +01004132 Object** map_or_index_field = NULL;
Steve Block44f0eee2011-05-26 01:26:41 +01004133 while (current != meta_map) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004134 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00004135 *RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
Steve Block053d10c2011-06-13 19:13:29 +01004136 if (!d->IsEmpty()) {
4137 FixedArray* contents = reinterpret_cast<FixedArray*>(
4138 d->get(DescriptorArray::kContentArrayIndex));
4139 map_or_index_field = RawField(contents, HeapObject::kMapOffset);
4140 Object* map_or_index = *map_or_index_field;
4141 bool map_done = true; // Controls a nested continue statement.
4142 for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
4143 i < contents->length();
4144 i += 2) {
4145 PropertyDetails details(Smi::cast(contents->get(i + 1)));
4146 if (details.IsTransition()) {
4147 // Found a map in the transition array. We record our progress in
4148 // the transition array by recording the current map in the map field
4149 // of the next map and recording the index in the transition array in
4150 // the map field of the array.
4151 Map* next = Map::cast(contents->get(i));
4152 next->set_map(current);
4153 *map_or_index_field = Smi::FromInt(i + 2);
4154 current = next;
4155 map_done = false;
4156 break;
4157 }
4158 }
4159 if (!map_done) continue;
Ben Murdoch7d3e7fc2011-07-12 16:37:06 +01004160 } else {
4161 map_or_index_field = NULL;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004162 }
Steve Block053d10c2011-06-13 19:13:29 +01004163 // That was the regular transitions, now for the prototype transitions.
4164 FixedArray* prototype_transitions =
4165 current->unchecked_prototype_transitions();
4166 Object** proto_map_or_index_field =
4167 RawField(prototype_transitions, HeapObject::kMapOffset);
4168 Object* map_or_index = *proto_map_or_index_field;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004169 const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
Steve Block053d10c2011-06-13 19:13:29 +01004170 int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
4171 if (i < prototype_transitions->length()) {
4172 // Found a map in the prototype transition array. Record progress in
4173 // an analogous way to the regular transitions array above.
4174 Object* perhaps_map = prototype_transitions->get(i);
4175 if (perhaps_map->IsMap()) {
4176 Map* next = Map::cast(perhaps_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004177 next->set_map(current);
Steve Block053d10c2011-06-13 19:13:29 +01004178 *proto_map_or_index_field =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004179 Smi::FromInt(i + kProtoTransitionElementsPerEntry);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004180 current = next;
Steve Block053d10c2011-06-13 19:13:29 +01004181 continue;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004182 }
4183 }
Steve Block053d10c2011-06-13 19:13:29 +01004184 *proto_map_or_index_field = heap()->fixed_array_map();
4185 if (map_or_index_field != NULL) {
4186 *map_or_index_field = heap()->fixed_array_map();
4187 }
4188
4189 // The callback expects a map to have a real map as its map, so we save
4190 // the map field, which is being used to track the traversal and put the
4191 // correct map (the meta_map) in place while we do the callback.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004192 Map* prev = current->map();
Steve Block44f0eee2011-05-26 01:26:41 +01004193 current->set_map(meta_map);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004194 callback(current, data);
4195 current = prev;
4196 }
4197}
4198
4199
John Reck59135872010-11-02 12:39:01 -07004200MaybeObject* CodeCache::Update(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004201 // The number of monomorphic stubs for normal load/store/call IC's can grow to
4202 // a large number and therefore they need to go into a hash table. They are
4203 // used to load global properties from cells.
4204 if (code->type() == NORMAL) {
4205 // Make sure that a hash table is allocated for the normal load code cache.
4206 if (normal_type_cache()->IsUndefined()) {
John Reck59135872010-11-02 12:39:01 -07004207 Object* result;
4208 { MaybeObject* maybe_result =
4209 CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
4210 if (!maybe_result->ToObject(&result)) return maybe_result;
4211 }
Steve Block6ded16b2010-05-10 14:33:55 +01004212 set_normal_type_cache(result);
4213 }
4214 return UpdateNormalTypeCache(name, code);
4215 } else {
4216 ASSERT(default_cache()->IsFixedArray());
4217 return UpdateDefaultCache(name, code);
4218 }
4219}
4220
4221
John Reck59135872010-11-02 12:39:01 -07004222MaybeObject* CodeCache::UpdateDefaultCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004223 // When updating the default code cache we disregard the type encoded in the
Steve Blocka7e24c12009-10-30 11:49:00 +00004224 // flags. This allows call constant stubs to overwrite call field
4225 // stubs, etc.
4226 Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
4227
4228 // First check whether we can update existing code cache without
4229 // extending it.
Steve Block6ded16b2010-05-10 14:33:55 +01004230 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004231 int length = cache->length();
4232 int deleted_index = -1;
Steve Block6ded16b2010-05-10 14:33:55 +01004233 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004234 Object* key = cache->get(i);
4235 if (key->IsNull()) {
4236 if (deleted_index < 0) deleted_index = i;
4237 continue;
4238 }
4239 if (key->IsUndefined()) {
4240 if (deleted_index >= 0) i = deleted_index;
Steve Block6ded16b2010-05-10 14:33:55 +01004241 cache->set(i + kCodeCacheEntryNameOffset, name);
4242 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004243 return this;
4244 }
4245 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004246 Code::Flags found =
4247 Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
Steve Blocka7e24c12009-10-30 11:49:00 +00004248 if (Code::RemoveTypeFromFlags(found) == flags) {
Steve Block6ded16b2010-05-10 14:33:55 +01004249 cache->set(i + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004250 return this;
4251 }
4252 }
4253 }
4254
4255 // Reached the end of the code cache. If there were deleted
4256 // elements, reuse the space for the first of them.
4257 if (deleted_index >= 0) {
Steve Block6ded16b2010-05-10 14:33:55 +01004258 cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
4259 cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
Steve Blocka7e24c12009-10-30 11:49:00 +00004260 return this;
4261 }
4262
Steve Block6ded16b2010-05-10 14:33:55 +01004263 // Extend the code cache with some new entries (at least one). Must be a
4264 // multiple of the entry size.
4265 int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
4266 new_length = new_length - new_length % kCodeCacheEntrySize;
4267 ASSERT((new_length % kCodeCacheEntrySize) == 0);
John Reck59135872010-11-02 12:39:01 -07004268 Object* result;
4269 { MaybeObject* maybe_result = cache->CopySize(new_length);
4270 if (!maybe_result->ToObject(&result)) return maybe_result;
4271 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004272
4273 // Add the (name, code) pair to the new cache.
4274 cache = FixedArray::cast(result);
Steve Block6ded16b2010-05-10 14:33:55 +01004275 cache->set(length + kCodeCacheEntryNameOffset, name);
4276 cache->set(length + kCodeCacheEntryCodeOffset, code);
4277 set_default_cache(cache);
Steve Blocka7e24c12009-10-30 11:49:00 +00004278 return this;
4279}
4280
4281
John Reck59135872010-11-02 12:39:01 -07004282MaybeObject* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004283 // Adding a new entry can cause a new cache to be allocated.
4284 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
John Reck59135872010-11-02 12:39:01 -07004285 Object* new_cache;
4286 { MaybeObject* maybe_new_cache = cache->Put(name, code);
4287 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4288 }
Steve Block6ded16b2010-05-10 14:33:55 +01004289 set_normal_type_cache(new_cache);
4290 return this;
4291}
4292
4293
4294Object* CodeCache::Lookup(String* name, Code::Flags flags) {
4295 if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
4296 return LookupNormalTypeCache(name, flags);
4297 } else {
4298 return LookupDefaultCache(name, flags);
4299 }
4300}
4301
4302
4303Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
4304 FixedArray* cache = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004305 int length = cache->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004306 for (int i = 0; i < length; i += kCodeCacheEntrySize) {
4307 Object* key = cache->get(i + kCodeCacheEntryNameOffset);
Steve Blocka7e24c12009-10-30 11:49:00 +00004308 // Skip deleted elements.
4309 if (key->IsNull()) continue;
4310 if (key->IsUndefined()) return key;
4311 if (name->Equals(String::cast(key))) {
Steve Block6ded16b2010-05-10 14:33:55 +01004312 Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
4313 if (code->flags() == flags) {
4314 return code;
4315 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004316 }
4317 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01004318 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00004319}
4320
4321
Steve Block6ded16b2010-05-10 14:33:55 +01004322Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
4323 if (!normal_type_cache()->IsUndefined()) {
4324 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4325 return cache->Lookup(name, flags);
4326 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01004327 return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004328 }
4329}
4330
4331
4332int CodeCache::GetIndex(Object* name, Code* code) {
4333 if (code->type() == NORMAL) {
4334 if (normal_type_cache()->IsUndefined()) return -1;
4335 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4336 return cache->GetIndex(String::cast(name), code->flags());
4337 }
4338
4339 FixedArray* array = default_cache();
Steve Blocka7e24c12009-10-30 11:49:00 +00004340 int len = array->length();
Steve Block6ded16b2010-05-10 14:33:55 +01004341 for (int i = 0; i < len; i += kCodeCacheEntrySize) {
4342 if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004343 }
4344 return -1;
4345}
4346
4347
Steve Block6ded16b2010-05-10 14:33:55 +01004348void CodeCache::RemoveByIndex(Object* name, Code* code, int index) {
4349 if (code->type() == NORMAL) {
4350 ASSERT(!normal_type_cache()->IsUndefined());
4351 CodeCacheHashTable* cache = CodeCacheHashTable::cast(normal_type_cache());
4352 ASSERT(cache->GetIndex(String::cast(name), code->flags()) == index);
4353 cache->RemoveByIndex(index);
4354 } else {
4355 FixedArray* array = default_cache();
4356 ASSERT(array->length() >= index && array->get(index)->IsCode());
4357 // Use null instead of undefined for deleted elements to distinguish
4358 // deleted elements from unused elements. This distinction is used
4359 // when looking up in the cache and when updating the cache.
4360 ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
4361 array->set_null(index - 1); // Name.
4362 array->set_null(index); // Code.
4363 }
4364}
4365
4366
4367// The key in the code cache hash table consists of the property name and the
4368// code object. The actual match is on the name and the code flags. If a key
4369// is created using the flags and not a code object it can only be used for
4370// lookup not to create a new entry.
4371class CodeCacheHashTableKey : public HashTableKey {
4372 public:
4373 CodeCacheHashTableKey(String* name, Code::Flags flags)
4374 : name_(name), flags_(flags), code_(NULL) { }
4375
4376 CodeCacheHashTableKey(String* name, Code* code)
4377 : name_(name),
4378 flags_(code->flags()),
4379 code_(code) { }
4380
4381
4382 bool IsMatch(Object* other) {
4383 if (!other->IsFixedArray()) return false;
4384 FixedArray* pair = FixedArray::cast(other);
4385 String* name = String::cast(pair->get(0));
4386 Code::Flags flags = Code::cast(pair->get(1))->flags();
4387 if (flags != flags_) {
4388 return false;
4389 }
4390 return name_->Equals(name);
4391 }
4392
4393 static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
4394 return name->Hash() ^ flags;
4395 }
4396
4397 uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
4398
4399 uint32_t HashForObject(Object* obj) {
4400 FixedArray* pair = FixedArray::cast(obj);
4401 String* name = String::cast(pair->get(0));
4402 Code* code = Code::cast(pair->get(1));
4403 return NameFlagsHashHelper(name, code->flags());
4404 }
4405
John Reck59135872010-11-02 12:39:01 -07004406 MUST_USE_RESULT MaybeObject* AsObject() {
Steve Block6ded16b2010-05-10 14:33:55 +01004407 ASSERT(code_ != NULL);
John Reck59135872010-11-02 12:39:01 -07004408 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01004409 { MaybeObject* maybe_obj = code_->heap()->AllocateFixedArray(2);
John Reck59135872010-11-02 12:39:01 -07004410 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4411 }
Steve Block6ded16b2010-05-10 14:33:55 +01004412 FixedArray* pair = FixedArray::cast(obj);
4413 pair->set(0, name_);
4414 pair->set(1, code_);
4415 return pair;
4416 }
4417
4418 private:
4419 String* name_;
4420 Code::Flags flags_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004421 // TODO(jkummerow): We should be able to get by without this.
Steve Block6ded16b2010-05-10 14:33:55 +01004422 Code* code_;
4423};
4424
4425
4426Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
4427 CodeCacheHashTableKey key(name, flags);
4428 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +01004429 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Block6ded16b2010-05-10 14:33:55 +01004430 return get(EntryToIndex(entry) + 1);
4431}
4432
4433
John Reck59135872010-11-02 12:39:01 -07004434MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
Steve Block6ded16b2010-05-10 14:33:55 +01004435 CodeCacheHashTableKey key(name, code);
John Reck59135872010-11-02 12:39:01 -07004436 Object* obj;
4437 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4438 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4439 }
Steve Block6ded16b2010-05-10 14:33:55 +01004440
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004441 // Don't use |this|, as the table might have grown.
Steve Block6ded16b2010-05-10 14:33:55 +01004442 CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
4443
4444 int entry = cache->FindInsertionEntry(key.Hash());
John Reck59135872010-11-02 12:39:01 -07004445 Object* k;
4446 { MaybeObject* maybe_k = key.AsObject();
4447 if (!maybe_k->ToObject(&k)) return maybe_k;
4448 }
Steve Block6ded16b2010-05-10 14:33:55 +01004449
4450 cache->set(EntryToIndex(entry), k);
4451 cache->set(EntryToIndex(entry) + 1, code);
4452 cache->ElementAdded();
4453 return cache;
4454}
4455
4456
4457int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
4458 CodeCacheHashTableKey key(name, flags);
4459 int entry = FindEntry(&key);
4460 return (entry == kNotFound) ? -1 : entry;
4461}
4462
4463
4464void CodeCacheHashTable::RemoveByIndex(int index) {
4465 ASSERT(index >= 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004466 Heap* heap = GetHeap();
4467 set(EntryToIndex(index), heap->null_value());
4468 set(EntryToIndex(index) + 1, heap->null_value());
Steve Block6ded16b2010-05-10 14:33:55 +01004469 ElementRemoved();
Steve Blocka7e24c12009-10-30 11:49:00 +00004470}
4471
4472
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004473MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
4474 Code::Flags flags,
4475 Code* code) {
4476 // Initialize cache if necessary.
4477 if (cache()->IsUndefined()) {
4478 Object* result;
4479 { MaybeObject* maybe_result =
4480 PolymorphicCodeCacheHashTable::Allocate(
4481 PolymorphicCodeCacheHashTable::kInitialSize);
4482 if (!maybe_result->ToObject(&result)) return maybe_result;
4483 }
4484 set_cache(result);
4485 } else {
4486 // This entry shouldn't be contained in the cache yet.
4487 ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
4488 ->Lookup(maps, flags)->IsUndefined());
4489 }
4490 PolymorphicCodeCacheHashTable* hash_table =
4491 PolymorphicCodeCacheHashTable::cast(cache());
4492 Object* new_cache;
4493 { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
4494 if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
4495 }
4496 set_cache(new_cache);
4497 return this;
4498}
4499
4500
4501Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
4502 if (!cache()->IsUndefined()) {
4503 PolymorphicCodeCacheHashTable* hash_table =
4504 PolymorphicCodeCacheHashTable::cast(cache());
4505 return hash_table->Lookup(maps, flags);
4506 } else {
4507 return GetHeap()->undefined_value();
4508 }
4509}
4510
4511
4512// Despite their name, object of this class are not stored in the actual
4513// hash table; instead they're temporarily used for lookups. It is therefore
4514// safe to have a weak (non-owning) pointer to a MapList as a member field.
4515class PolymorphicCodeCacheHashTableKey : public HashTableKey {
4516 public:
4517 // Callers must ensure that |maps| outlives the newly constructed object.
4518 PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
4519 : maps_(maps),
4520 code_flags_(code_flags) {}
4521
4522 bool IsMatch(Object* other) {
4523 MapList other_maps(kDefaultListAllocationSize);
4524 int other_flags;
4525 FromObject(other, &other_flags, &other_maps);
4526 if (code_flags_ != other_flags) return false;
4527 if (maps_->length() != other_maps.length()) return false;
4528 // Compare just the hashes first because it's faster.
4529 int this_hash = MapsHashHelper(maps_, code_flags_);
4530 int other_hash = MapsHashHelper(&other_maps, other_flags);
4531 if (this_hash != other_hash) return false;
4532
4533 // Full comparison: for each map in maps_, look for an equivalent map in
4534 // other_maps. This implementation is slow, but probably good enough for
4535 // now because the lists are short (<= 4 elements currently).
4536 for (int i = 0; i < maps_->length(); ++i) {
4537 bool match_found = false;
4538 for (int j = 0; j < other_maps.length(); ++j) {
4539 if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
4540 match_found = true;
4541 break;
4542 }
4543 }
4544 if (!match_found) return false;
4545 }
4546 return true;
4547 }
4548
4549 static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
4550 uint32_t hash = code_flags;
4551 for (int i = 0; i < maps->length(); ++i) {
4552 hash ^= maps->at(i)->Hash();
4553 }
4554 return hash;
4555 }
4556
4557 uint32_t Hash() {
4558 return MapsHashHelper(maps_, code_flags_);
4559 }
4560
4561 uint32_t HashForObject(Object* obj) {
4562 MapList other_maps(kDefaultListAllocationSize);
4563 int other_flags;
4564 FromObject(obj, &other_flags, &other_maps);
4565 return MapsHashHelper(&other_maps, other_flags);
4566 }
4567
4568 MUST_USE_RESULT MaybeObject* AsObject() {
4569 Object* obj;
4570 // The maps in |maps_| must be copied to a newly allocated FixedArray,
4571 // both because the referenced MapList is short-lived, and because C++
4572 // objects can't be stored in the heap anyway.
4573 { MaybeObject* maybe_obj =
4574 HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
4575 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4576 }
4577 FixedArray* list = FixedArray::cast(obj);
4578 list->set(0, Smi::FromInt(code_flags_));
4579 for (int i = 0; i < maps_->length(); ++i) {
4580 list->set(i + 1, maps_->at(i));
4581 }
4582 return list;
4583 }
4584
4585 private:
4586 static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
4587 FixedArray* list = FixedArray::cast(obj);
4588 maps->Rewind(0);
4589 *code_flags = Smi::cast(list->get(0))->value();
4590 for (int i = 1; i < list->length(); ++i) {
4591 maps->Add(Map::cast(list->get(i)));
4592 }
4593 return maps;
4594 }
4595
4596 MapList* maps_; // weak.
4597 int code_flags_;
4598 static const int kDefaultListAllocationSize = kMaxKeyedPolymorphism + 1;
4599};
4600
4601
4602Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
4603 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4604 int entry = FindEntry(&key);
4605 if (entry == kNotFound) return GetHeap()->undefined_value();
4606 return get(EntryToIndex(entry) + 1);
4607}
4608
4609
4610MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
4611 int code_flags,
4612 Code* code) {
4613 PolymorphicCodeCacheHashTableKey key(maps, code_flags);
4614 Object* obj;
4615 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
4616 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4617 }
4618 PolymorphicCodeCacheHashTable* cache =
4619 reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
4620 int entry = cache->FindInsertionEntry(key.Hash());
4621 { MaybeObject* maybe_obj = key.AsObject();
4622 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4623 }
4624 cache->set(EntryToIndex(entry), obj);
4625 cache->set(EntryToIndex(entry) + 1, code);
4626 cache->ElementAdded();
4627 return cache;
4628}
4629
4630
John Reck59135872010-11-02 12:39:01 -07004631MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004632 ElementsAccessor* accessor = array->GetElementsAccessor();
4633 MaybeObject* maybe_result =
4634 accessor->AddElementsToFixedArray(array->elements(), this, array, array);
4635 FixedArray* result;
4636 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
4637#ifdef DEBUG
4638 if (FLAG_enable_slow_asserts) {
4639 for (int i = 0; i < result->length(); i++) {
4640 Object* current = result->get(i);
4641 ASSERT(current->IsNumber() || current->IsString());
Steve Blocka7e24c12009-10-30 11:49:00 +00004642 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004643 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004644#endif
4645 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004646}
4647
4648
John Reck59135872010-11-02 12:39:01 -07004649MaybeObject* FixedArray::UnionOfKeys(FixedArray* other) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004650 ElementsAccessor* accessor = ElementsAccessor::ForArray(other);
4651 MaybeObject* maybe_result =
4652 accessor->AddElementsToFixedArray(other, this, NULL, NULL);
4653 FixedArray* result;
4654 if (!maybe_result->To<FixedArray>(&result)) return maybe_result;
Ben Murdochf87a2032010-10-22 12:50:53 +01004655#ifdef DEBUG
4656 if (FLAG_enable_slow_asserts) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00004657 for (int i = 0; i < result->length(); i++) {
4658 Object* current = result->get(i);
4659 ASSERT(current->IsNumber() || current->IsString());
Ben Murdochf87a2032010-10-22 12:50:53 +01004660 }
4661 }
4662#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00004663 return result;
4664}
4665
4666
John Reck59135872010-11-02 12:39:01 -07004667MaybeObject* FixedArray::CopySize(int new_length) {
Steve Block44f0eee2011-05-26 01:26:41 +01004668 Heap* heap = GetHeap();
4669 if (new_length == 0) return heap->empty_fixed_array();
John Reck59135872010-11-02 12:39:01 -07004670 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01004671 { MaybeObject* maybe_obj = heap->AllocateFixedArray(new_length);
John Reck59135872010-11-02 12:39:01 -07004672 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
4673 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004674 FixedArray* result = FixedArray::cast(obj);
4675 // Copy the content
Leon Clarke4515c472010-02-03 11:58:03 +00004676 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00004677 int len = length();
4678 if (new_length < len) len = new_length;
4679 result->set_map(map());
Leon Clarke4515c472010-02-03 11:58:03 +00004680 WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004681 for (int i = 0; i < len; i++) {
4682 result->set(i, get(i), mode);
4683 }
4684 return result;
4685}
4686
4687
4688void FixedArray::CopyTo(int pos, FixedArray* dest, int dest_pos, int len) {
Leon Clarke4515c472010-02-03 11:58:03 +00004689 AssertNoAllocation no_gc;
4690 WriteBarrierMode mode = dest->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00004691 for (int index = 0; index < len; index++) {
4692 dest->set(dest_pos+index, get(pos+index), mode);
4693 }
4694}
4695
4696
4697#ifdef DEBUG
4698bool FixedArray::IsEqualTo(FixedArray* other) {
4699 if (length() != other->length()) return false;
4700 for (int i = 0 ; i < length(); ++i) {
4701 if (get(i) != other->get(i)) return false;
4702 }
4703 return true;
4704}
4705#endif
4706
4707
John Reck59135872010-11-02 12:39:01 -07004708MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) {
Steve Block44f0eee2011-05-26 01:26:41 +01004709 Heap* heap = Isolate::Current()->heap();
Steve Blocka7e24c12009-10-30 11:49:00 +00004710 if (number_of_descriptors == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01004711 return heap->empty_descriptor_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00004712 }
4713 // Allocate the array of keys.
John Reck59135872010-11-02 12:39:01 -07004714 Object* array;
4715 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004716 heap->AllocateFixedArray(ToKeyIndex(number_of_descriptors));
John Reck59135872010-11-02 12:39:01 -07004717 if (!maybe_array->ToObject(&array)) return maybe_array;
4718 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004719 // Do not use DescriptorArray::cast on incomplete object.
4720 FixedArray* result = FixedArray::cast(array);
4721
4722 // Allocate the content array and set it in the descriptor array.
John Reck59135872010-11-02 12:39:01 -07004723 { MaybeObject* maybe_array =
Steve Block44f0eee2011-05-26 01:26:41 +01004724 heap->AllocateFixedArray(number_of_descriptors << 1);
John Reck59135872010-11-02 12:39:01 -07004725 if (!maybe_array->ToObject(&array)) return maybe_array;
4726 }
Ben Murdoch257744e2011-11-30 15:57:28 +00004727 result->set(kBitField3StorageIndex, Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00004728 result->set(kContentArrayIndex, array);
4729 result->set(kEnumerationIndexIndex,
Leon Clarke4515c472010-02-03 11:58:03 +00004730 Smi::FromInt(PropertyDetails::kInitialIndex));
Steve Blocka7e24c12009-10-30 11:49:00 +00004731 return result;
4732}
4733
4734
4735void DescriptorArray::SetEnumCache(FixedArray* bridge_storage,
4736 FixedArray* new_cache) {
4737 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength);
4738 if (HasEnumCache()) {
4739 FixedArray::cast(get(kEnumerationIndexIndex))->
4740 set(kEnumCacheBridgeCacheIndex, new_cache);
4741 } else {
4742 if (IsEmpty()) return; // Do nothing for empty descriptor array.
4743 FixedArray::cast(bridge_storage)->
4744 set(kEnumCacheBridgeCacheIndex, new_cache);
4745 fast_set(FixedArray::cast(bridge_storage),
4746 kEnumCacheBridgeEnumIndex,
4747 get(kEnumerationIndexIndex));
4748 set(kEnumerationIndexIndex, bridge_storage);
4749 }
4750}
4751
4752
John Reck59135872010-11-02 12:39:01 -07004753MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor,
4754 TransitionFlag transition_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00004755 // Transitions are only kept when inserting another transition.
4756 // This precondition is not required by this function's implementation, but
4757 // is currently required by the semantics of maps, so we check it.
4758 // Conversely, we filter after replacing, so replacing a transition and
4759 // removing all other transitions is not supported.
4760 bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
4761 ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
4762 ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
4763
4764 // Ensure the key is a symbol.
John Reck59135872010-11-02 12:39:01 -07004765 Object* result;
4766 { MaybeObject* maybe_result = descriptor->KeyToSymbol();
4767 if (!maybe_result->ToObject(&result)) return maybe_result;
4768 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004769
4770 int transitions = 0;
4771 int null_descriptors = 0;
4772 if (remove_transitions) {
4773 for (int i = 0; i < number_of_descriptors(); i++) {
4774 if (IsTransition(i)) transitions++;
4775 if (IsNullDescriptor(i)) null_descriptors++;
4776 }
4777 } else {
4778 for (int i = 0; i < number_of_descriptors(); i++) {
4779 if (IsNullDescriptor(i)) null_descriptors++;
4780 }
4781 }
4782 int new_size = number_of_descriptors() - transitions - null_descriptors;
4783
4784 // If key is in descriptor, we replace it in-place when filtering.
4785 // Count a null descriptor for key as inserted, not replaced.
4786 int index = Search(descriptor->GetKey());
4787 const bool inserting = (index == kNotFound);
4788 const bool replacing = !inserting;
4789 bool keep_enumeration_index = false;
4790 if (inserting) {
4791 ++new_size;
4792 }
4793 if (replacing) {
4794 // We are replacing an existing descriptor. We keep the enumeration
4795 // index of a visible property.
4796 PropertyType t = PropertyDetails(GetDetails(index)).type();
4797 if (t == CONSTANT_FUNCTION ||
4798 t == FIELD ||
4799 t == CALLBACKS ||
4800 t == INTERCEPTOR) {
4801 keep_enumeration_index = true;
4802 } else if (remove_transitions) {
4803 // Replaced descriptor has been counted as removed if it is
4804 // a transition that will be replaced. Adjust count in this case.
4805 ++new_size;
4806 }
4807 }
John Reck59135872010-11-02 12:39:01 -07004808 { MaybeObject* maybe_result = Allocate(new_size);
4809 if (!maybe_result->ToObject(&result)) return maybe_result;
4810 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004811 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4812 // Set the enumeration index in the descriptors and set the enumeration index
4813 // in the result.
4814 int enumeration_index = NextEnumerationIndex();
4815 if (!descriptor->GetDetails().IsTransition()) {
4816 if (keep_enumeration_index) {
4817 descriptor->SetEnumerationIndex(
4818 PropertyDetails(GetDetails(index)).index());
4819 } else {
4820 descriptor->SetEnumerationIndex(enumeration_index);
4821 ++enumeration_index;
4822 }
4823 }
4824 new_descriptors->SetNextEnumerationIndex(enumeration_index);
4825
4826 // Copy the descriptors, filtering out transitions and null descriptors,
4827 // and inserting or replacing a descriptor.
4828 uint32_t descriptor_hash = descriptor->GetKey()->Hash();
4829 int from_index = 0;
4830 int to_index = 0;
4831
4832 for (; from_index < number_of_descriptors(); from_index++) {
4833 String* key = GetKey(from_index);
4834 if (key->Hash() > descriptor_hash || key == descriptor->GetKey()) {
4835 break;
4836 }
4837 if (IsNullDescriptor(from_index)) continue;
4838 if (remove_transitions && IsTransition(from_index)) continue;
4839 new_descriptors->CopyFrom(to_index++, this, from_index);
4840 }
4841
4842 new_descriptors->Set(to_index++, descriptor);
4843 if (replacing) from_index++;
4844
4845 for (; from_index < number_of_descriptors(); from_index++) {
4846 if (IsNullDescriptor(from_index)) continue;
4847 if (remove_transitions && IsTransition(from_index)) continue;
4848 new_descriptors->CopyFrom(to_index++, this, from_index);
4849 }
4850
4851 ASSERT(to_index == new_descriptors->number_of_descriptors());
4852 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates());
4853
4854 return new_descriptors;
4855}
4856
4857
John Reck59135872010-11-02 12:39:01 -07004858MaybeObject* DescriptorArray::RemoveTransitions() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004859 // Remove all transitions and null descriptors. Return a copy of the array
4860 // with all transitions removed, or a Failure object if the new array could
4861 // not be allocated.
4862
4863 // Compute the size of the map transition entries to be removed.
4864 int num_removed = 0;
4865 for (int i = 0; i < number_of_descriptors(); i++) {
4866 if (!IsProperty(i)) num_removed++;
4867 }
4868
4869 // Allocate the new descriptor array.
John Reck59135872010-11-02 12:39:01 -07004870 Object* result;
4871 { MaybeObject* maybe_result = Allocate(number_of_descriptors() - num_removed);
4872 if (!maybe_result->ToObject(&result)) return maybe_result;
4873 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004874 DescriptorArray* new_descriptors = DescriptorArray::cast(result);
4875
4876 // Copy the content.
4877 int next_descriptor = 0;
4878 for (int i = 0; i < number_of_descriptors(); i++) {
4879 if (IsProperty(i)) new_descriptors->CopyFrom(next_descriptor++, this, i);
4880 }
4881 ASSERT(next_descriptor == new_descriptors->number_of_descriptors());
4882
4883 return new_descriptors;
4884}
4885
4886
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004887void DescriptorArray::SortUnchecked() {
Steve Blocka7e24c12009-10-30 11:49:00 +00004888 // In-place heap sort.
4889 int len = number_of_descriptors();
4890
4891 // Bottom-up max-heap construction.
Steve Block6ded16b2010-05-10 14:33:55 +01004892 // Index of the last node with children
4893 const int max_parent_index = (len / 2) - 1;
4894 for (int i = max_parent_index; i >= 0; --i) {
4895 int parent_index = i;
4896 const uint32_t parent_hash = GetKey(i)->Hash();
4897 while (parent_index <= max_parent_index) {
4898 int child_index = 2 * parent_index + 1;
Steve Blocka7e24c12009-10-30 11:49:00 +00004899 uint32_t child_hash = GetKey(child_index)->Hash();
Steve Block6ded16b2010-05-10 14:33:55 +01004900 if (child_index + 1 < len) {
4901 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4902 if (right_child_hash > child_hash) {
4903 child_index++;
4904 child_hash = right_child_hash;
4905 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004906 }
Steve Block6ded16b2010-05-10 14:33:55 +01004907 if (child_hash <= parent_hash) break;
4908 Swap(parent_index, child_index);
4909 // Now element at child_index could be < its children.
4910 parent_index = child_index; // parent_hash remains correct.
Steve Blocka7e24c12009-10-30 11:49:00 +00004911 }
4912 }
4913
4914 // Extract elements and create sorted array.
4915 for (int i = len - 1; i > 0; --i) {
4916 // Put max element at the back of the array.
4917 Swap(0, i);
4918 // Sift down the new top element.
4919 int parent_index = 0;
Steve Block6ded16b2010-05-10 14:33:55 +01004920 const uint32_t parent_hash = GetKey(parent_index)->Hash();
4921 const int max_parent_index = (i / 2) - 1;
4922 while (parent_index <= max_parent_index) {
4923 int child_index = parent_index * 2 + 1;
4924 uint32_t child_hash = GetKey(child_index)->Hash();
4925 if (child_index + 1 < i) {
4926 uint32_t right_child_hash = GetKey(child_index + 1)->Hash();
4927 if (right_child_hash > child_hash) {
4928 child_index++;
4929 child_hash = right_child_hash;
4930 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004931 }
Steve Block6ded16b2010-05-10 14:33:55 +01004932 if (child_hash <= parent_hash) break;
4933 Swap(parent_index, child_index);
4934 parent_index = child_index;
Steve Blocka7e24c12009-10-30 11:49:00 +00004935 }
4936 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004937}
Steve Blocka7e24c12009-10-30 11:49:00 +00004938
Kristian Monsen0d5e1162010-09-30 15:31:59 +01004939
4940void DescriptorArray::Sort() {
4941 SortUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00004942 SLOW_ASSERT(IsSortedNoDuplicates());
4943}
4944
4945
4946int DescriptorArray::BinarySearch(String* name, int low, int high) {
4947 uint32_t hash = name->Hash();
4948
4949 while (low <= high) {
4950 int mid = (low + high) / 2;
4951 String* mid_name = GetKey(mid);
4952 uint32_t mid_hash = mid_name->Hash();
4953
4954 if (mid_hash > hash) {
4955 high = mid - 1;
4956 continue;
4957 }
4958 if (mid_hash < hash) {
4959 low = mid + 1;
4960 continue;
4961 }
4962 // Found an element with the same hash-code.
4963 ASSERT(hash == mid_hash);
4964 // There might be more, so we find the first one and
4965 // check them all to see if we have a match.
4966 if (name == mid_name && !is_null_descriptor(mid)) return mid;
4967 while ((mid > low) && (GetKey(mid - 1)->Hash() == hash)) mid--;
4968 for (; (mid <= high) && (GetKey(mid)->Hash() == hash); mid++) {
4969 if (GetKey(mid)->Equals(name) && !is_null_descriptor(mid)) return mid;
4970 }
4971 break;
4972 }
4973 return kNotFound;
4974}
4975
4976
4977int DescriptorArray::LinearSearch(String* name, int len) {
4978 uint32_t hash = name->Hash();
4979 for (int number = 0; number < len; number++) {
4980 String* entry = GetKey(number);
4981 if ((entry->Hash() == hash) &&
4982 name->Equals(entry) &&
4983 !is_null_descriptor(number)) {
4984 return number;
4985 }
4986 }
4987 return kNotFound;
4988}
4989
4990
Ben Murdochb0fe1622011-05-05 13:52:32 +01004991MaybeObject* DeoptimizationInputData::Allocate(int deopt_entry_count,
4992 PretenureFlag pretenure) {
4993 ASSERT(deopt_entry_count > 0);
Steve Block44f0eee2011-05-26 01:26:41 +01004994 return HEAP->AllocateFixedArray(LengthFor(deopt_entry_count),
Ben Murdochb0fe1622011-05-05 13:52:32 +01004995 pretenure);
4996}
4997
4998
4999MaybeObject* DeoptimizationOutputData::Allocate(int number_of_deopt_points,
5000 PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01005001 if (number_of_deopt_points == 0) return HEAP->empty_fixed_array();
5002 return HEAP->AllocateFixedArray(LengthOfFixedArray(number_of_deopt_points),
Ben Murdochb0fe1622011-05-05 13:52:32 +01005003 pretenure);
5004}
5005
5006
Steve Blocka7e24c12009-10-30 11:49:00 +00005007#ifdef DEBUG
5008bool DescriptorArray::IsEqualTo(DescriptorArray* other) {
5009 if (IsEmpty()) return other->IsEmpty();
5010 if (other->IsEmpty()) return false;
5011 if (length() != other->length()) return false;
5012 for (int i = 0; i < length(); ++i) {
5013 if (get(i) != other->get(i) && i != kContentArrayIndex) return false;
5014 }
5015 return GetContentArray()->IsEqualTo(other->GetContentArray());
5016}
5017#endif
5018
5019
Steve Blocka7e24c12009-10-30 11:49:00 +00005020bool String::LooksValid() {
Steve Block44f0eee2011-05-26 01:26:41 +01005021 if (!Isolate::Current()->heap()->Contains(this)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00005022 return true;
5023}
5024
5025
5026int String::Utf8Length() {
5027 if (IsAsciiRepresentation()) return length();
5028 // Attempt to flatten before accessing the string. It probably
5029 // doesn't make Utf8Length faster, but it is very likely that
5030 // the string will be accessed later (for example by WriteUtf8)
5031 // so it's still a good idea.
Steve Block44f0eee2011-05-26 01:26:41 +01005032 Heap* heap = GetHeap();
Steve Block6ded16b2010-05-10 14:33:55 +01005033 TryFlatten();
Steve Block44f0eee2011-05-26 01:26:41 +01005034 Access<StringInputBuffer> buffer(
5035 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005036 buffer->Reset(0, this);
5037 int result = 0;
5038 while (buffer->has_more())
5039 result += unibrow::Utf8::Length(buffer->GetNext());
5040 return result;
5041}
5042
5043
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005044String::FlatContent String::GetFlatContent() {
Steve Blocka7e24c12009-10-30 11:49:00 +00005045 int length = this->length();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005046 StringShape shape(this);
Steve Blocka7e24c12009-10-30 11:49:00 +00005047 String* string = this;
Steve Blocka7e24c12009-10-30 11:49:00 +00005048 int offset = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005049 if (shape.representation_tag() == kConsStringTag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005050 ConsString* cons = ConsString::cast(string);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005051 if (cons->second()->length() != 0) {
5052 return FlatContent();
5053 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005054 string = cons->first();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005055 shape = StringShape(string);
Steve Blocka7e24c12009-10-30 11:49:00 +00005056 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005057 if (shape.representation_tag() == kSlicedStringTag) {
5058 SlicedString* slice = SlicedString::cast(string);
5059 offset = slice->offset();
5060 string = slice->parent();
5061 shape = StringShape(string);
5062 ASSERT(shape.representation_tag() != kConsStringTag &&
5063 shape.representation_tag() != kSlicedStringTag);
Steve Blocka7e24c12009-10-30 11:49:00 +00005064 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005065 if (shape.encoding_tag() == kAsciiStringTag) {
5066 const char* start;
5067 if (shape.representation_tag() == kSeqStringTag) {
5068 start = SeqAsciiString::cast(string)->GetChars();
5069 } else {
5070 start = ExternalAsciiString::cast(string)->resource()->data();
5071 }
5072 return FlatContent(Vector<const char>(start + offset, length));
5073 } else {
5074 ASSERT(shape.encoding_tag() == kTwoByteStringTag);
5075 const uc16* start;
5076 if (shape.representation_tag() == kSeqStringTag) {
5077 start = SeqTwoByteString::cast(string)->GetChars();
5078 } else {
5079 start = ExternalTwoByteString::cast(string)->resource()->data();
5080 }
5081 return FlatContent(Vector<const uc16>(start + offset, length));
5082 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005083}
5084
5085
Ben Murdoch589d6972011-11-30 16:04:58 +00005086SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5087 RobustnessFlag robust_flag,
5088 int offset,
5089 int length,
5090 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005091 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00005092 return SmartArrayPointer<char>(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005093 }
Steve Block44f0eee2011-05-26 01:26:41 +01005094 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005095
5096 // Negative length means the to the end of the string.
5097 if (length < 0) length = kMaxInt - offset;
5098
5099 // Compute the size of the UTF-8 string. Start at the specified offset.
Steve Block44f0eee2011-05-26 01:26:41 +01005100 Access<StringInputBuffer> buffer(
5101 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005102 buffer->Reset(offset, this);
5103 int character_position = offset;
5104 int utf8_bytes = 0;
5105 while (buffer->has_more()) {
5106 uint16_t character = buffer->GetNext();
5107 if (character_position < offset + length) {
5108 utf8_bytes += unibrow::Utf8::Length(character);
5109 }
5110 character_position++;
5111 }
5112
5113 if (length_return) {
5114 *length_return = utf8_bytes;
5115 }
5116
5117 char* result = NewArray<char>(utf8_bytes + 1);
5118
5119 // Convert the UTF-16 string to a UTF-8 buffer. Start at the specified offset.
5120 buffer->Rewind();
5121 buffer->Seek(offset);
5122 character_position = offset;
5123 int utf8_byte_position = 0;
5124 while (buffer->has_more()) {
5125 uint16_t character = buffer->GetNext();
5126 if (character_position < offset + length) {
5127 if (allow_nulls == DISALLOW_NULLS && character == 0) {
5128 character = ' ';
5129 }
5130 utf8_byte_position +=
5131 unibrow::Utf8::Encode(result + utf8_byte_position, character);
5132 }
5133 character_position++;
5134 }
5135 result[utf8_byte_position] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00005136 return SmartArrayPointer<char>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005137}
5138
5139
Ben Murdoch589d6972011-11-30 16:04:58 +00005140SmartArrayPointer<char> String::ToCString(AllowNullsFlag allow_nulls,
5141 RobustnessFlag robust_flag,
5142 int* length_return) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005143 return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
5144}
5145
5146
5147const uc16* String::GetTwoByteData() {
5148 return GetTwoByteData(0);
5149}
5150
5151
5152const uc16* String::GetTwoByteData(unsigned start) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005153 ASSERT(!IsAsciiRepresentationUnderneath());
Steve Blocka7e24c12009-10-30 11:49:00 +00005154 switch (StringShape(this).representation_tag()) {
5155 case kSeqStringTag:
5156 return SeqTwoByteString::cast(this)->SeqTwoByteStringGetData(start);
5157 case kExternalStringTag:
5158 return ExternalTwoByteString::cast(this)->
5159 ExternalTwoByteStringGetData(start);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005160 case kSlicedStringTag: {
5161 SlicedString* slice = SlicedString::cast(this);
5162 return slice->parent()->GetTwoByteData(start + slice->offset());
5163 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005164 case kConsStringTag:
5165 UNREACHABLE();
5166 return NULL;
5167 }
5168 UNREACHABLE();
5169 return NULL;
5170}
5171
5172
Ben Murdoch589d6972011-11-30 16:04:58 +00005173SmartArrayPointer<uc16> String::ToWideCString(RobustnessFlag robust_flag) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005174 if (robust_flag == ROBUST_STRING_TRAVERSAL && !LooksValid()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00005175 return SmartArrayPointer<uc16>();
Steve Blocka7e24c12009-10-30 11:49:00 +00005176 }
Steve Block44f0eee2011-05-26 01:26:41 +01005177 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00005178
Steve Block44f0eee2011-05-26 01:26:41 +01005179 Access<StringInputBuffer> buffer(
5180 heap->isolate()->objects_string_input_buffer());
Steve Blocka7e24c12009-10-30 11:49:00 +00005181 buffer->Reset(this);
5182
5183 uc16* result = NewArray<uc16>(length() + 1);
5184
5185 int i = 0;
5186 while (buffer->has_more()) {
5187 uint16_t character = buffer->GetNext();
5188 result[i++] = character;
5189 }
5190 result[i] = 0;
Ben Murdoch589d6972011-11-30 16:04:58 +00005191 return SmartArrayPointer<uc16>(result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005192}
5193
5194
5195const uc16* SeqTwoByteString::SeqTwoByteStringGetData(unsigned start) {
5196 return reinterpret_cast<uc16*>(
5197 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize) + start;
5198}
5199
5200
5201void SeqTwoByteString::SeqTwoByteStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5202 unsigned* offset_ptr,
5203 unsigned max_chars) {
5204 unsigned chars_read = 0;
5205 unsigned offset = *offset_ptr;
5206 while (chars_read < max_chars) {
5207 uint16_t c = *reinterpret_cast<uint16_t*>(
5208 reinterpret_cast<char*>(this) -
5209 kHeapObjectTag + kHeaderSize + offset * kShortSize);
5210 if (c <= kMaxAsciiCharCode) {
5211 // Fast case for ASCII characters. Cursor is an input output argument.
5212 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5213 rbb->util_buffer,
5214 rbb->capacity,
5215 rbb->cursor)) {
5216 break;
5217 }
5218 } else {
5219 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5220 rbb->util_buffer,
5221 rbb->capacity,
5222 rbb->cursor)) {
5223 break;
5224 }
5225 }
5226 offset++;
5227 chars_read++;
5228 }
5229 *offset_ptr = offset;
5230 rbb->remaining += chars_read;
5231}
5232
5233
5234const unibrow::byte* SeqAsciiString::SeqAsciiStringReadBlock(
5235 unsigned* remaining,
5236 unsigned* offset_ptr,
5237 unsigned max_chars) {
5238 const unibrow::byte* b = reinterpret_cast<unibrow::byte*>(this) -
5239 kHeapObjectTag + kHeaderSize + *offset_ptr * kCharSize;
5240 *remaining = max_chars;
5241 *offset_ptr += max_chars;
5242 return b;
5243}
5244
5245
5246// This will iterate unless the block of string data spans two 'halves' of
5247// a ConsString, in which case it will recurse. Since the block of string
5248// data to be read has a maximum size this limits the maximum recursion
5249// depth to something sane. Since C++ does not have tail call recursion
5250// elimination, the iteration must be explicit. Since this is not an
5251// -IntoBuffer method it can delegate to one of the efficient
5252// *AsciiStringReadBlock routines.
5253const unibrow::byte* ConsString::ConsStringReadBlock(ReadBlockBuffer* rbb,
5254 unsigned* offset_ptr,
5255 unsigned max_chars) {
5256 ConsString* current = this;
5257 unsigned offset = *offset_ptr;
5258 int offset_correction = 0;
5259
5260 while (true) {
5261 String* left = current->first();
5262 unsigned left_length = (unsigned)left->length();
5263 if (left_length > offset &&
5264 (max_chars <= left_length - offset ||
5265 (rbb->capacity <= left_length - offset &&
5266 (max_chars = left_length - offset, true)))) { // comma operator!
5267 // Left hand side only - iterate unless we have reached the bottom of
5268 // the cons tree. The assignment on the left of the comma operator is
5269 // in order to make use of the fact that the -IntoBuffer routines can
5270 // produce at most 'capacity' characters. This enables us to postpone
5271 // the point where we switch to the -IntoBuffer routines (below) in order
5272 // to maximize the chances of delegating a big chunk of work to the
5273 // efficient *AsciiStringReadBlock routines.
5274 if (StringShape(left).IsCons()) {
5275 current = ConsString::cast(left);
5276 continue;
5277 } else {
5278 const unibrow::byte* answer =
5279 String::ReadBlock(left, rbb, &offset, max_chars);
5280 *offset_ptr = offset + offset_correction;
5281 return answer;
5282 }
5283 } else if (left_length <= offset) {
5284 // Right hand side only - iterate unless we have reached the bottom of
5285 // the cons tree.
5286 String* right = current->second();
5287 offset -= left_length;
5288 offset_correction += left_length;
5289 if (StringShape(right).IsCons()) {
5290 current = ConsString::cast(right);
5291 continue;
5292 } else {
5293 const unibrow::byte* answer =
5294 String::ReadBlock(right, rbb, &offset, max_chars);
5295 *offset_ptr = offset + offset_correction;
5296 return answer;
5297 }
5298 } else {
5299 // The block to be read spans two sides of the ConsString, so we call the
5300 // -IntoBuffer version, which will recurse. The -IntoBuffer methods
5301 // are able to assemble data from several part strings because they use
5302 // the util_buffer to store their data and never return direct pointers
5303 // to their storage. We don't try to read more than the buffer capacity
5304 // here or we can get too much recursion.
5305 ASSERT(rbb->remaining == 0);
5306 ASSERT(rbb->cursor == 0);
5307 current->ConsStringReadBlockIntoBuffer(
5308 rbb,
5309 &offset,
5310 max_chars > rbb->capacity ? rbb->capacity : max_chars);
5311 *offset_ptr = offset + offset_correction;
5312 return rbb->util_buffer;
5313 }
5314 }
5315}
5316
5317
Steve Blocka7e24c12009-10-30 11:49:00 +00005318uint16_t ExternalAsciiString::ExternalAsciiStringGet(int index) {
5319 ASSERT(index >= 0 && index < length());
5320 return resource()->data()[index];
5321}
5322
5323
5324const unibrow::byte* ExternalAsciiString::ExternalAsciiStringReadBlock(
5325 unsigned* remaining,
5326 unsigned* offset_ptr,
5327 unsigned max_chars) {
5328 // Cast const char* to unibrow::byte* (signedness difference).
5329 const unibrow::byte* b =
5330 reinterpret_cast<const unibrow::byte*>(resource()->data()) + *offset_ptr;
5331 *remaining = max_chars;
5332 *offset_ptr += max_chars;
5333 return b;
5334}
5335
5336
5337const uc16* ExternalTwoByteString::ExternalTwoByteStringGetData(
5338 unsigned start) {
5339 return resource()->data() + start;
5340}
5341
5342
5343uint16_t ExternalTwoByteString::ExternalTwoByteStringGet(int index) {
5344 ASSERT(index >= 0 && index < length());
5345 return resource()->data()[index];
5346}
5347
5348
5349void ExternalTwoByteString::ExternalTwoByteStringReadBlockIntoBuffer(
5350 ReadBlockBuffer* rbb,
5351 unsigned* offset_ptr,
5352 unsigned max_chars) {
5353 unsigned chars_read = 0;
5354 unsigned offset = *offset_ptr;
5355 const uint16_t* data = resource()->data();
5356 while (chars_read < max_chars) {
5357 uint16_t c = data[offset];
5358 if (c <= kMaxAsciiCharCode) {
5359 // Fast case for ASCII characters. Cursor is an input output argument.
5360 if (!unibrow::CharacterStream::EncodeAsciiCharacter(c,
5361 rbb->util_buffer,
5362 rbb->capacity,
5363 rbb->cursor))
5364 break;
5365 } else {
5366 if (!unibrow::CharacterStream::EncodeNonAsciiCharacter(c,
5367 rbb->util_buffer,
5368 rbb->capacity,
5369 rbb->cursor))
5370 break;
5371 }
5372 offset++;
5373 chars_read++;
5374 }
5375 *offset_ptr = offset;
5376 rbb->remaining += chars_read;
5377}
5378
5379
5380void SeqAsciiString::SeqAsciiStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5381 unsigned* offset_ptr,
5382 unsigned max_chars) {
5383 unsigned capacity = rbb->capacity - rbb->cursor;
5384 if (max_chars > capacity) max_chars = capacity;
5385 memcpy(rbb->util_buffer + rbb->cursor,
5386 reinterpret_cast<char*>(this) - kHeapObjectTag + kHeaderSize +
5387 *offset_ptr * kCharSize,
5388 max_chars);
5389 rbb->remaining += max_chars;
5390 *offset_ptr += max_chars;
5391 rbb->cursor += max_chars;
5392}
5393
5394
5395void ExternalAsciiString::ExternalAsciiStringReadBlockIntoBuffer(
5396 ReadBlockBuffer* rbb,
5397 unsigned* offset_ptr,
5398 unsigned max_chars) {
5399 unsigned capacity = rbb->capacity - rbb->cursor;
5400 if (max_chars > capacity) max_chars = capacity;
5401 memcpy(rbb->util_buffer + rbb->cursor,
5402 resource()->data() + *offset_ptr,
5403 max_chars);
5404 rbb->remaining += max_chars;
5405 *offset_ptr += max_chars;
5406 rbb->cursor += max_chars;
5407}
5408
5409
5410// This method determines the type of string involved and then copies
5411// a whole chunk of characters into a buffer, or returns a pointer to a buffer
5412// where they can be found. The pointer is not necessarily valid across a GC
5413// (see AsciiStringReadBlock).
5414const unibrow::byte* String::ReadBlock(String* input,
5415 ReadBlockBuffer* rbb,
5416 unsigned* offset_ptr,
5417 unsigned max_chars) {
5418 ASSERT(*offset_ptr <= static_cast<unsigned>(input->length()));
5419 if (max_chars == 0) {
5420 rbb->remaining = 0;
5421 return NULL;
5422 }
5423 switch (StringShape(input).representation_tag()) {
5424 case kSeqStringTag:
5425 if (input->IsAsciiRepresentation()) {
5426 SeqAsciiString* str = SeqAsciiString::cast(input);
5427 return str->SeqAsciiStringReadBlock(&rbb->remaining,
5428 offset_ptr,
5429 max_chars);
5430 } else {
5431 SeqTwoByteString* str = SeqTwoByteString::cast(input);
5432 str->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5433 offset_ptr,
5434 max_chars);
5435 return rbb->util_buffer;
5436 }
5437 case kConsStringTag:
5438 return ConsString::cast(input)->ConsStringReadBlock(rbb,
5439 offset_ptr,
5440 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005441 case kExternalStringTag:
5442 if (input->IsAsciiRepresentation()) {
5443 return ExternalAsciiString::cast(input)->ExternalAsciiStringReadBlock(
5444 &rbb->remaining,
5445 offset_ptr,
5446 max_chars);
5447 } else {
5448 ExternalTwoByteString::cast(input)->
5449 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5450 offset_ptr,
5451 max_chars);
5452 return rbb->util_buffer;
5453 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005454 case kSlicedStringTag:
5455 return SlicedString::cast(input)->SlicedStringReadBlock(rbb,
5456 offset_ptr,
5457 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005458 default:
5459 break;
5460 }
5461
5462 UNREACHABLE();
5463 return 0;
5464}
5465
5466
Steve Blocka7e24c12009-10-30 11:49:00 +00005467void Relocatable::PostGarbageCollectionProcessing() {
Steve Block44f0eee2011-05-26 01:26:41 +01005468 Isolate* isolate = Isolate::Current();
5469 Relocatable* current = isolate->relocatable_top();
Steve Blocka7e24c12009-10-30 11:49:00 +00005470 while (current != NULL) {
5471 current->PostGarbageCollection();
5472 current = current->prev_;
5473 }
5474}
5475
5476
5477// Reserve space for statics needing saving and restoring.
5478int Relocatable::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +01005479 return sizeof(Isolate::Current()->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005480}
5481
5482
5483// Archive statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005484char* Relocatable::ArchiveState(Isolate* isolate, char* to) {
Steve Block44f0eee2011-05-26 01:26:41 +01005485 *reinterpret_cast<Relocatable**>(to) = isolate->relocatable_top();
5486 isolate->set_relocatable_top(NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +00005487 return to + ArchiveSpacePerThread();
5488}
5489
5490
5491// Restore statics that are thread local.
Ben Murdoch257744e2011-11-30 15:57:28 +00005492char* Relocatable::RestoreState(Isolate* isolate, char* from) {
Steve Block44f0eee2011-05-26 01:26:41 +01005493 isolate->set_relocatable_top(*reinterpret_cast<Relocatable**>(from));
Steve Blocka7e24c12009-10-30 11:49:00 +00005494 return from + ArchiveSpacePerThread();
5495}
5496
5497
5498char* Relocatable::Iterate(ObjectVisitor* v, char* thread_storage) {
5499 Relocatable* top = *reinterpret_cast<Relocatable**>(thread_storage);
5500 Iterate(v, top);
5501 return thread_storage + ArchiveSpacePerThread();
5502}
5503
5504
5505void Relocatable::Iterate(ObjectVisitor* v) {
Steve Block44f0eee2011-05-26 01:26:41 +01005506 Isolate* isolate = Isolate::Current();
5507 Iterate(v, isolate->relocatable_top());
Steve Blocka7e24c12009-10-30 11:49:00 +00005508}
5509
5510
5511void Relocatable::Iterate(ObjectVisitor* v, Relocatable* top) {
5512 Relocatable* current = top;
5513 while (current != NULL) {
5514 current->IterateInstance(v);
5515 current = current->prev_;
5516 }
5517}
5518
5519
Steve Block44f0eee2011-05-26 01:26:41 +01005520FlatStringReader::FlatStringReader(Isolate* isolate, Handle<String> str)
5521 : Relocatable(isolate),
5522 str_(str.location()),
Steve Blocka7e24c12009-10-30 11:49:00 +00005523 length_(str->length()) {
5524 PostGarbageCollection();
5525}
5526
5527
Steve Block44f0eee2011-05-26 01:26:41 +01005528FlatStringReader::FlatStringReader(Isolate* isolate, Vector<const char> input)
5529 : Relocatable(isolate),
5530 str_(0),
Steve Blocka7e24c12009-10-30 11:49:00 +00005531 is_ascii_(true),
5532 length_(input.length()),
5533 start_(input.start()) { }
5534
5535
5536void FlatStringReader::PostGarbageCollection() {
5537 if (str_ == NULL) return;
5538 Handle<String> str(str_);
5539 ASSERT(str->IsFlat());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005540 String::FlatContent content = str->GetFlatContent();
5541 ASSERT(content.IsFlat());
5542 is_ascii_ = content.IsAscii();
Steve Blocka7e24c12009-10-30 11:49:00 +00005543 if (is_ascii_) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005544 start_ = content.ToAsciiVector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00005545 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005546 start_ = content.ToUC16Vector().start();
Steve Blocka7e24c12009-10-30 11:49:00 +00005547 }
5548}
5549
5550
5551void StringInputBuffer::Seek(unsigned pos) {
5552 Reset(pos, input_);
5553}
5554
5555
5556void SafeStringInputBuffer::Seek(unsigned pos) {
5557 Reset(pos, input_);
5558}
5559
5560
5561// This method determines the type of string involved and then copies
5562// a whole chunk of characters into a buffer. It can be used with strings
5563// that have been glued together to form a ConsString and which must cooperate
5564// to fill up a buffer.
5565void String::ReadBlockIntoBuffer(String* input,
5566 ReadBlockBuffer* rbb,
5567 unsigned* offset_ptr,
5568 unsigned max_chars) {
5569 ASSERT(*offset_ptr <= (unsigned)input->length());
5570 if (max_chars == 0) return;
5571
5572 switch (StringShape(input).representation_tag()) {
5573 case kSeqStringTag:
5574 if (input->IsAsciiRepresentation()) {
5575 SeqAsciiString::cast(input)->SeqAsciiStringReadBlockIntoBuffer(rbb,
5576 offset_ptr,
5577 max_chars);
5578 return;
5579 } else {
5580 SeqTwoByteString::cast(input)->SeqTwoByteStringReadBlockIntoBuffer(rbb,
5581 offset_ptr,
5582 max_chars);
5583 return;
5584 }
5585 case kConsStringTag:
5586 ConsString::cast(input)->ConsStringReadBlockIntoBuffer(rbb,
5587 offset_ptr,
5588 max_chars);
5589 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005590 case kExternalStringTag:
5591 if (input->IsAsciiRepresentation()) {
Steve Blockd0582a62009-12-15 09:54:21 +00005592 ExternalAsciiString::cast(input)->
5593 ExternalAsciiStringReadBlockIntoBuffer(rbb, offset_ptr, max_chars);
5594 } else {
5595 ExternalTwoByteString::cast(input)->
5596 ExternalTwoByteStringReadBlockIntoBuffer(rbb,
5597 offset_ptr,
5598 max_chars);
Steve Blocka7e24c12009-10-30 11:49:00 +00005599 }
5600 return;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005601 case kSlicedStringTag:
5602 SlicedString::cast(input)->SlicedStringReadBlockIntoBuffer(rbb,
5603 offset_ptr,
5604 max_chars);
5605 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00005606 default:
5607 break;
5608 }
5609
5610 UNREACHABLE();
5611 return;
5612}
5613
5614
5615const unibrow::byte* String::ReadBlock(String* input,
5616 unibrow::byte* util_buffer,
5617 unsigned capacity,
5618 unsigned* remaining,
5619 unsigned* offset_ptr) {
5620 ASSERT(*offset_ptr <= (unsigned)input->length());
5621 unsigned chars = input->length() - *offset_ptr;
5622 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5623 const unibrow::byte* answer = ReadBlock(input, &rbb, offset_ptr, chars);
5624 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5625 *remaining = rbb.remaining;
5626 return answer;
5627}
5628
5629
5630const unibrow::byte* String::ReadBlock(String** raw_input,
5631 unibrow::byte* util_buffer,
5632 unsigned capacity,
5633 unsigned* remaining,
5634 unsigned* offset_ptr) {
5635 Handle<String> input(raw_input);
5636 ASSERT(*offset_ptr <= (unsigned)input->length());
5637 unsigned chars = input->length() - *offset_ptr;
5638 if (chars > capacity) chars = capacity;
5639 ReadBlockBuffer rbb(util_buffer, 0, capacity, 0);
5640 ReadBlockIntoBuffer(*input, &rbb, offset_ptr, chars);
5641 ASSERT(rbb.remaining <= static_cast<unsigned>(input->length()));
5642 *remaining = rbb.remaining;
5643 return rbb.util_buffer;
5644}
5645
5646
5647// This will iterate unless the block of string data spans two 'halves' of
5648// a ConsString, in which case it will recurse. Since the block of string
5649// data to be read has a maximum size this limits the maximum recursion
5650// depth to something sane. Since C++ does not have tail call recursion
5651// elimination, the iteration must be explicit.
5652void ConsString::ConsStringReadBlockIntoBuffer(ReadBlockBuffer* rbb,
5653 unsigned* offset_ptr,
5654 unsigned max_chars) {
5655 ConsString* current = this;
5656 unsigned offset = *offset_ptr;
5657 int offset_correction = 0;
5658
5659 while (true) {
5660 String* left = current->first();
5661 unsigned left_length = (unsigned)left->length();
5662 if (left_length > offset &&
5663 max_chars <= left_length - offset) {
5664 // Left hand side only - iterate unless we have reached the bottom of
5665 // the cons tree.
5666 if (StringShape(left).IsCons()) {
5667 current = ConsString::cast(left);
5668 continue;
5669 } else {
5670 String::ReadBlockIntoBuffer(left, rbb, &offset, max_chars);
5671 *offset_ptr = offset + offset_correction;
5672 return;
5673 }
5674 } else if (left_length <= offset) {
5675 // Right hand side only - iterate unless we have reached the bottom of
5676 // the cons tree.
5677 offset -= left_length;
5678 offset_correction += left_length;
5679 String* right = current->second();
5680 if (StringShape(right).IsCons()) {
5681 current = ConsString::cast(right);
5682 continue;
5683 } else {
5684 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5685 *offset_ptr = offset + offset_correction;
5686 return;
5687 }
5688 } else {
5689 // The block to be read spans two sides of the ConsString, so we recurse.
5690 // First recurse on the left.
5691 max_chars -= left_length - offset;
5692 String::ReadBlockIntoBuffer(left, rbb, &offset, left_length - offset);
5693 // We may have reached the max or there may not have been enough space
5694 // in the buffer for the characters in the left hand side.
5695 if (offset == left_length) {
5696 // Recurse on the right.
5697 String* right = String::cast(current->second());
5698 offset -= left_length;
5699 offset_correction += left_length;
5700 String::ReadBlockIntoBuffer(right, rbb, &offset, max_chars);
5701 }
5702 *offset_ptr = offset + offset_correction;
5703 return;
5704 }
5705 }
5706}
5707
5708
Steve Blocka7e24c12009-10-30 11:49:00 +00005709uint16_t ConsString::ConsStringGet(int index) {
5710 ASSERT(index >= 0 && index < this->length());
5711
5712 // Check for a flattened cons string
5713 if (second()->length() == 0) {
5714 String* left = first();
5715 return left->Get(index);
5716 }
5717
5718 String* string = String::cast(this);
5719
5720 while (true) {
5721 if (StringShape(string).IsCons()) {
5722 ConsString* cons_string = ConsString::cast(string);
5723 String* left = cons_string->first();
5724 if (left->length() > index) {
5725 string = left;
5726 } else {
5727 index -= left->length();
5728 string = cons_string->second();
5729 }
5730 } else {
5731 return string->Get(index);
5732 }
5733 }
5734
5735 UNREACHABLE();
5736 return 0;
5737}
5738
5739
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005740uint16_t SlicedString::SlicedStringGet(int index) {
5741 return parent()->Get(offset() + index);
5742}
5743
5744
5745const unibrow::byte* SlicedString::SlicedStringReadBlock(
5746 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
5747 unsigned offset = this->offset();
5748 *offset_ptr += offset;
5749 const unibrow::byte* answer = String::ReadBlock(String::cast(parent()),
5750 buffer, offset_ptr, chars);
5751 *offset_ptr -= offset;
5752 return answer;
5753}
5754
5755
5756void SlicedString::SlicedStringReadBlockIntoBuffer(
5757 ReadBlockBuffer* buffer, unsigned* offset_ptr, unsigned chars) {
5758 unsigned offset = this->offset();
5759 *offset_ptr += offset;
5760 String::ReadBlockIntoBuffer(String::cast(parent()),
5761 buffer, offset_ptr, chars);
5762 *offset_ptr -= offset;
5763}
5764
Steve Blocka7e24c12009-10-30 11:49:00 +00005765template <typename sinkchar>
5766void String::WriteToFlat(String* src,
5767 sinkchar* sink,
5768 int f,
5769 int t) {
5770 String* source = src;
5771 int from = f;
5772 int to = t;
5773 while (true) {
5774 ASSERT(0 <= from && from <= to && to <= source->length());
5775 switch (StringShape(source).full_representation_tag()) {
5776 case kAsciiStringTag | kExternalStringTag: {
5777 CopyChars(sink,
5778 ExternalAsciiString::cast(source)->resource()->data() + from,
5779 to - from);
5780 return;
5781 }
5782 case kTwoByteStringTag | kExternalStringTag: {
5783 const uc16* data =
5784 ExternalTwoByteString::cast(source)->resource()->data();
5785 CopyChars(sink,
5786 data + from,
5787 to - from);
5788 return;
5789 }
5790 case kAsciiStringTag | kSeqStringTag: {
5791 CopyChars(sink,
5792 SeqAsciiString::cast(source)->GetChars() + from,
5793 to - from);
5794 return;
5795 }
5796 case kTwoByteStringTag | kSeqStringTag: {
5797 CopyChars(sink,
5798 SeqTwoByteString::cast(source)->GetChars() + from,
5799 to - from);
5800 return;
5801 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005802 case kAsciiStringTag | kConsStringTag:
5803 case kTwoByteStringTag | kConsStringTag: {
5804 ConsString* cons_string = ConsString::cast(source);
5805 String* first = cons_string->first();
5806 int boundary = first->length();
5807 if (to - boundary >= boundary - from) {
5808 // Right hand side is longer. Recurse over left.
5809 if (from < boundary) {
5810 WriteToFlat(first, sink, from, boundary);
5811 sink += boundary - from;
5812 from = 0;
5813 } else {
5814 from -= boundary;
5815 }
5816 to -= boundary;
5817 source = cons_string->second();
5818 } else {
5819 // Left hand side is longer. Recurse over right.
5820 if (to > boundary) {
5821 String* second = cons_string->second();
5822 WriteToFlat(second,
5823 sink + boundary - from,
5824 0,
5825 to - boundary);
5826 to = boundary;
5827 }
5828 source = first;
5829 }
5830 break;
5831 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005832 case kAsciiStringTag | kSlicedStringTag:
5833 case kTwoByteStringTag | kSlicedStringTag: {
5834 SlicedString* slice = SlicedString::cast(source);
5835 unsigned offset = slice->offset();
5836 WriteToFlat(slice->parent(), sink, from + offset, to + offset);
5837 return;
5838 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005839 }
5840 }
5841}
5842
5843
Steve Blocka7e24c12009-10-30 11:49:00 +00005844template <typename IteratorA, typename IteratorB>
5845static inline bool CompareStringContents(IteratorA* ia, IteratorB* ib) {
5846 // General slow case check. We know that the ia and ib iterators
5847 // have the same length.
5848 while (ia->has_more()) {
5849 uc32 ca = ia->GetNext();
5850 uc32 cb = ib->GetNext();
5851 if (ca != cb)
5852 return false;
5853 }
5854 return true;
5855}
5856
5857
5858// Compares the contents of two strings by reading and comparing
5859// int-sized blocks of characters.
5860template <typename Char>
5861static inline bool CompareRawStringContents(Vector<Char> a, Vector<Char> b) {
5862 int length = a.length();
5863 ASSERT_EQ(length, b.length());
5864 const Char* pa = a.start();
5865 const Char* pb = b.start();
5866 int i = 0;
5867#ifndef V8_HOST_CAN_READ_UNALIGNED
5868 // If this architecture isn't comfortable reading unaligned ints
5869 // then we have to check that the strings are aligned before
5870 // comparing them blockwise.
5871 const int kAlignmentMask = sizeof(uint32_t) - 1; // NOLINT
5872 uint32_t pa_addr = reinterpret_cast<uint32_t>(pa);
5873 uint32_t pb_addr = reinterpret_cast<uint32_t>(pb);
5874 if (((pa_addr & kAlignmentMask) | (pb_addr & kAlignmentMask)) == 0) {
5875#endif
5876 const int kStepSize = sizeof(int) / sizeof(Char); // NOLINT
5877 int endpoint = length - kStepSize;
5878 // Compare blocks until we reach near the end of the string.
5879 for (; i <= endpoint; i += kStepSize) {
5880 uint32_t wa = *reinterpret_cast<const uint32_t*>(pa + i);
5881 uint32_t wb = *reinterpret_cast<const uint32_t*>(pb + i);
5882 if (wa != wb) {
5883 return false;
5884 }
5885 }
5886#ifndef V8_HOST_CAN_READ_UNALIGNED
5887 }
5888#endif
5889 // Compare the remaining characters that didn't fit into a block.
5890 for (; i < length; i++) {
5891 if (a[i] != b[i]) {
5892 return false;
5893 }
5894 }
5895 return true;
5896}
5897
5898
Steve Blocka7e24c12009-10-30 11:49:00 +00005899template <typename IteratorA>
Steve Block44f0eee2011-05-26 01:26:41 +01005900static inline bool CompareStringContentsPartial(Isolate* isolate,
5901 IteratorA* ia,
5902 String* b) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005903 String::FlatContent content = b->GetFlatContent();
5904 if (content.IsFlat()) {
5905 if (content.IsAscii()) {
5906 VectorIterator<char> ib(content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005907 return CompareStringContents(ia, &ib);
5908 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005909 VectorIterator<uc16> ib(content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005910 return CompareStringContents(ia, &ib);
5911 }
5912 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005913 isolate->objects_string_compare_buffer_b()->Reset(0, b);
5914 return CompareStringContents(ia,
5915 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005916 }
5917}
5918
5919
Steve Blocka7e24c12009-10-30 11:49:00 +00005920bool String::SlowEquals(String* other) {
5921 // Fast check: negative check with lengths.
5922 int len = length();
5923 if (len != other->length()) return false;
5924 if (len == 0) return true;
5925
5926 // Fast check: if hash code is computed for both strings
5927 // a fast negative check can be performed.
5928 if (HasHashCode() && other->HasHashCode()) {
5929 if (Hash() != other->Hash()) return false;
5930 }
5931
Leon Clarkef7060e22010-06-03 12:02:55 +01005932 // We know the strings are both non-empty. Compare the first chars
5933 // before we try to flatten the strings.
5934 if (this->Get(0) != other->Get(0)) return false;
5935
5936 String* lhs = this->TryFlattenGetString();
5937 String* rhs = other->TryFlattenGetString();
5938
5939 if (StringShape(lhs).IsSequentialAscii() &&
5940 StringShape(rhs).IsSequentialAscii()) {
5941 const char* str1 = SeqAsciiString::cast(lhs)->GetChars();
5942 const char* str2 = SeqAsciiString::cast(rhs)->GetChars();
Steve Blocka7e24c12009-10-30 11:49:00 +00005943 return CompareRawStringContents(Vector<const char>(str1, len),
5944 Vector<const char>(str2, len));
5945 }
5946
Steve Block44f0eee2011-05-26 01:26:41 +01005947 Isolate* isolate = GetIsolate();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005948 String::FlatContent lhs_content = lhs->GetFlatContent();
5949 String::FlatContent rhs_content = rhs->GetFlatContent();
5950 if (lhs_content.IsFlat()) {
5951 if (lhs_content.IsAscii()) {
5952 Vector<const char> vec1 = lhs_content.ToAsciiVector();
5953 if (rhs_content.IsFlat()) {
5954 if (rhs_content.IsAscii()) {
5955 Vector<const char> vec2 = rhs_content.ToAsciiVector();
Steve Blocka7e24c12009-10-30 11:49:00 +00005956 return CompareRawStringContents(vec1, vec2);
5957 } else {
5958 VectorIterator<char> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005959 VectorIterator<uc16> ib(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005960 return CompareStringContents(&buf1, &ib);
5961 }
5962 } else {
5963 VectorIterator<char> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005964 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5965 return CompareStringContents(&buf1,
5966 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005967 }
5968 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005969 Vector<const uc16> vec1 = lhs_content.ToUC16Vector();
5970 if (rhs_content.IsFlat()) {
5971 if (rhs_content.IsAscii()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005972 VectorIterator<uc16> buf1(vec1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005973 VectorIterator<char> ib(rhs_content.ToAsciiVector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005974 return CompareStringContents(&buf1, &ib);
5975 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005976 Vector<const uc16> vec2(rhs_content.ToUC16Vector());
Steve Blocka7e24c12009-10-30 11:49:00 +00005977 return CompareRawStringContents(vec1, vec2);
5978 }
5979 } else {
5980 VectorIterator<uc16> buf1(vec1);
Steve Block44f0eee2011-05-26 01:26:41 +01005981 isolate->objects_string_compare_buffer_b()->Reset(0, rhs);
5982 return CompareStringContents(&buf1,
5983 isolate->objects_string_compare_buffer_b());
Steve Blocka7e24c12009-10-30 11:49:00 +00005984 }
5985 }
5986 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01005987 isolate->objects_string_compare_buffer_a()->Reset(0, lhs);
5988 return CompareStringContentsPartial(isolate,
5989 isolate->objects_string_compare_buffer_a(), rhs);
Steve Blocka7e24c12009-10-30 11:49:00 +00005990 }
5991}
5992
5993
5994bool String::MarkAsUndetectable() {
5995 if (StringShape(this).IsSymbol()) return false;
5996
5997 Map* map = this->map();
Ben Murdoch8b112d22011-06-08 16:22:53 +01005998 Heap* heap = map->heap();
Steve Block44f0eee2011-05-26 01:26:41 +01005999 if (map == heap->string_map()) {
6000 this->set_map(heap->undetectable_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006001 return true;
Steve Block44f0eee2011-05-26 01:26:41 +01006002 } else if (map == heap->ascii_string_map()) {
6003 this->set_map(heap->undetectable_ascii_string_map());
Steve Blocka7e24c12009-10-30 11:49:00 +00006004 return true;
6005 }
6006 // Rest cannot be marked as undetectable
6007 return false;
6008}
6009
6010
6011bool String::IsEqualTo(Vector<const char> str) {
Steve Block44f0eee2011-05-26 01:26:41 +01006012 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00006013 int slen = length();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006014 Access<UnicodeCache::Utf8Decoder>
6015 decoder(isolate->unicode_cache()->utf8_decoder());
Steve Blocka7e24c12009-10-30 11:49:00 +00006016 decoder->Reset(str.start(), str.length());
6017 int i;
6018 for (i = 0; i < slen && decoder->has_more(); i++) {
6019 uc32 r = decoder->GetNext();
6020 if (Get(i) != r) return false;
6021 }
6022 return i == slen && !decoder->has_more();
6023}
6024
6025
Steve Block9fac8402011-05-12 15:51:54 +01006026bool String::IsAsciiEqualTo(Vector<const char> str) {
6027 int slen = length();
6028 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006029 FlatContent content = GetFlatContent();
6030 if (content.IsAscii()) {
6031 return CompareChars(content.ToAsciiVector().start(),
6032 str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006033 }
6034 for (int i = 0; i < slen; i++) {
6035 if (Get(i) != static_cast<uint16_t>(str[i])) return false;
Steve Block9fac8402011-05-12 15:51:54 +01006036 }
6037 return true;
6038}
6039
6040
6041bool String::IsTwoByteEqualTo(Vector<const uc16> str) {
6042 int slen = length();
6043 if (str.length() != slen) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006044 FlatContent content = GetFlatContent();
6045 if (content.IsTwoByte()) {
6046 return CompareChars(content.ToUC16Vector().start(), str.start(), slen) == 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006047 }
Steve Block9fac8402011-05-12 15:51:54 +01006048 for (int i = 0; i < slen; i++) {
6049 if (Get(i) != str[i]) return false;
6050 }
6051 return true;
6052}
6053
6054
Steve Blocka7e24c12009-10-30 11:49:00 +00006055uint32_t String::ComputeAndSetHash() {
6056 // Should only be called if hash code has not yet been computed.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006057 ASSERT(!HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006058
Steve Block6ded16b2010-05-10 14:33:55 +01006059 const int len = length();
6060
Steve Blocka7e24c12009-10-30 11:49:00 +00006061 // Compute the hash code.
Steve Block6ded16b2010-05-10 14:33:55 +01006062 uint32_t field = 0;
6063 if (StringShape(this).IsSequentialAscii()) {
6064 field = HashSequentialString(SeqAsciiString::cast(this)->GetChars(), len);
6065 } else if (StringShape(this).IsSequentialTwoByte()) {
6066 field = HashSequentialString(SeqTwoByteString::cast(this)->GetChars(), len);
6067 } else {
6068 StringInputBuffer buffer(this);
6069 field = ComputeHashField(&buffer, len);
6070 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006071
6072 // Store the hash code in the object.
Steve Blockd0582a62009-12-15 09:54:21 +00006073 set_hash_field(field);
Steve Blocka7e24c12009-10-30 11:49:00 +00006074
6075 // Check the hash code is there.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006076 ASSERT(HasHashCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00006077 uint32_t result = field >> kHashShift;
6078 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
6079 return result;
6080}
6081
6082
6083bool String::ComputeArrayIndex(unibrow::CharacterStream* buffer,
6084 uint32_t* index,
6085 int length) {
6086 if (length == 0 || length > kMaxArrayIndexSize) return false;
6087 uc32 ch = buffer->GetNext();
6088
6089 // If the string begins with a '0' character, it must only consist
6090 // of it to be a legal array index.
6091 if (ch == '0') {
6092 *index = 0;
6093 return length == 1;
6094 }
6095
6096 // Convert string to uint32 array index; character by character.
6097 int d = ch - '0';
6098 if (d < 0 || d > 9) return false;
6099 uint32_t result = d;
6100 while (buffer->has_more()) {
6101 d = buffer->GetNext() - '0';
6102 if (d < 0 || d > 9) return false;
6103 // Check that the new result is below the 32 bit limit.
6104 if (result > 429496729U - ((d > 5) ? 1 : 0)) return false;
6105 result = (result * 10) + d;
6106 }
6107
6108 *index = result;
6109 return true;
6110}
6111
6112
6113bool String::SlowAsArrayIndex(uint32_t* index) {
6114 if (length() <= kMaxCachedArrayIndexLength) {
6115 Hash(); // force computation of hash code
Steve Blockd0582a62009-12-15 09:54:21 +00006116 uint32_t field = hash_field();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006117 if ((field & kIsNotArrayIndexMask) != 0) return false;
Steve Blockd0582a62009-12-15 09:54:21 +00006118 // Isolate the array index form the full hash field.
6119 *index = (kArrayIndexHashMask & field) >> kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00006120 return true;
6121 } else {
6122 StringInputBuffer buffer(this);
6123 return ComputeArrayIndex(&buffer, index, length());
6124 }
6125}
6126
6127
Iain Merrick9ac36c92010-09-13 15:29:50 +01006128uint32_t StringHasher::MakeArrayIndexHash(uint32_t value, int length) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006129 // For array indexes mix the length into the hash as an array index could
6130 // be zero.
6131 ASSERT(length > 0);
6132 ASSERT(length <= String::kMaxArrayIndexSize);
6133 ASSERT(TenToThe(String::kMaxCachedArrayIndexLength) <
6134 (1 << String::kArrayIndexValueBits));
Iain Merrick9ac36c92010-09-13 15:29:50 +01006135
6136 value <<= String::kHashShift;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006137 value |= length << String::kArrayIndexHashLengthShift;
Iain Merrick9ac36c92010-09-13 15:29:50 +01006138
6139 ASSERT((value & String::kIsNotArrayIndexMask) == 0);
6140 ASSERT((length > String::kMaxCachedArrayIndexLength) ||
6141 (value & String::kContainsCachedArrayIndexMask) == 0);
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006142 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00006143}
6144
6145
6146uint32_t StringHasher::GetHashField() {
6147 ASSERT(is_valid());
Steve Blockd0582a62009-12-15 09:54:21 +00006148 if (length_ <= String::kMaxHashCalcLength) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006149 if (is_array_index()) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01006150 return MakeArrayIndexHash(array_index(), length_);
Steve Blocka7e24c12009-10-30 11:49:00 +00006151 }
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006152 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006153 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01006154 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask;
Steve Blocka7e24c12009-10-30 11:49:00 +00006155 }
6156}
6157
6158
Steve Blockd0582a62009-12-15 09:54:21 +00006159uint32_t String::ComputeHashField(unibrow::CharacterStream* buffer,
6160 int length) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006161 StringHasher hasher(length);
6162
6163 // Very long strings have a trivial hash that doesn't inspect the
6164 // string contents.
6165 if (hasher.has_trivial_hash()) {
6166 return hasher.GetHashField();
6167 }
6168
6169 // Do the iterative array index computation as long as there is a
6170 // chance this is an array index.
6171 while (buffer->has_more() && hasher.is_array_index()) {
6172 hasher.AddCharacter(buffer->GetNext());
6173 }
6174
6175 // Process the remaining characters without updating the array
6176 // index.
6177 while (buffer->has_more()) {
6178 hasher.AddCharacterNoIndex(buffer->GetNext());
6179 }
6180
6181 return hasher.GetHashField();
6182}
6183
6184
John Reck59135872010-11-02 12:39:01 -07006185MaybeObject* String::SubString(int start, int end, PretenureFlag pretenure) {
Steve Block44f0eee2011-05-26 01:26:41 +01006186 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006187 if (start == 0 && end == length()) return this;
Steve Block44f0eee2011-05-26 01:26:41 +01006188 MaybeObject* result = heap->AllocateSubString(this, start, end, pretenure);
Steve Blockd0582a62009-12-15 09:54:21 +00006189 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00006190}
6191
6192
6193void String::PrintOn(FILE* file) {
6194 int length = this->length();
6195 for (int i = 0; i < length; i++) {
6196 fprintf(file, "%c", Get(i));
6197 }
6198}
6199
6200
6201void Map::CreateBackPointers() {
6202 DescriptorArray* descriptors = instance_descriptors();
6203 for (int i = 0; i < descriptors->number_of_descriptors(); i++) {
Iain Merrick75681382010-08-19 15:07:18 +01006204 if (descriptors->GetType(i) == MAP_TRANSITION ||
Ben Murdoch589d6972011-11-30 16:04:58 +00006205 descriptors->GetType(i) == ELEMENTS_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01006206 descriptors->GetType(i) == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006207 // Get target.
6208 Map* target = Map::cast(descriptors->GetValue(i));
6209#ifdef DEBUG
6210 // Verify target.
6211 Object* source_prototype = prototype();
6212 Object* target_prototype = target->prototype();
6213 ASSERT(source_prototype->IsJSObject() ||
6214 source_prototype->IsMap() ||
6215 source_prototype->IsNull());
6216 ASSERT(target_prototype->IsJSObject() ||
6217 target_prototype->IsNull());
6218 ASSERT(source_prototype->IsMap() ||
6219 source_prototype == target_prototype);
6220#endif
6221 // Point target back to source. set_prototype() will not let us set
6222 // the prototype to a map, as we do here.
6223 *RawField(target, kPrototypeOffset) = this;
6224 }
6225 }
6226}
6227
6228
Steve Block44f0eee2011-05-26 01:26:41 +01006229void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006230 // Live DescriptorArray objects will be marked, so we must use
6231 // low-level accessors to get and modify their data.
6232 DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
Ben Murdoch257744e2011-11-30 15:57:28 +00006233 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset));
6234 if (d->IsEmpty()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00006235 Smi* NullDescriptorDetails =
6236 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi();
6237 FixedArray* contents = reinterpret_cast<FixedArray*>(
6238 d->get(DescriptorArray::kContentArrayIndex));
6239 ASSERT(contents->length() >= 2);
6240 for (int i = 0; i < contents->length(); i += 2) {
6241 // If the pair (value, details) is a map transition,
6242 // check if the target is live. If not, null the descriptor.
6243 // Also drop the back pointer for that map transition, so that this
6244 // map is not reached again by following a back pointer from a
6245 // non-live object.
6246 PropertyDetails details(Smi::cast(contents->get(i + 1)));
Iain Merrick75681382010-08-19 15:07:18 +01006247 if (details.type() == MAP_TRANSITION ||
Ben Murdoch589d6972011-11-30 16:04:58 +00006248 details.type() == ELEMENTS_TRANSITION ||
Iain Merrick75681382010-08-19 15:07:18 +01006249 details.type() == CONSTANT_TRANSITION) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006250 Map* target = reinterpret_cast<Map*>(contents->get(i));
6251 ASSERT(target->IsHeapObject());
6252 if (!target->IsMarked()) {
6253 ASSERT(target->IsMap());
Iain Merrick75681382010-08-19 15:07:18 +01006254 contents->set_unchecked(i + 1, NullDescriptorDetails);
Steve Block44f0eee2011-05-26 01:26:41 +01006255 contents->set_null_unchecked(heap, i);
Steve Blocka7e24c12009-10-30 11:49:00 +00006256 ASSERT(target->prototype() == this ||
6257 target->prototype() == real_prototype);
6258 // Getter prototype() is read-only, set_prototype() has side effects.
6259 *RawField(target, Map::kPrototypeOffset) = real_prototype;
6260 }
6261 }
6262 }
6263}
6264
6265
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006266int Map::Hash() {
6267 // For performance reasons we only hash the 3 most variable fields of a map:
6268 // constructor, prototype and bit_field2.
6269
6270 // Shift away the tag.
6271 int hash = (static_cast<uint32_t>(
6272 reinterpret_cast<uintptr_t>(constructor())) >> 2);
6273
6274 // XOR-ing the prototype and constructor directly yields too many zero bits
6275 // when the two pointers are close (which is fairly common).
6276 // To avoid this we shift the prototype 4 bits relatively to the constructor.
6277 hash ^= (static_cast<uint32_t>(
6278 reinterpret_cast<uintptr_t>(prototype())) << 2);
6279
6280 return hash ^ (hash >> 16) ^ bit_field2();
6281}
6282
6283
6284bool Map::EquivalentToForNormalization(Map* other,
6285 PropertyNormalizationMode mode) {
6286 return
6287 constructor() == other->constructor() &&
6288 prototype() == other->prototype() &&
6289 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
6290 0 :
6291 other->inobject_properties()) &&
6292 instance_type() == other->instance_type() &&
6293 bit_field() == other->bit_field() &&
6294 bit_field2() == other->bit_field2() &&
6295 (bit_field3() & ~(1<<Map::kIsShared)) ==
6296 (other->bit_field3() & ~(1<<Map::kIsShared));
6297}
6298
6299
Steve Block791712a2010-08-27 10:21:07 +01006300void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
6301 // Iterate over all fields in the body but take care in dealing with
6302 // the code entry.
6303 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset);
6304 v->VisitCodeEntry(this->address() + kCodeEntryOffset);
6305 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size);
6306}
6307
6308
Ben Murdochb0fe1622011-05-05 13:52:32 +01006309void JSFunction::MarkForLazyRecompilation() {
6310 ASSERT(is_compiled() && !IsOptimized());
Ben Murdochb8e0da22011-05-16 14:20:40 +01006311 ASSERT(shared()->allows_lazy_compilation() ||
6312 code()->optimizable());
Steve Block44f0eee2011-05-26 01:26:41 +01006313 Builtins* builtins = GetIsolate()->builtins();
6314 ReplaceCode(builtins->builtin(Builtins::kLazyRecompile));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006315}
6316
6317
Ben Murdochb0fe1622011-05-05 13:52:32 +01006318bool JSFunction::IsInlineable() {
6319 if (IsBuiltin()) return false;
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006320 SharedFunctionInfo* shared_info = shared();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006321 // Check that the function has a script associated with it.
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006322 if (!shared_info->script()->IsScript()) return false;
6323 if (shared_info->optimization_disabled()) return false;
6324 Code* code = shared_info->code();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006325 if (code->kind() == Code::OPTIMIZED_FUNCTION) return true;
6326 // If we never ran this (unlikely) then lets try to optimize it.
6327 if (code->kind() != Code::FUNCTION) return true;
6328 return code->optimizable();
6329}
6330
6331
Steve Blocka7e24c12009-10-30 11:49:00 +00006332Object* JSFunction::SetInstancePrototype(Object* value) {
6333 ASSERT(value->IsJSObject());
Steve Block44f0eee2011-05-26 01:26:41 +01006334 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006335 if (has_initial_map()) {
6336 initial_map()->set_prototype(value);
6337 } else {
6338 // Put the value in the initial map field until an initial map is
6339 // needed. At that point, a new initial map is created and the
6340 // prototype is put into the initial map where it belongs.
6341 set_prototype_or_initial_map(value);
6342 }
Steve Block44f0eee2011-05-26 01:26:41 +01006343 heap->ClearInstanceofCache();
Steve Blocka7e24c12009-10-30 11:49:00 +00006344 return value;
6345}
6346
6347
John Reck59135872010-11-02 12:39:01 -07006348MaybeObject* JSFunction::SetPrototype(Object* value) {
Steve Block6ded16b2010-05-10 14:33:55 +01006349 ASSERT(should_have_prototype());
Steve Blocka7e24c12009-10-30 11:49:00 +00006350 Object* construct_prototype = value;
6351
6352 // If the value is not a JSObject, store the value in the map's
6353 // constructor field so it can be accessed. Also, set the prototype
6354 // used for constructing objects to the original object prototype.
6355 // See ECMA-262 13.2.2.
6356 if (!value->IsJSObject()) {
6357 // Copy the map so this does not affect unrelated functions.
6358 // Remove map transitions because they point to maps with a
6359 // different prototype.
Ben Murdoch8b112d22011-06-08 16:22:53 +01006360 Object* new_object;
John Reck59135872010-11-02 12:39:01 -07006361 { MaybeObject* maybe_new_map = map()->CopyDropTransitions();
Ben Murdoch8b112d22011-06-08 16:22:53 +01006362 if (!maybe_new_map->ToObject(&new_object)) return maybe_new_map;
John Reck59135872010-11-02 12:39:01 -07006363 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01006364 Map* new_map = Map::cast(new_object);
6365 Heap* heap = new_map->heap();
6366 set_map(new_map);
6367 new_map->set_constructor(value);
6368 new_map->set_non_instance_prototype(true);
Steve Blocka7e24c12009-10-30 11:49:00 +00006369 construct_prototype =
Steve Block44f0eee2011-05-26 01:26:41 +01006370 heap->isolate()->context()->global_context()->
6371 initial_object_prototype();
Steve Blocka7e24c12009-10-30 11:49:00 +00006372 } else {
6373 map()->set_non_instance_prototype(false);
6374 }
6375
6376 return SetInstancePrototype(construct_prototype);
6377}
6378
6379
Steve Block6ded16b2010-05-10 14:33:55 +01006380Object* JSFunction::RemovePrototype() {
Steve Block44f0eee2011-05-26 01:26:41 +01006381 Context* global_context = context()->global_context();
6382 Map* no_prototype_map = shared()->strict_mode()
6383 ? global_context->strict_mode_function_without_prototype_map()
6384 : global_context->function_without_prototype_map();
6385
6386 if (map() == no_prototype_map) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01006387 // Be idempotent.
6388 return this;
6389 }
Steve Block44f0eee2011-05-26 01:26:41 +01006390
6391 ASSERT(!shared()->strict_mode() ||
6392 map() == global_context->strict_mode_function_map());
6393 ASSERT(shared()->strict_mode() || map() == global_context->function_map());
6394
6395 set_map(no_prototype_map);
Ben Murdoch8b112d22011-06-08 16:22:53 +01006396 set_prototype_or_initial_map(no_prototype_map->heap()->the_hole_value());
Steve Block6ded16b2010-05-10 14:33:55 +01006397 return this;
6398}
6399
6400
Steve Blocka7e24c12009-10-30 11:49:00 +00006401Object* JSFunction::SetInstanceClassName(String* name) {
6402 shared()->set_instance_class_name(name);
6403 return this;
6404}
6405
6406
Ben Murdochb0fe1622011-05-05 13:52:32 +01006407void JSFunction::PrintName(FILE* out) {
Ben Murdoch589d6972011-11-30 16:04:58 +00006408 SmartArrayPointer<char> name = shared()->DebugName()->ToCString();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006409 PrintF(out, "%s", *name);
6410}
6411
6412
Steve Blocka7e24c12009-10-30 11:49:00 +00006413Context* JSFunction::GlobalContextFromLiterals(FixedArray* literals) {
6414 return Context::cast(literals->get(JSFunction::kLiteralGlobalContextIndex));
6415}
6416
6417
Steve Block44f0eee2011-05-26 01:26:41 +01006418MaybeObject* Oddball::Initialize(const char* to_string,
6419 Object* to_number,
6420 byte kind) {
John Reck59135872010-11-02 12:39:01 -07006421 Object* symbol;
Steve Block44f0eee2011-05-26 01:26:41 +01006422 { MaybeObject* maybe_symbol =
6423 Isolate::Current()->heap()->LookupAsciiSymbol(to_string);
John Reck59135872010-11-02 12:39:01 -07006424 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
6425 }
Steve Blocka7e24c12009-10-30 11:49:00 +00006426 set_to_string(String::cast(symbol));
6427 set_to_number(to_number);
Steve Block44f0eee2011-05-26 01:26:41 +01006428 set_kind(kind);
Steve Blocka7e24c12009-10-30 11:49:00 +00006429 return this;
6430}
6431
6432
Ben Murdochf87a2032010-10-22 12:50:53 +01006433String* SharedFunctionInfo::DebugName() {
6434 Object* n = name();
6435 if (!n->IsString() || String::cast(n)->length() == 0) return inferred_name();
6436 return String::cast(n);
6437}
6438
6439
Steve Blocka7e24c12009-10-30 11:49:00 +00006440bool SharedFunctionInfo::HasSourceCode() {
6441 return !script()->IsUndefined() &&
Iain Merrick75681382010-08-19 15:07:18 +01006442 !reinterpret_cast<Script*>(script())->source()->IsUndefined();
Steve Blocka7e24c12009-10-30 11:49:00 +00006443}
6444
6445
6446Object* SharedFunctionInfo::GetSourceCode() {
Steve Block44f0eee2011-05-26 01:26:41 +01006447 Isolate* isolate = GetIsolate();
6448 if (!HasSourceCode()) return isolate->heap()->undefined_value();
6449 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00006450 Object* source = Script::cast(script())->source();
Steve Block44f0eee2011-05-26 01:26:41 +01006451 return *SubString(Handle<String>(String::cast(source), isolate),
Steve Blocka7e24c12009-10-30 11:49:00 +00006452 start_position(), end_position());
6453}
6454
6455
Ben Murdochb0fe1622011-05-05 13:52:32 +01006456int SharedFunctionInfo::SourceSize() {
6457 return end_position() - start_position();
6458}
6459
6460
Steve Blocka7e24c12009-10-30 11:49:00 +00006461int SharedFunctionInfo::CalculateInstanceSize() {
6462 int instance_size =
6463 JSObject::kHeaderSize +
6464 expected_nof_properties() * kPointerSize;
6465 if (instance_size > JSObject::kMaxInstanceSize) {
6466 instance_size = JSObject::kMaxInstanceSize;
6467 }
6468 return instance_size;
6469}
6470
6471
6472int SharedFunctionInfo::CalculateInObjectProperties() {
6473 return (CalculateInstanceSize() - JSObject::kHeaderSize) / kPointerSize;
6474}
6475
6476
Andrei Popescu402d9372010-02-26 13:31:12 +00006477bool SharedFunctionInfo::CanGenerateInlineConstructor(Object* prototype) {
6478 // Check the basic conditions for generating inline constructor code.
6479 if (!FLAG_inline_new
6480 || !has_only_simple_this_property_assignments()
6481 || this_property_assignments_count() == 0) {
6482 return false;
6483 }
6484
6485 // If the prototype is null inline constructors cause no problems.
6486 if (!prototype->IsJSObject()) {
6487 ASSERT(prototype->IsNull());
6488 return true;
6489 }
6490
Ben Murdoch8b112d22011-06-08 16:22:53 +01006491 Heap* heap = GetHeap();
6492
Andrei Popescu402d9372010-02-26 13:31:12 +00006493 // Traverse the proposed prototype chain looking for setters for properties of
6494 // the same names as are set by the inline constructor.
6495 for (Object* obj = prototype;
Steve Block44f0eee2011-05-26 01:26:41 +01006496 obj != heap->null_value();
Andrei Popescu402d9372010-02-26 13:31:12 +00006497 obj = obj->GetPrototype()) {
6498 JSObject* js_object = JSObject::cast(obj);
6499 for (int i = 0; i < this_property_assignments_count(); i++) {
6500 LookupResult result;
6501 String* name = GetThisPropertyAssignmentName(i);
6502 js_object->LocalLookupRealNamedProperty(name, &result);
6503 if (result.IsProperty() && result.type() == CALLBACKS) {
6504 return false;
6505 }
6506 }
6507 }
6508
6509 return true;
6510}
6511
6512
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006513void SharedFunctionInfo::ForbidInlineConstructor() {
6514 set_compiler_hints(BooleanBit::set(compiler_hints(),
6515 kHasOnlySimpleThisPropertyAssignments,
6516 false));
6517}
6518
6519
Steve Blocka7e24c12009-10-30 11:49:00 +00006520void SharedFunctionInfo::SetThisPropertyAssignmentsInfo(
Steve Blocka7e24c12009-10-30 11:49:00 +00006521 bool only_simple_this_property_assignments,
6522 FixedArray* assignments) {
6523 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006524 kHasOnlySimpleThisPropertyAssignments,
6525 only_simple_this_property_assignments));
6526 set_this_property_assignments(assignments);
6527 set_this_property_assignments_count(assignments->length() / 3);
6528}
6529
6530
6531void SharedFunctionInfo::ClearThisPropertyAssignmentsInfo() {
Steve Block44f0eee2011-05-26 01:26:41 +01006532 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00006533 set_compiler_hints(BooleanBit::set(compiler_hints(),
Steve Blocka7e24c12009-10-30 11:49:00 +00006534 kHasOnlySimpleThisPropertyAssignments,
6535 false));
Steve Block44f0eee2011-05-26 01:26:41 +01006536 set_this_property_assignments(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00006537 set_this_property_assignments_count(0);
6538}
6539
6540
6541String* SharedFunctionInfo::GetThisPropertyAssignmentName(int index) {
6542 Object* obj = this_property_assignments();
6543 ASSERT(obj->IsFixedArray());
6544 ASSERT(index < this_property_assignments_count());
6545 obj = FixedArray::cast(obj)->get(index * 3);
6546 ASSERT(obj->IsString());
6547 return String::cast(obj);
6548}
6549
6550
6551bool SharedFunctionInfo::IsThisPropertyAssignmentArgument(int index) {
6552 Object* obj = this_property_assignments();
6553 ASSERT(obj->IsFixedArray());
6554 ASSERT(index < this_property_assignments_count());
6555 obj = FixedArray::cast(obj)->get(index * 3 + 1);
6556 return Smi::cast(obj)->value() != -1;
6557}
6558
6559
6560int SharedFunctionInfo::GetThisPropertyAssignmentArgument(int index) {
6561 ASSERT(IsThisPropertyAssignmentArgument(index));
6562 Object* obj =
6563 FixedArray::cast(this_property_assignments())->get(index * 3 + 1);
6564 return Smi::cast(obj)->value();
6565}
6566
6567
6568Object* SharedFunctionInfo::GetThisPropertyAssignmentConstant(int index) {
6569 ASSERT(!IsThisPropertyAssignmentArgument(index));
6570 Object* obj =
6571 FixedArray::cast(this_property_assignments())->get(index * 3 + 2);
6572 return obj;
6573}
6574
6575
Steve Blocka7e24c12009-10-30 11:49:00 +00006576// Support function for printing the source code to a StringStream
6577// without any allocation in the heap.
6578void SharedFunctionInfo::SourceCodePrint(StringStream* accumulator,
6579 int max_length) {
6580 // For some native functions there is no source.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006581 if (!HasSourceCode()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006582 accumulator->Add("<No Source>");
6583 return;
6584 }
6585
Steve Blockd0582a62009-12-15 09:54:21 +00006586 // Get the source for the script which this function came from.
Steve Blocka7e24c12009-10-30 11:49:00 +00006587 // Don't use String::cast because we don't want more assertion errors while
6588 // we are already creating a stack dump.
6589 String* script_source =
6590 reinterpret_cast<String*>(Script::cast(script())->source());
6591
6592 if (!script_source->LooksValid()) {
6593 accumulator->Add("<Invalid Source>");
6594 return;
6595 }
6596
6597 if (!is_toplevel()) {
6598 accumulator->Add("function ");
6599 Object* name = this->name();
6600 if (name->IsString() && String::cast(name)->length() > 0) {
6601 accumulator->PrintName(name);
6602 }
6603 }
6604
6605 int len = end_position() - start_position();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006606 if (len <= max_length || max_length < 0) {
6607 accumulator->Put(script_source, start_position(), end_position());
6608 } else {
Steve Blocka7e24c12009-10-30 11:49:00 +00006609 accumulator->Put(script_source,
6610 start_position(),
6611 start_position() + max_length);
6612 accumulator->Add("...\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00006613 }
6614}
6615
6616
Ben Murdochb0fe1622011-05-05 13:52:32 +01006617static bool IsCodeEquivalent(Code* code, Code* recompiled) {
6618 if (code->instruction_size() != recompiled->instruction_size()) return false;
6619 ByteArray* code_relocation = code->relocation_info();
6620 ByteArray* recompiled_relocation = recompiled->relocation_info();
6621 int length = code_relocation->length();
6622 if (length != recompiled_relocation->length()) return false;
6623 int compare = memcmp(code_relocation->GetDataStartAddress(),
6624 recompiled_relocation->GetDataStartAddress(),
6625 length);
6626 return compare == 0;
6627}
6628
6629
6630void SharedFunctionInfo::EnableDeoptimizationSupport(Code* recompiled) {
6631 ASSERT(!has_deoptimization_support());
6632 AssertNoAllocation no_allocation;
6633 Code* code = this->code();
6634 if (IsCodeEquivalent(code, recompiled)) {
6635 // Copy the deoptimization data from the recompiled code.
6636 code->set_deoptimization_data(recompiled->deoptimization_data());
6637 code->set_has_deoptimization_support(true);
6638 } else {
6639 // TODO(3025757): In case the recompiled isn't equivalent to the
6640 // old code, we have to replace it. We should try to avoid this
6641 // altogether because it flushes valuable type feedback by
6642 // effectively resetting all IC state.
6643 set_code(recompiled);
6644 }
6645 ASSERT(has_deoptimization_support());
6646}
6647
6648
Ben Murdoch257744e2011-11-30 15:57:28 +00006649void SharedFunctionInfo::DisableOptimization(JSFunction* function) {
6650 // Disable optimization for the shared function info and mark the
6651 // code as non-optimizable. The marker on the shared function info
6652 // is there because we flush non-optimized code thereby loosing the
6653 // non-optimizable information for the code. When the code is
6654 // regenerated and set on the shared function info it is marked as
6655 // non-optimizable if optimization is disabled for the shared
6656 // function info.
6657 set_optimization_disabled(true);
6658 // Code should be the lazy compilation stub or else unoptimized. If the
6659 // latter, disable optimization for the code too.
6660 ASSERT(code()->kind() == Code::FUNCTION || code()->kind() == Code::BUILTIN);
6661 if (code()->kind() == Code::FUNCTION) {
6662 code()->set_optimizable(false);
6663 }
6664 if (FLAG_trace_opt) {
6665 PrintF("[disabled optimization for: ");
6666 function->PrintName();
6667 PrintF(" / %" V8PRIxPTR "]\n", reinterpret_cast<intptr_t>(function));
6668 }
6669}
6670
6671
Ben Murdochb0fe1622011-05-05 13:52:32 +01006672bool SharedFunctionInfo::VerifyBailoutId(int id) {
6673 // TODO(srdjan): debugging ARM crashes in hydrogen. OK to disable while
6674 // we are always bailing out on ARM.
6675
6676 ASSERT(id != AstNode::kNoNumber);
6677 Code* unoptimized = code();
6678 DeoptimizationOutputData* data =
6679 DeoptimizationOutputData::cast(unoptimized->deoptimization_data());
6680 unsigned ignore = Deoptimizer::GetOutputInfo(data, id, this);
6681 USE(ignore);
6682 return true; // Return true if there was no ASSERT.
6683}
6684
6685
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006686void SharedFunctionInfo::StartInobjectSlackTracking(Map* map) {
6687 ASSERT(!IsInobjectSlackTrackingInProgress());
6688
6689 // Only initiate the tracking the first time.
6690 if (live_objects_may_exist()) return;
6691 set_live_objects_may_exist(true);
6692
6693 // No tracking during the snapshot construction phase.
6694 if (Serializer::enabled()) return;
6695
6696 if (map->unused_property_fields() == 0) return;
6697
6698 // Nonzero counter is a leftover from the previous attempt interrupted
6699 // by GC, keep it.
6700 if (construction_count() == 0) {
6701 set_construction_count(kGenerousAllocationCount);
6702 }
6703 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006704 Builtins* builtins = map->heap()->isolate()->builtins();
6705 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006706 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006707 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006708}
6709
6710
6711// Called from GC, hence reinterpret_cast and unchecked accessors.
6712void SharedFunctionInfo::DetachInitialMap() {
6713 Map* map = reinterpret_cast<Map*>(initial_map());
6714
6715 // Make the map remember to restore the link if it survives the GC.
6716 map->set_bit_field2(
6717 map->bit_field2() | (1 << Map::kAttachedToSharedFunctionInfo));
6718
6719 // Undo state changes made by StartInobjectTracking (except the
6720 // construction_count). This way if the initial map does not survive the GC
6721 // then StartInobjectTracking will be called again the next time the
6722 // constructor is called. The countdown will continue and (possibly after
6723 // several more GCs) CompleteInobjectSlackTracking will eventually be called.
Steve Block44f0eee2011-05-26 01:26:41 +01006724 set_initial_map(map->heap()->raw_unchecked_undefined_value());
6725 Builtins* builtins = map->heap()->isolate()->builtins();
6726 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006727 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006728 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006729 // It is safe to clear the flag: it will be set again if the map is live.
6730 set_live_objects_may_exist(false);
6731}
6732
6733
6734// Called from GC, hence reinterpret_cast and unchecked accessors.
6735void SharedFunctionInfo::AttachInitialMap(Map* map) {
6736 map->set_bit_field2(
6737 map->bit_field2() & ~(1 << Map::kAttachedToSharedFunctionInfo));
6738
6739 // Resume inobject slack tracking.
6740 set_initial_map(map);
Steve Block44f0eee2011-05-26 01:26:41 +01006741 Builtins* builtins = map->heap()->isolate()->builtins();
6742 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubGeneric),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006743 *RawField(this, kConstructStubOffset));
Steve Block44f0eee2011-05-26 01:26:41 +01006744 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubCountdown));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006745 // The map survived the gc, so there may be objects referencing it.
6746 set_live_objects_may_exist(true);
6747}
6748
6749
6750static void GetMinInobjectSlack(Map* map, void* data) {
6751 int slack = map->unused_property_fields();
6752 if (*reinterpret_cast<int*>(data) > slack) {
6753 *reinterpret_cast<int*>(data) = slack;
6754 }
6755}
6756
6757
6758static void ShrinkInstanceSize(Map* map, void* data) {
6759 int slack = *reinterpret_cast<int*>(data);
6760 map->set_inobject_properties(map->inobject_properties() - slack);
6761 map->set_unused_property_fields(map->unused_property_fields() - slack);
6762 map->set_instance_size(map->instance_size() - slack * kPointerSize);
6763
6764 // Visitor id might depend on the instance size, recalculate it.
6765 map->set_visitor_id(StaticVisitorBase::GetVisitorId(map));
6766}
6767
6768
6769void SharedFunctionInfo::CompleteInobjectSlackTracking() {
6770 ASSERT(live_objects_may_exist() && IsInobjectSlackTrackingInProgress());
6771 Map* map = Map::cast(initial_map());
6772
Steve Block44f0eee2011-05-26 01:26:41 +01006773 Heap* heap = map->heap();
6774 set_initial_map(heap->undefined_value());
6775 Builtins* builtins = heap->isolate()->builtins();
6776 ASSERT_EQ(builtins->builtin(Builtins::kJSConstructStubCountdown),
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006777 construct_stub());
Steve Block44f0eee2011-05-26 01:26:41 +01006778 set_construct_stub(builtins->builtin(Builtins::kJSConstructStubGeneric));
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006779
6780 int slack = map->unused_property_fields();
6781 map->TraverseTransitionTree(&GetMinInobjectSlack, &slack);
6782 if (slack != 0) {
6783 // Resize the initial map and all maps in its transition tree.
6784 map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00006785
Kristian Monsen0d5e1162010-09-30 15:31:59 +01006786 // Give the correct expected_nof_properties to initial maps created later.
6787 ASSERT(expected_nof_properties() >= slack);
6788 set_expected_nof_properties(expected_nof_properties() - slack);
6789 }
6790}
6791
6792
Steve Blocka7e24c12009-10-30 11:49:00 +00006793void ObjectVisitor::VisitCodeTarget(RelocInfo* rinfo) {
6794 ASSERT(RelocInfo::IsCodeTarget(rinfo->rmode()));
6795 Object* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
6796 Object* old_target = target;
6797 VisitPointer(&target);
6798 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6799}
6800
6801
Steve Block791712a2010-08-27 10:21:07 +01006802void ObjectVisitor::VisitCodeEntry(Address entry_address) {
6803 Object* code = Code::GetObjectFromEntryAddress(entry_address);
6804 Object* old_code = code;
6805 VisitPointer(&code);
6806 if (code != old_code) {
6807 Memory::Address_at(entry_address) = reinterpret_cast<Code*>(code)->entry();
6808 }
6809}
6810
6811
Ben Murdochb0fe1622011-05-05 13:52:32 +01006812void ObjectVisitor::VisitGlobalPropertyCell(RelocInfo* rinfo) {
6813 ASSERT(rinfo->rmode() == RelocInfo::GLOBAL_PROPERTY_CELL);
6814 Object* cell = rinfo->target_cell();
6815 Object* old_cell = cell;
6816 VisitPointer(&cell);
6817 if (cell != old_cell) {
6818 rinfo->set_target_cell(reinterpret_cast<JSGlobalPropertyCell*>(cell));
6819 }
6820}
6821
6822
Steve Blocka7e24c12009-10-30 11:49:00 +00006823void ObjectVisitor::VisitDebugTarget(RelocInfo* rinfo) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01006824 ASSERT((RelocInfo::IsJSReturn(rinfo->rmode()) &&
6825 rinfo->IsPatchedReturnSequence()) ||
6826 (RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
6827 rinfo->IsPatchedDebugBreakSlotSequence()));
Steve Blocka7e24c12009-10-30 11:49:00 +00006828 Object* target = Code::GetCodeFromTargetAddress(rinfo->call_address());
6829 Object* old_target = target;
6830 VisitPointer(&target);
6831 CHECK_EQ(target, old_target); // VisitPointer doesn't change Code* *target.
6832}
6833
6834
Ben Murdochb0fe1622011-05-05 13:52:32 +01006835void Code::InvalidateRelocation() {
Ben Murdoch8b112d22011-06-08 16:22:53 +01006836 set_relocation_info(heap()->empty_byte_array());
Ben Murdochb0fe1622011-05-05 13:52:32 +01006837}
6838
6839
Steve Blockd0582a62009-12-15 09:54:21 +00006840void Code::Relocate(intptr_t delta) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006841 for (RelocIterator it(this, RelocInfo::kApplyMask); !it.done(); it.next()) {
6842 it.rinfo()->apply(delta);
6843 }
6844 CPU::FlushICache(instruction_start(), instruction_size());
6845}
6846
6847
6848void Code::CopyFrom(const CodeDesc& desc) {
6849 // copy code
6850 memmove(instruction_start(), desc.buffer, desc.instr_size);
6851
Steve Blocka7e24c12009-10-30 11:49:00 +00006852 // copy reloc info
6853 memmove(relocation_start(),
6854 desc.buffer + desc.buffer_size - desc.reloc_size,
6855 desc.reloc_size);
6856
6857 // unbox handles and relocate
Steve Block3ce2e202009-11-05 08:53:23 +00006858 intptr_t delta = instruction_start() - desc.buffer;
Steve Blocka7e24c12009-10-30 11:49:00 +00006859 int mode_mask = RelocInfo::kCodeTargetMask |
6860 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
Ben Murdochb0fe1622011-05-05 13:52:32 +01006861 RelocInfo::ModeMask(RelocInfo::GLOBAL_PROPERTY_CELL) |
Steve Blocka7e24c12009-10-30 11:49:00 +00006862 RelocInfo::kApplyMask;
Steve Block3ce2e202009-11-05 08:53:23 +00006863 Assembler* origin = desc.origin; // Needed to find target_object on X64.
Steve Blocka7e24c12009-10-30 11:49:00 +00006864 for (RelocIterator it(this, mode_mask); !it.done(); it.next()) {
6865 RelocInfo::Mode mode = it.rinfo()->rmode();
6866 if (mode == RelocInfo::EMBEDDED_OBJECT) {
Steve Block3ce2e202009-11-05 08:53:23 +00006867 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006868 it.rinfo()->set_target_object(*p);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006869 } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
Steve Block1e0659c2011-05-24 12:43:12 +01006870 Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
Ben Murdochb0fe1622011-05-05 13:52:32 +01006871 it.rinfo()->set_target_cell(*cell);
Steve Blocka7e24c12009-10-30 11:49:00 +00006872 } else if (RelocInfo::IsCodeTarget(mode)) {
6873 // rewrite code handles in inline cache targets to direct
6874 // pointers to the first instruction in the code object
Steve Block3ce2e202009-11-05 08:53:23 +00006875 Handle<Object> p = it.rinfo()->target_object_handle(origin);
Steve Blocka7e24c12009-10-30 11:49:00 +00006876 Code* code = Code::cast(*p);
6877 it.rinfo()->set_target_address(code->instruction_start());
6878 } else {
6879 it.rinfo()->apply(delta);
6880 }
6881 }
6882 CPU::FlushICache(instruction_start(), instruction_size());
6883}
6884
6885
6886// Locate the source position which is closest to the address in the code. This
6887// is using the source position information embedded in the relocation info.
6888// The position returned is relative to the beginning of the script where the
6889// source for this function is found.
6890int Code::SourcePosition(Address pc) {
6891 int distance = kMaxInt;
6892 int position = RelocInfo::kNoPosition; // Initially no position found.
6893 // Run through all the relocation info to find the best matching source
6894 // position. All the code needs to be considered as the sequence of the
6895 // instructions in the code does not necessarily follow the same order as the
6896 // source.
6897 RelocIterator it(this, RelocInfo::kPositionMask);
6898 while (!it.done()) {
6899 // Only look at positions after the current pc.
6900 if (it.rinfo()->pc() < pc) {
6901 // Get position and distance.
Steve Blockd0582a62009-12-15 09:54:21 +00006902
6903 int dist = static_cast<int>(pc - it.rinfo()->pc());
6904 int pos = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006905 // If this position is closer than the current candidate or if it has the
6906 // same distance as the current candidate and the position is higher then
6907 // this position is the new candidate.
6908 if ((dist < distance) ||
6909 (dist == distance && pos > position)) {
6910 position = pos;
6911 distance = dist;
6912 }
6913 }
6914 it.next();
6915 }
6916 return position;
6917}
6918
6919
6920// Same as Code::SourcePosition above except it only looks for statement
6921// positions.
6922int Code::SourceStatementPosition(Address pc) {
6923 // First find the position as close as possible using all position
6924 // information.
6925 int position = SourcePosition(pc);
6926 // Now find the closest statement position before the position.
6927 int statement_position = 0;
6928 RelocIterator it(this, RelocInfo::kPositionMask);
6929 while (!it.done()) {
6930 if (RelocInfo::IsStatementPosition(it.rinfo()->rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +00006931 int p = static_cast<int>(it.rinfo()->data());
Steve Blocka7e24c12009-10-30 11:49:00 +00006932 if (statement_position < p && p <= position) {
6933 statement_position = p;
6934 }
6935 }
6936 it.next();
6937 }
6938 return statement_position;
6939}
6940
6941
Ben Murdochb8e0da22011-05-16 14:20:40 +01006942SafepointEntry Code::GetSafepointEntry(Address pc) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006943 SafepointTable table(this);
Ben Murdochb8e0da22011-05-16 14:20:40 +01006944 return table.FindEntry(pc);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006945}
6946
6947
6948void Code::SetNoStackCheckTable() {
6949 // Indicate the absence of a stack-check table by a table start after the
6950 // end of the instructions. Table start must be aligned, so round up.
Steve Block1e0659c2011-05-24 12:43:12 +01006951 set_stack_check_table_offset(RoundUp(instruction_size(), kIntSize));
Ben Murdochb0fe1622011-05-05 13:52:32 +01006952}
6953
6954
6955Map* Code::FindFirstMap() {
6956 ASSERT(is_inline_cache_stub());
6957 AssertNoAllocation no_allocation;
6958 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
6959 for (RelocIterator it(this, mask); !it.done(); it.next()) {
6960 RelocInfo* info = it.rinfo();
6961 Object* object = info->target_object();
6962 if (object->IsMap()) return Map::cast(object);
6963 }
6964 return NULL;
6965}
6966
6967
Steve Blocka7e24c12009-10-30 11:49:00 +00006968#ifdef ENABLE_DISASSEMBLER
Ben Murdochb0fe1622011-05-05 13:52:32 +01006969
Ben Murdochb0fe1622011-05-05 13:52:32 +01006970void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
6971 disasm::NameConverter converter;
6972 int deopt_count = DeoptCount();
6973 PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
6974 if (0 == deopt_count) return;
6975
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006976 PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc",
6977 FLAG_print_code_verbose ? "commands" : "");
Ben Murdochb0fe1622011-05-05 13:52:32 +01006978 for (int i = 0; i < deopt_count; i++) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01006979 PrintF(out, "%6d %6d %6d",
6980 i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006981
6982 if (!FLAG_print_code_verbose) {
6983 PrintF(out, "\n");
6984 continue;
6985 }
6986 // Print details of the frame translation.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006987 int translation_index = TranslationIndex(i)->value();
6988 TranslationIterator iterator(TranslationByteArray(), translation_index);
6989 Translation::Opcode opcode =
6990 static_cast<Translation::Opcode>(iterator.Next());
6991 ASSERT(Translation::BEGIN == opcode);
6992 int frame_count = iterator.Next();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006993 PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
6994 frame_count);
Ben Murdochb0fe1622011-05-05 13:52:32 +01006995
Ben Murdoch69a99ed2011-11-30 16:03:39 +00006996 while (iterator.HasNext() &&
6997 Translation::BEGIN !=
6998 (opcode = static_cast<Translation::Opcode>(iterator.Next()))) {
6999 PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
7000
7001 switch (opcode) {
7002 case Translation::BEGIN:
7003 UNREACHABLE();
7004 break;
7005
7006 case Translation::FRAME: {
7007 int ast_id = iterator.Next();
7008 int function_id = iterator.Next();
7009 JSFunction* function =
7010 JSFunction::cast(LiteralArray()->get(function_id));
7011 unsigned height = iterator.Next();
Ben Murdoch589d6972011-11-30 16:04:58 +00007012 PrintF(out, "{ast_id=%d, function=", ast_id);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007013 function->PrintName(out);
7014 PrintF(out, ", height=%u}", height);
7015 break;
7016 }
7017
7018 case Translation::DUPLICATE:
7019 break;
7020
7021 case Translation::REGISTER: {
7022 int reg_code = iterator.Next();
7023 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7024 break;
7025 }
7026
7027 case Translation::INT32_REGISTER: {
7028 int reg_code = iterator.Next();
7029 PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
7030 break;
7031 }
7032
7033 case Translation::DOUBLE_REGISTER: {
7034 int reg_code = iterator.Next();
7035 PrintF(out, "{input=%s}",
7036 DoubleRegister::AllocationIndexToString(reg_code));
7037 break;
7038 }
7039
7040 case Translation::STACK_SLOT: {
7041 int input_slot_index = iterator.Next();
7042 PrintF(out, "{input=%d}", input_slot_index);
7043 break;
7044 }
7045
7046 case Translation::INT32_STACK_SLOT: {
7047 int input_slot_index = iterator.Next();
7048 PrintF(out, "{input=%d}", input_slot_index);
7049 break;
7050 }
7051
7052 case Translation::DOUBLE_STACK_SLOT: {
7053 int input_slot_index = iterator.Next();
7054 PrintF(out, "{input=%d}", input_slot_index);
7055 break;
7056 }
7057
7058 case Translation::LITERAL: {
7059 unsigned literal_index = iterator.Next();
7060 PrintF(out, "{literal_id=%u}", literal_index);
7061 break;
7062 }
7063
7064 case Translation::ARGUMENTS_OBJECT:
7065 break;
Ben Murdochb0fe1622011-05-05 13:52:32 +01007066 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007067 PrintF(out, "\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007068 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007069 }
7070}
7071
7072
7073void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
7074 PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
7075 this->DeoptPoints());
7076 if (this->DeoptPoints() == 0) return;
7077
7078 PrintF("%6s %8s %s\n", "ast id", "pc", "state");
7079 for (int i = 0; i < this->DeoptPoints(); i++) {
7080 int pc_and_state = this->PcAndState(i)->value();
7081 PrintF("%6d %8d %s\n",
7082 this->AstId(i)->value(),
7083 FullCodeGenerator::PcField::decode(pc_and_state),
7084 FullCodeGenerator::State2String(
7085 FullCodeGenerator::StateField::decode(pc_and_state)));
7086 }
7087}
7088
Ben Murdochb0fe1622011-05-05 13:52:32 +01007089
Steve Blocka7e24c12009-10-30 11:49:00 +00007090// Identify kind of code.
7091const char* Code::Kind2String(Kind kind) {
7092 switch (kind) {
7093 case FUNCTION: return "FUNCTION";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007094 case OPTIMIZED_FUNCTION: return "OPTIMIZED_FUNCTION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007095 case STUB: return "STUB";
7096 case BUILTIN: return "BUILTIN";
7097 case LOAD_IC: return "LOAD_IC";
7098 case KEYED_LOAD_IC: return "KEYED_LOAD_IC";
7099 case STORE_IC: return "STORE_IC";
7100 case KEYED_STORE_IC: return "KEYED_STORE_IC";
7101 case CALL_IC: return "CALL_IC";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007102 case KEYED_CALL_IC: return "KEYED_CALL_IC";
Ben Murdoch257744e2011-11-30 15:57:28 +00007103 case UNARY_OP_IC: return "UNARY_OP_IC";
7104 case BINARY_OP_IC: return "BINARY_OP_IC";
Ben Murdochb0fe1622011-05-05 13:52:32 +01007105 case COMPARE_IC: return "COMPARE_IC";
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007106 case TO_BOOLEAN_IC: return "TO_BOOLEAN_IC";
Steve Blocka7e24c12009-10-30 11:49:00 +00007107 }
7108 UNREACHABLE();
7109 return NULL;
7110}
7111
7112
7113const char* Code::ICState2String(InlineCacheState state) {
7114 switch (state) {
7115 case UNINITIALIZED: return "UNINITIALIZED";
7116 case PREMONOMORPHIC: return "PREMONOMORPHIC";
7117 case MONOMORPHIC: return "MONOMORPHIC";
7118 case MONOMORPHIC_PROTOTYPE_FAILURE: return "MONOMORPHIC_PROTOTYPE_FAILURE";
7119 case MEGAMORPHIC: return "MEGAMORPHIC";
7120 case DEBUG_BREAK: return "DEBUG_BREAK";
7121 case DEBUG_PREPARE_STEP_IN: return "DEBUG_PREPARE_STEP_IN";
7122 }
7123 UNREACHABLE();
7124 return NULL;
7125}
7126
7127
7128const char* Code::PropertyType2String(PropertyType type) {
7129 switch (type) {
7130 case NORMAL: return "NORMAL";
7131 case FIELD: return "FIELD";
7132 case CONSTANT_FUNCTION: return "CONSTANT_FUNCTION";
7133 case CALLBACKS: return "CALLBACKS";
Ben Murdoch257744e2011-11-30 15:57:28 +00007134 case HANDLER: return "HANDLER";
Steve Blocka7e24c12009-10-30 11:49:00 +00007135 case INTERCEPTOR: return "INTERCEPTOR";
7136 case MAP_TRANSITION: return "MAP_TRANSITION";
Ben Murdoch589d6972011-11-30 16:04:58 +00007137 case ELEMENTS_TRANSITION: return "ELEMENTS_TRANSITION";
Steve Blocka7e24c12009-10-30 11:49:00 +00007138 case CONSTANT_TRANSITION: return "CONSTANT_TRANSITION";
7139 case NULL_DESCRIPTOR: return "NULL_DESCRIPTOR";
7140 }
7141 UNREACHABLE();
7142 return NULL;
7143}
7144
Ben Murdochb0fe1622011-05-05 13:52:32 +01007145
Steve Block1e0659c2011-05-24 12:43:12 +01007146void Code::PrintExtraICState(FILE* out, Kind kind, ExtraICState extra) {
7147 const char* name = NULL;
7148 switch (kind) {
7149 case CALL_IC:
7150 if (extra == STRING_INDEX_OUT_OF_BOUNDS) {
7151 name = "STRING_INDEX_OUT_OF_BOUNDS";
7152 }
7153 break;
7154 case STORE_IC:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01007155 case KEYED_STORE_IC:
7156 if (extra == kStrictMode) {
Steve Block1e0659c2011-05-24 12:43:12 +01007157 name = "STRICT";
7158 }
7159 break;
7160 default:
7161 break;
7162 }
7163 if (name != NULL) {
7164 PrintF(out, "extra_ic_state = %s\n", name);
7165 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007166 PrintF(out, "extra_ic_state = %d\n", extra);
Steve Block1e0659c2011-05-24 12:43:12 +01007167 }
7168}
7169
7170
Ben Murdochb0fe1622011-05-05 13:52:32 +01007171void Code::Disassemble(const char* name, FILE* out) {
7172 PrintF(out, "kind = %s\n", Kind2String(kind()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007173 if (is_inline_cache_stub()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007174 PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
Steve Block1e0659c2011-05-24 12:43:12 +01007175 PrintExtraICState(out, kind(), extra_ic_state());
Steve Blocka7e24c12009-10-30 11:49:00 +00007176 if (ic_state() == MONOMORPHIC) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007177 PrintF(out, "type = %s\n", PropertyType2String(type()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007178 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007179 if (is_call_stub() || is_keyed_call_stub()) {
7180 PrintF(out, "argc = %d\n", arguments_count());
7181 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007182 }
7183 if ((name != NULL) && (name[0] != '\0')) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01007184 PrintF(out, "name = %s\n", name);
7185 }
7186 if (kind() == OPTIMIZED_FUNCTION) {
7187 PrintF(out, "stack_slots = %d\n", stack_slots());
Steve Blocka7e24c12009-10-30 11:49:00 +00007188 }
7189
Ben Murdochb0fe1622011-05-05 13:52:32 +01007190 PrintF(out, "Instructions (size = %d)\n", instruction_size());
7191 Disassembler::Decode(out, this);
7192 PrintF(out, "\n");
7193
Ben Murdochb0fe1622011-05-05 13:52:32 +01007194 if (kind() == FUNCTION) {
7195 DeoptimizationOutputData* data =
7196 DeoptimizationOutputData::cast(this->deoptimization_data());
7197 data->DeoptimizationOutputDataPrint(out);
7198 } else if (kind() == OPTIMIZED_FUNCTION) {
7199 DeoptimizationInputData* data =
7200 DeoptimizationInputData::cast(this->deoptimization_data());
7201 data->DeoptimizationInputDataPrint(out);
7202 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007203 PrintF("\n");
Ben Murdochb0fe1622011-05-05 13:52:32 +01007204
7205 if (kind() == OPTIMIZED_FUNCTION) {
7206 SafepointTable table(this);
7207 PrintF(out, "Safepoints (size = %u)\n", table.size());
7208 for (unsigned i = 0; i < table.length(); i++) {
7209 unsigned pc_offset = table.GetPcOffset(i);
7210 PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
7211 table.PrintEntry(i);
7212 PrintF(out, " (sp -> fp)");
Ben Murdochb8e0da22011-05-16 14:20:40 +01007213 SafepointEntry entry = table.GetEntry(i);
7214 if (entry.deoptimization_index() != Safepoint::kNoDeoptimizationIndex) {
7215 PrintF(out, " %6d", entry.deoptimization_index());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007216 } else {
7217 PrintF(out, " <none>");
7218 }
Ben Murdochb8e0da22011-05-16 14:20:40 +01007219 if (entry.argument_count() > 0) {
7220 PrintF(out, " argc: %d", entry.argument_count());
7221 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01007222 PrintF(out, "\n");
7223 }
7224 PrintF(out, "\n");
7225 } else if (kind() == FUNCTION) {
Steve Block1e0659c2011-05-24 12:43:12 +01007226 unsigned offset = stack_check_table_offset();
Ben Murdochb0fe1622011-05-05 13:52:32 +01007227 // If there is no stack check table, the "table start" will at or after
7228 // (due to alignment) the end of the instruction stream.
7229 if (static_cast<int>(offset) < instruction_size()) {
7230 unsigned* address =
7231 reinterpret_cast<unsigned*>(instruction_start() + offset);
7232 unsigned length = address[0];
7233 PrintF(out, "Stack checks (size = %u)\n", length);
7234 PrintF(out, "ast_id pc_offset\n");
7235 for (unsigned i = 0; i < length; ++i) {
7236 unsigned index = (2 * i) + 1;
7237 PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
7238 }
7239 PrintF(out, "\n");
7240 }
7241 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007242
7243 PrintF("RelocInfo (size = %d)\n", relocation_size());
Ben Murdochb0fe1622011-05-05 13:52:32 +01007244 for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
7245 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00007246}
7247#endif // ENABLE_DISASSEMBLER
7248
7249
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007250static void CopyFastElementsToFast(FixedArray* source,
7251 FixedArray* destination,
7252 WriteBarrierMode mode) {
7253 uint32_t count = static_cast<uint32_t>(source->length());
7254 for (uint32_t i = 0; i < count; ++i) {
7255 destination->set(i, source->get(i), mode);
7256 }
7257}
7258
7259
7260static void CopySlowElementsToFast(NumberDictionary* source,
7261 FixedArray* destination,
7262 WriteBarrierMode mode) {
7263 for (int i = 0; i < source->Capacity(); ++i) {
7264 Object* key = source->KeyAt(i);
7265 if (key->IsNumber()) {
7266 uint32_t entry = static_cast<uint32_t>(key->Number());
7267 destination->set(entry, source->ValueAt(i), mode);
7268 }
7269 }
7270}
7271
7272
John Reck59135872010-11-02 12:39:01 -07007273MaybeObject* JSObject::SetFastElementsCapacityAndLength(int capacity,
7274 int length) {
Steve Block44f0eee2011-05-26 01:26:41 +01007275 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +00007276 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007277 ASSERT(!HasExternalArrayElements());
Steve Block8defd9f2010-07-08 12:39:36 +01007278
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007279 // Allocate a new fast elements backing store.
7280 FixedArray* new_elements = NULL;
7281 { Object* object;
7282 MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
7283 if (!maybe->ToObject(&object)) return maybe;
7284 new_elements = FixedArray::cast(object);
7285 }
7286
7287 // Find the new map to use for this object if there is a map change.
7288 Map* new_map = NULL;
7289 if (elements()->map() != heap->non_strict_arguments_elements_map()) {
7290 Object* object;
7291 MaybeObject* maybe = map()->GetFastElementsMap();
7292 if (!maybe->ToObject(&object)) return maybe;
7293 new_map = Map::cast(object);
7294 }
7295
7296 switch (GetElementsKind()) {
7297 case FAST_ELEMENTS: {
7298 AssertNoAllocation no_gc;
7299 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7300 CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
7301 set_map(new_map);
7302 set_elements(new_elements);
7303 break;
7304 }
7305 case DICTIONARY_ELEMENTS: {
7306 AssertNoAllocation no_gc;
7307 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7308 CopySlowElementsToFast(NumberDictionary::cast(elements()),
7309 new_elements,
7310 mode);
7311 set_map(new_map);
7312 set_elements(new_elements);
7313 break;
7314 }
7315 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7316 AssertNoAllocation no_gc;
7317 WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
7318 // The object's map and the parameter map are unchanged, the unaliased
7319 // arguments are copied to the new backing store.
7320 FixedArray* parameter_map = FixedArray::cast(elements());
7321 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7322 if (arguments->IsDictionary()) {
7323 CopySlowElementsToFast(NumberDictionary::cast(arguments),
7324 new_elements,
7325 mode);
7326 } else {
7327 CopyFastElementsToFast(arguments, new_elements, mode);
7328 }
7329 parameter_map->set(1, new_elements);
7330 break;
7331 }
7332 case FAST_DOUBLE_ELEMENTS: {
7333 FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
7334 uint32_t old_length = static_cast<uint32_t>(old_elements->length());
7335 // Fill out the new array with this content and array holes.
7336 for (uint32_t i = 0; i < old_length; i++) {
7337 if (!old_elements->is_the_hole(i)) {
7338 Object* obj;
7339 // Objects must be allocated in the old object space, since the
7340 // overall number of HeapNumbers needed for the conversion might
7341 // exceed the capacity of new space, and we would fail repeatedly
7342 // trying to convert the FixedDoubleArray.
7343 MaybeObject* maybe_value_object =
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007344 GetHeap()->AllocateHeapNumber(old_elements->get_scalar(i),
7345 TENURED);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007346 if (!maybe_value_object->ToObject(&obj)) return maybe_value_object;
7347 // Force write barrier. It's not worth trying to exploit
7348 // elems->GetWriteBarrierMode(), since it requires an
7349 // AssertNoAllocation stack object that would have to be positioned
7350 // after the HeapNumber allocation anyway.
7351 new_elements->set(i, obj, UPDATE_WRITE_BARRIER);
7352 }
7353 }
7354 set_map(new_map);
7355 set_elements(new_elements);
7356 break;
7357 }
7358 case EXTERNAL_BYTE_ELEMENTS:
7359 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7360 case EXTERNAL_SHORT_ELEMENTS:
7361 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7362 case EXTERNAL_INT_ELEMENTS:
7363 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7364 case EXTERNAL_FLOAT_ELEMENTS:
7365 case EXTERNAL_DOUBLE_ELEMENTS:
7366 case EXTERNAL_PIXEL_ELEMENTS:
7367 UNREACHABLE();
7368 break;
7369 }
7370
7371 // Update the length if necessary.
7372 if (IsJSArray()) {
7373 JSArray::cast(this)->set_length(Smi::FromInt(length));
7374 }
7375
7376 return new_elements;
7377}
7378
7379
7380MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
7381 int capacity,
7382 int length) {
7383 Heap* heap = GetHeap();
7384 // We should never end in here with a pixel or external array.
7385 ASSERT(!HasExternalArrayElements());
7386
John Reck59135872010-11-02 12:39:01 -07007387 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007388 { MaybeObject* maybe_obj =
7389 heap->AllocateUninitializedFixedDoubleArray(capacity);
John Reck59135872010-11-02 12:39:01 -07007390 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7391 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007392 FixedDoubleArray* elems = FixedDoubleArray::cast(obj);
Steve Block8defd9f2010-07-08 12:39:36 +01007393
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007394 { MaybeObject* maybe_obj = map()->GetFastDoubleElementsMap();
John Reck59135872010-11-02 12:39:01 -07007395 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7396 }
Steve Block8defd9f2010-07-08 12:39:36 +01007397 Map* new_map = Map::cast(obj);
7398
Leon Clarke4515c472010-02-03 11:58:03 +00007399 AssertNoAllocation no_gc;
Steve Blocka7e24c12009-10-30 11:49:00 +00007400 switch (GetElementsKind()) {
7401 case FAST_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007402 elems->Initialize(FixedArray::cast(elements()));
7403 break;
7404 }
7405 case FAST_DOUBLE_ELEMENTS: {
7406 elems->Initialize(FixedDoubleArray::cast(elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007407 break;
7408 }
7409 case DICTIONARY_ELEMENTS: {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007410 elems->Initialize(NumberDictionary::cast(elements()));
Steve Blocka7e24c12009-10-30 11:49:00 +00007411 break;
7412 }
7413 default:
7414 UNREACHABLE();
7415 break;
7416 }
Steve Block8defd9f2010-07-08 12:39:36 +01007417
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007418 ASSERT(new_map->has_fast_double_elements());
Steve Block8defd9f2010-07-08 12:39:36 +01007419 set_map(new_map);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007420 ASSERT(elems->IsFixedDoubleArray());
Steve Blocka7e24c12009-10-30 11:49:00 +00007421 set_elements(elems);
Steve Block8defd9f2010-07-08 12:39:36 +01007422
7423 if (IsJSArray()) {
7424 JSArray::cast(this)->set_length(Smi::FromInt(length));
7425 }
7426
7427 return this;
Steve Blocka7e24c12009-10-30 11:49:00 +00007428}
7429
7430
John Reck59135872010-11-02 12:39:01 -07007431MaybeObject* JSObject::SetSlowElements(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007432 // We should never end in here with a pixel or external array.
Steve Block44f0eee2011-05-26 01:26:41 +01007433 ASSERT(!HasExternalArrayElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007434
7435 uint32_t new_length = static_cast<uint32_t>(len->Number());
7436
7437 switch (GetElementsKind()) {
7438 case FAST_ELEMENTS: {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007439 case FAST_DOUBLE_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007440 // Make sure we never try to shrink dense arrays into sparse arrays.
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007441 ASSERT(static_cast<uint32_t>(
7442 FixedArrayBase::cast(elements())->length()) <= new_length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007443 MaybeObject* result = NormalizeElements();
7444 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007445
7446 // Update length for JSArrays.
7447 if (IsJSArray()) JSArray::cast(this)->set_length(len);
7448 break;
7449 }
7450 case DICTIONARY_ELEMENTS: {
7451 if (IsJSArray()) {
7452 uint32_t old_length =
Steve Block6ded16b2010-05-10 14:33:55 +01007453 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
Steve Blocka7e24c12009-10-30 11:49:00 +00007454 element_dictionary()->RemoveNumberEntries(new_length, old_length),
7455 JSArray::cast(this)->set_length(len);
7456 }
7457 break;
7458 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007459 case NON_STRICT_ARGUMENTS_ELEMENTS:
7460 UNIMPLEMENTED();
7461 break;
7462 case EXTERNAL_BYTE_ELEMENTS:
7463 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7464 case EXTERNAL_SHORT_ELEMENTS:
7465 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7466 case EXTERNAL_INT_ELEMENTS:
7467 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7468 case EXTERNAL_FLOAT_ELEMENTS:
7469 case EXTERNAL_DOUBLE_ELEMENTS:
7470 case EXTERNAL_PIXEL_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007471 UNREACHABLE();
7472 break;
7473 }
7474 return this;
7475}
7476
7477
John Reck59135872010-11-02 12:39:01 -07007478MaybeObject* JSArray::Initialize(int capacity) {
Steve Block44f0eee2011-05-26 01:26:41 +01007479 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00007480 ASSERT(capacity >= 0);
Leon Clarke4515c472010-02-03 11:58:03 +00007481 set_length(Smi::FromInt(0));
Steve Blocka7e24c12009-10-30 11:49:00 +00007482 FixedArray* new_elements;
7483 if (capacity == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01007484 new_elements = heap->empty_fixed_array();
Steve Blocka7e24c12009-10-30 11:49:00 +00007485 } else {
John Reck59135872010-11-02 12:39:01 -07007486 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01007487 { MaybeObject* maybe_obj = heap->AllocateFixedArrayWithHoles(capacity);
John Reck59135872010-11-02 12:39:01 -07007488 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7489 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007490 new_elements = FixedArray::cast(obj);
7491 }
7492 set_elements(new_elements);
7493 return this;
7494}
7495
7496
7497void JSArray::Expand(int required_size) {
7498 Handle<JSArray> self(this);
7499 Handle<FixedArray> old_backing(FixedArray::cast(elements()));
7500 int old_size = old_backing->length();
Steve Blockd0582a62009-12-15 09:54:21 +00007501 int new_size = required_size > old_size ? required_size : old_size;
Steve Block44f0eee2011-05-26 01:26:41 +01007502 Handle<FixedArray> new_backing = FACTORY->NewFixedArray(new_size);
Steve Blocka7e24c12009-10-30 11:49:00 +00007503 // Can't use this any more now because we may have had a GC!
7504 for (int i = 0; i < old_size; i++) new_backing->set(i, old_backing->get(i));
7505 self->SetContent(*new_backing);
7506}
7507
7508
Steve Block44f0eee2011-05-26 01:26:41 +01007509static Failure* ArrayLengthRangeError(Heap* heap) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007510 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007511 return heap->isolate()->Throw(
7512 *FACTORY->NewRangeError("invalid_array_length",
7513 HandleVector<Object>(NULL, 0)));
Steve Blocka7e24c12009-10-30 11:49:00 +00007514}
7515
7516
John Reck59135872010-11-02 12:39:01 -07007517MaybeObject* JSObject::SetElementsLength(Object* len) {
Steve Block3ce2e202009-11-05 08:53:23 +00007518 // We should never end in here with a pixel or external array.
Steve Block6ded16b2010-05-10 14:33:55 +01007519 ASSERT(AllowsSetElementsLength());
Steve Blocka7e24c12009-10-30 11:49:00 +00007520
John Reck59135872010-11-02 12:39:01 -07007521 MaybeObject* maybe_smi_length = len->ToSmi();
7522 Object* smi_length = Smi::FromInt(0);
7523 if (maybe_smi_length->ToObject(&smi_length) && smi_length->IsSmi()) {
Steve Block8defd9f2010-07-08 12:39:36 +01007524 const int value = Smi::cast(smi_length)->value();
Ben Murdoch8b112d22011-06-08 16:22:53 +01007525 if (value < 0) return ArrayLengthRangeError(GetHeap());
Ben Murdoch589d6972011-11-30 16:04:58 +00007526 ElementsKind elements_kind = GetElementsKind();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007527 switch (elements_kind) {
7528 case FAST_ELEMENTS:
7529 case FAST_DOUBLE_ELEMENTS: {
7530 int old_capacity = FixedArrayBase::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00007531 if (value <= old_capacity) {
7532 if (IsJSArray()) {
John Reck59135872010-11-02 12:39:01 -07007533 Object* obj;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007534 if (elements_kind == FAST_ELEMENTS) {
7535 MaybeObject* maybe_obj = EnsureWritableFastElements();
John Reck59135872010-11-02 12:39:01 -07007536 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7537 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007538 if (2 * value <= old_capacity) {
7539 // If more than half the elements won't be used, trim the array.
7540 if (value == 0) {
7541 initialize_elements();
7542 } else {
7543 Address filler_start;
7544 int filler_size;
7545 if (GetElementsKind() == FAST_ELEMENTS) {
7546 FixedArray* fast_elements = FixedArray::cast(elements());
7547 fast_elements->set_length(value);
7548 filler_start = fast_elements->address() +
7549 FixedArray::OffsetOfElementAt(value);
7550 filler_size = (old_capacity - value) * kPointerSize;
7551 } else {
7552 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7553 FixedDoubleArray* fast_double_elements =
7554 FixedDoubleArray::cast(elements());
7555 fast_double_elements->set_length(value);
7556 filler_start = fast_double_elements->address() +
7557 FixedDoubleArray::OffsetOfElementAt(value);
7558 filler_size = (old_capacity - value) * kDoubleSize;
7559 }
7560 GetHeap()->CreateFillerObjectAt(filler_start, filler_size);
7561 }
7562 } else {
7563 // Otherwise, fill the unused tail with holes.
7564 int old_length = FastD2I(JSArray::cast(this)->length()->Number());
7565 if (GetElementsKind() == FAST_ELEMENTS) {
7566 FixedArray* fast_elements = FixedArray::cast(elements());
7567 for (int i = value; i < old_length; i++) {
7568 fast_elements->set_the_hole(i);
7569 }
7570 } else {
7571 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7572 FixedDoubleArray* fast_double_elements =
7573 FixedDoubleArray::cast(elements());
7574 for (int i = value; i < old_length; i++) {
7575 fast_double_elements->set_the_hole(i);
7576 }
7577 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007578 }
Leon Clarke4515c472010-02-03 11:58:03 +00007579 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007580 }
7581 return this;
7582 }
7583 int min = NewElementsCapacity(old_capacity);
7584 int new_capacity = value > min ? value : min;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007585 if (!ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007586 MaybeObject* result;
7587 if (GetElementsKind() == FAST_ELEMENTS) {
7588 result = SetFastElementsCapacityAndLength(new_capacity, value);
7589 } else {
7590 ASSERT(GetElementsKind() == FAST_DOUBLE_ELEMENTS);
7591 result = SetFastDoubleElementsCapacityAndLength(new_capacity,
7592 value);
John Reck59135872010-11-02 12:39:01 -07007593 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007594 if (result->IsFailure()) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007595 return this;
7596 }
7597 break;
7598 }
7599 case DICTIONARY_ELEMENTS: {
7600 if (IsJSArray()) {
7601 if (value == 0) {
7602 // If the length of a slow array is reset to zero, we clear
7603 // the array and flush backing storage. This has the added
7604 // benefit that the array returns to fast mode.
John Reck59135872010-11-02 12:39:01 -07007605 Object* obj;
7606 { MaybeObject* maybe_obj = ResetElements();
7607 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7608 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007609 } else {
7610 // Remove deleted elements.
7611 uint32_t old_length =
7612 static_cast<uint32_t>(JSArray::cast(this)->length()->Number());
7613 element_dictionary()->RemoveNumberEntries(value, old_length);
7614 }
Leon Clarke4515c472010-02-03 11:58:03 +00007615 JSArray::cast(this)->set_length(Smi::cast(smi_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00007616 }
7617 return this;
7618 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007619 case NON_STRICT_ARGUMENTS_ELEMENTS:
7620 case EXTERNAL_BYTE_ELEMENTS:
7621 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7622 case EXTERNAL_SHORT_ELEMENTS:
7623 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7624 case EXTERNAL_INT_ELEMENTS:
7625 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
7626 case EXTERNAL_FLOAT_ELEMENTS:
7627 case EXTERNAL_DOUBLE_ELEMENTS:
7628 case EXTERNAL_PIXEL_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007629 UNREACHABLE();
7630 break;
7631 }
7632 }
7633
7634 // General slow case.
7635 if (len->IsNumber()) {
7636 uint32_t length;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01007637 if (len->ToArrayIndex(&length)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007638 return SetSlowElements(len);
7639 } else {
Ben Murdoch8b112d22011-06-08 16:22:53 +01007640 return ArrayLengthRangeError(GetHeap());
Steve Blocka7e24c12009-10-30 11:49:00 +00007641 }
7642 }
7643
7644 // len is not a number so make the array size one and
7645 // set only element to len.
John Reck59135872010-11-02 12:39:01 -07007646 Object* obj;
Ben Murdoch8b112d22011-06-08 16:22:53 +01007647 { MaybeObject* maybe_obj = GetHeap()->AllocateFixedArray(1);
John Reck59135872010-11-02 12:39:01 -07007648 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7649 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007650 FixedArray::cast(obj)->set(0, len);
Leon Clarke4515c472010-02-03 11:58:03 +00007651 if (IsJSArray()) JSArray::cast(this)->set_length(Smi::FromInt(1));
Steve Blocka7e24c12009-10-30 11:49:00 +00007652 set_elements(FixedArray::cast(obj));
7653 return this;
7654}
7655
7656
Steve Block053d10c2011-06-13 19:13:29 +01007657Object* Map::GetPrototypeTransition(Object* prototype) {
7658 FixedArray* cache = prototype_transitions();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007659 int number_of_transitions = NumberOfProtoTransitions();
7660 const int proto_offset =
7661 kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
7662 const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
7663 const int step = kProtoTransitionElementsPerEntry;
7664 for (int i = 0; i < number_of_transitions; i++) {
7665 if (cache->get(proto_offset + i * step) == prototype) {
7666 Object* map = cache->get(map_offset + i * step);
7667 ASSERT(map->IsMap());
7668 return map;
7669 }
Steve Block053d10c2011-06-13 19:13:29 +01007670 }
7671 return NULL;
7672}
7673
7674
7675MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007676 ASSERT(map->IsMap());
7677 ASSERT(HeapObject::cast(prototype)->map()->IsMap());
Steve Block053d10c2011-06-13 19:13:29 +01007678 // Don't cache prototype transition if this map is shared.
7679 if (is_shared() || !FLAG_cache_prototype_transitions) return this;
7680
7681 FixedArray* cache = prototype_transitions();
7682
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007683 const int step = kProtoTransitionElementsPerEntry;
7684 const int header = kProtoTransitionHeaderSize;
Steve Block053d10c2011-06-13 19:13:29 +01007685
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007686 int capacity = (cache->length() - header) / step;
Steve Block053d10c2011-06-13 19:13:29 +01007687
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007688 int transitions = NumberOfProtoTransitions() + 1;
7689
7690 if (transitions > capacity) {
Steve Block053d10c2011-06-13 19:13:29 +01007691 if (capacity > kMaxCachedPrototypeTransitions) return this;
7692
7693 FixedArray* new_cache;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007694 // Grow array by factor 2 over and above what we need.
7695 { MaybeObject* maybe_cache =
7696 heap()->AllocateFixedArray(transitions * 2 * step + header);
Steve Block053d10c2011-06-13 19:13:29 +01007697 if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
7698 }
7699
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007700 for (int i = 0; i < capacity * step; i++) {
7701 new_cache->set(i + header, cache->get(i + header));
7702 }
Steve Block053d10c2011-06-13 19:13:29 +01007703 cache = new_cache;
7704 set_prototype_transitions(cache);
7705 }
7706
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007707 int last = transitions - 1;
7708
7709 cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
7710 cache->set(header + last * step + kProtoTransitionMapOffset, map);
7711 SetNumberOfProtoTransitions(transitions);
Steve Block053d10c2011-06-13 19:13:29 +01007712
7713 return cache;
7714}
7715
7716
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007717MaybeObject* JSReceiver::SetPrototype(Object* value,
7718 bool skip_hidden_prototypes) {
7719#ifdef DEBUG
7720 int size = Size();
7721#endif
7722
Steve Block44f0eee2011-05-26 01:26:41 +01007723 Heap* heap = GetHeap();
Andrei Popescu402d9372010-02-26 13:31:12 +00007724 // Silently ignore the change if value is not a JSObject or null.
7725 // SpiderMonkey behaves this way.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007726 if (!value->IsJSReceiver() && !value->IsNull()) return value;
Andrei Popescu402d9372010-02-26 13:31:12 +00007727
Ben Murdoch8b112d22011-06-08 16:22:53 +01007728 // From 8.6.2 Object Internal Methods
7729 // ...
7730 // In addition, if [[Extensible]] is false the value of the [[Class]] and
7731 // [[Prototype]] internal properties of the object may not be modified.
7732 // ...
7733 // Implementation specific extensions that modify [[Class]], [[Prototype]]
7734 // or [[Extensible]] must not violate the invariants defined in the preceding
7735 // paragraph.
7736 if (!this->map()->is_extensible()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007737 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01007738 Handle<Object> handle(this, heap->isolate());
7739 return heap->isolate()->Throw(
7740 *FACTORY->NewTypeError("non_extensible_proto",
7741 HandleVector<Object>(&handle, 1)));
7742 }
7743
Andrei Popescu402d9372010-02-26 13:31:12 +00007744 // Before we can set the prototype we need to be sure
7745 // prototype cycles are prevented.
7746 // It is sufficient to validate that the receiver is not in the new prototype
7747 // chain.
Steve Block44f0eee2011-05-26 01:26:41 +01007748 for (Object* pt = value; pt != heap->null_value(); pt = pt->GetPrototype()) {
Andrei Popescu402d9372010-02-26 13:31:12 +00007749 if (JSObject::cast(pt) == this) {
7750 // Cycle detected.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007751 HandleScope scope(heap->isolate());
Steve Block44f0eee2011-05-26 01:26:41 +01007752 return heap->isolate()->Throw(
7753 *FACTORY->NewError("cyclic_proto", HandleVector<Object>(NULL, 0)));
Andrei Popescu402d9372010-02-26 13:31:12 +00007754 }
7755 }
7756
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007757 JSReceiver* real_receiver = this;
Andrei Popescu402d9372010-02-26 13:31:12 +00007758
7759 if (skip_hidden_prototypes) {
7760 // Find the first object in the chain whose prototype object is not
7761 // hidden and set the new prototype on that object.
7762 Object* current_proto = real_receiver->GetPrototype();
7763 while (current_proto->IsJSObject() &&
7764 JSObject::cast(current_proto)->map()->is_hidden_prototype()) {
7765 real_receiver = JSObject::cast(current_proto);
7766 current_proto = current_proto->GetPrototype();
7767 }
7768 }
7769
7770 // Set the new prototype of the object.
Steve Block053d10c2011-06-13 19:13:29 +01007771 Map* map = real_receiver->map();
7772
7773 // Nothing to do if prototype is already set.
7774 if (map->prototype() == value) return value;
7775
7776 Object* new_map = map->GetPrototypeTransition(value);
7777 if (new_map == NULL) {
7778 { MaybeObject* maybe_new_map = map->CopyDropTransitions();
7779 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
7780 }
7781
7782 { MaybeObject* maybe_new_cache =
7783 map->PutPrototypeTransition(value, Map::cast(new_map));
7784 if (maybe_new_cache->IsFailure()) return maybe_new_cache;
7785 }
7786
7787 Map::cast(new_map)->set_prototype(value);
John Reck59135872010-11-02 12:39:01 -07007788 }
Steve Block053d10c2011-06-13 19:13:29 +01007789 ASSERT(Map::cast(new_map)->prototype() == value);
Andrei Popescu402d9372010-02-26 13:31:12 +00007790 real_receiver->set_map(Map::cast(new_map));
7791
Steve Block44f0eee2011-05-26 01:26:41 +01007792 heap->ClearInstanceofCache();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007793 ASSERT(size == Size());
Andrei Popescu402d9372010-02-26 13:31:12 +00007794 return value;
7795}
7796
7797
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007798bool JSObject::HasElementPostInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007799 switch (GetElementsKind()) {
7800 case FAST_ELEMENTS: {
7801 uint32_t length = IsJSArray() ?
7802 static_cast<uint32_t>
7803 (Smi::cast(JSArray::cast(this)->length())->value()) :
7804 static_cast<uint32_t>(FixedArray::cast(elements())->length());
7805 if ((index < length) &&
7806 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7807 return true;
7808 }
7809 break;
7810 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007811 case FAST_DOUBLE_ELEMENTS: {
7812 uint32_t length = IsJSArray() ?
7813 static_cast<uint32_t>
7814 (Smi::cast(JSArray::cast(this)->length())->value()) :
7815 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7816 if ((index < length) &&
7817 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7818 return true;
7819 }
7820 break;
7821 }
Steve Block44f0eee2011-05-26 01:26:41 +01007822 case EXTERNAL_PIXEL_ELEMENTS: {
7823 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00007824 if (index < static_cast<uint32_t>(pixels->length())) {
7825 return true;
7826 }
7827 break;
7828 }
Steve Block3ce2e202009-11-05 08:53:23 +00007829 case EXTERNAL_BYTE_ELEMENTS:
7830 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7831 case EXTERNAL_SHORT_ELEMENTS:
7832 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7833 case EXTERNAL_INT_ELEMENTS:
7834 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007835 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007836 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007837 ExternalArray* array = ExternalArray::cast(elements());
7838 if (index < static_cast<uint32_t>(array->length())) {
7839 return true;
7840 }
7841 break;
7842 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007843 case DICTIONARY_ELEMENTS: {
7844 if (element_dictionary()->FindEntry(index)
7845 != NumberDictionary::kNotFound) {
7846 return true;
7847 }
7848 break;
7849 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007850 case NON_STRICT_ARGUMENTS_ELEMENTS:
Steve Blocka7e24c12009-10-30 11:49:00 +00007851 UNREACHABLE();
7852 break;
7853 }
7854
7855 // Handle [] on String objects.
7856 if (this->IsStringObjectWithCharacterAt(index)) return true;
7857
7858 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01007859 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00007860 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
7861}
7862
7863
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007864bool JSObject::HasElementWithInterceptor(JSReceiver* receiver, uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01007865 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00007866 // Make sure that the top context does not change when doing
7867 // callbacks or interceptor calls.
7868 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01007869 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00007870 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007871 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00007872 Handle<JSObject> holder_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01007873 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00007874 v8::AccessorInfo info(args.end());
7875 if (!interceptor->query()->IsUndefined()) {
7876 v8::IndexedPropertyQuery query =
7877 v8::ToCData<v8::IndexedPropertyQuery>(interceptor->query());
Steve Block44f0eee2011-05-26 01:26:41 +01007878 LOG(isolate,
7879 ApiIndexedPropertyAccess("interceptor-indexed-has", this, index));
Iain Merrick75681382010-08-19 15:07:18 +01007880 v8::Handle<v8::Integer> result;
Steve Blocka7e24c12009-10-30 11:49:00 +00007881 {
7882 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007883 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007884 result = query(index, info);
7885 }
Iain Merrick75681382010-08-19 15:07:18 +01007886 if (!result.IsEmpty()) {
7887 ASSERT(result->IsInt32());
7888 return true; // absence of property is signaled by empty handle.
7889 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007890 } else if (!interceptor->getter()->IsUndefined()) {
7891 v8::IndexedPropertyGetter getter =
7892 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01007893 LOG(isolate,
7894 ApiIndexedPropertyAccess("interceptor-indexed-has-get", this, index));
Steve Blocka7e24c12009-10-30 11:49:00 +00007895 v8::Handle<v8::Value> result;
7896 {
7897 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01007898 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00007899 result = getter(index, info);
7900 }
7901 if (!result.IsEmpty()) return true;
7902 }
7903 return holder_handle->HasElementPostInterceptor(*receiver_handle, index);
7904}
7905
7906
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007907JSObject::LocalElementType JSObject::HasLocalElement(uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00007908 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01007909 if (IsAccessCheckNeeded()) {
7910 Heap* heap = GetHeap();
7911 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
7912 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
7913 return UNDEFINED_ELEMENT;
7914 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007915 }
7916
Steve Block1e0659c2011-05-24 12:43:12 +01007917 if (IsJSGlobalProxy()) {
7918 Object* proto = GetPrototype();
7919 if (proto->IsNull()) return UNDEFINED_ELEMENT;
7920 ASSERT(proto->IsJSGlobalObject());
7921 return JSObject::cast(proto)->HasLocalElement(index);
7922 }
7923
Steve Blocka7e24c12009-10-30 11:49:00 +00007924 // Check for lookup interceptor
7925 if (HasIndexedInterceptor()) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007926 return HasElementWithInterceptor(this, index) ? INTERCEPTED_ELEMENT
7927 : UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00007928 }
7929
7930 // Handle [] on String objects.
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007931 if (this->IsStringObjectWithCharacterAt(index)) {
7932 return STRING_CHARACTER_ELEMENT;
7933 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007934
7935 switch (GetElementsKind()) {
7936 case FAST_ELEMENTS: {
7937 uint32_t length = IsJSArray() ?
7938 static_cast<uint32_t>
7939 (Smi::cast(JSArray::cast(this)->length())->value()) :
7940 static_cast<uint32_t>(FixedArray::cast(elements())->length());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007941 if ((index < length) &&
7942 !FixedArray::cast(elements())->get(index)->IsTheHole()) {
7943 return FAST_ELEMENT;
7944 }
7945 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007946 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00007947 case FAST_DOUBLE_ELEMENTS: {
7948 uint32_t length = IsJSArray() ?
7949 static_cast<uint32_t>
7950 (Smi::cast(JSArray::cast(this)->length())->value()) :
7951 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
7952 if ((index < length) &&
7953 !FixedDoubleArray::cast(elements())->is_the_hole(index)) {
7954 return FAST_ELEMENT;
7955 }
7956 break;
7957 }
Steve Block44f0eee2011-05-26 01:26:41 +01007958 case EXTERNAL_PIXEL_ELEMENTS: {
7959 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007960 if (index < static_cast<uint32_t>(pixels->length())) return FAST_ELEMENT;
7961 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007962 }
Steve Block3ce2e202009-11-05 08:53:23 +00007963 case EXTERNAL_BYTE_ELEMENTS:
7964 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
7965 case EXTERNAL_SHORT_ELEMENTS:
7966 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
7967 case EXTERNAL_INT_ELEMENTS:
7968 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00007969 case EXTERNAL_FLOAT_ELEMENTS:
7970 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00007971 ExternalArray* array = ExternalArray::cast(elements());
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007972 if (index < static_cast<uint32_t>(array->length())) return FAST_ELEMENT;
7973 break;
Steve Block3ce2e202009-11-05 08:53:23 +00007974 }
Steve Blocka7e24c12009-10-30 11:49:00 +00007975 case DICTIONARY_ELEMENTS: {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007976 if (element_dictionary()->FindEntry(index) !=
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007977 NumberDictionary::kNotFound) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +01007978 return DICTIONARY_ELEMENT;
7979 }
7980 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00007981 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007982 case NON_STRICT_ARGUMENTS_ELEMENTS: {
7983 // Aliased parameters and non-aliased elements in a fast backing store
7984 // behave as FAST_ELEMENT. Non-aliased elements in a dictionary
7985 // backing store behave as DICTIONARY_ELEMENT.
7986 FixedArray* parameter_map = FixedArray::cast(elements());
7987 uint32_t length = parameter_map->length();
7988 Object* probe =
7989 index < (length - 2) ? parameter_map->get(index + 2) : NULL;
7990 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
7991 // If not aliased, check the arguments.
7992 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
7993 if (arguments->IsDictionary()) {
7994 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
7995 if (dictionary->FindEntry(index) != NumberDictionary::kNotFound) {
7996 return DICTIONARY_ELEMENT;
7997 }
7998 } else {
7999 length = arguments->length();
8000 probe = (index < length) ? arguments->get(index) : NULL;
8001 if (probe != NULL && !probe->IsTheHole()) return FAST_ELEMENT;
8002 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008003 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008004 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008005 }
Kristian Monsen0d5e1162010-09-30 15:31:59 +01008006
8007 return UNDEFINED_ELEMENT;
Steve Blocka7e24c12009-10-30 11:49:00 +00008008}
8009
8010
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008011bool JSObject::HasElementInElements(FixedArray* elements,
8012 ElementsKind kind,
8013 uint32_t index) {
8014 ASSERT(kind == FAST_ELEMENTS || kind == DICTIONARY_ELEMENTS);
8015 if (kind == FAST_ELEMENTS) {
8016 int length = IsJSArray()
8017 ? Smi::cast(JSArray::cast(this)->length())->value()
8018 : elements->length();
8019 if (index < static_cast<uint32_t>(length) &&
8020 !elements->get(index)->IsTheHole()) {
8021 return true;
8022 }
8023 } else {
8024 if (NumberDictionary::cast(elements)->FindEntry(index) !=
8025 NumberDictionary::kNotFound) {
8026 return true;
8027 }
8028 }
8029 return false;
8030}
8031
8032
8033bool JSObject::HasElementWithReceiver(JSReceiver* receiver, uint32_t index) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008034 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008035 if (IsAccessCheckNeeded()) {
8036 Heap* heap = GetHeap();
8037 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
8038 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
8039 return false;
8040 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008041 }
8042
8043 // Check for lookup interceptor
8044 if (HasIndexedInterceptor()) {
8045 return HasElementWithInterceptor(receiver, index);
8046 }
8047
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008048 ElementsKind kind = GetElementsKind();
8049 switch (kind) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008050 case FAST_ELEMENTS: {
8051 uint32_t length = IsJSArray() ?
8052 static_cast<uint32_t>
8053 (Smi::cast(JSArray::cast(this)->length())->value()) :
8054 static_cast<uint32_t>(FixedArray::cast(elements())->length());
8055 if ((index < length) &&
8056 !FixedArray::cast(elements())->get(index)->IsTheHole()) return true;
8057 break;
8058 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008059 case FAST_DOUBLE_ELEMENTS: {
8060 uint32_t length = IsJSArray() ?
8061 static_cast<uint32_t>
8062 (Smi::cast(JSArray::cast(this)->length())->value()) :
8063 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
8064 if ((index < length) &&
8065 !FixedDoubleArray::cast(elements())->is_the_hole(index)) return true;
8066 break;
8067 }
Steve Block44f0eee2011-05-26 01:26:41 +01008068 case EXTERNAL_PIXEL_ELEMENTS: {
8069 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008070 if (index < static_cast<uint32_t>(pixels->length())) {
8071 return true;
8072 }
8073 break;
8074 }
Steve Block3ce2e202009-11-05 08:53:23 +00008075 case EXTERNAL_BYTE_ELEMENTS:
8076 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8077 case EXTERNAL_SHORT_ELEMENTS:
8078 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8079 case EXTERNAL_INT_ELEMENTS:
8080 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008081 case EXTERNAL_FLOAT_ELEMENTS:
8082 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00008083 ExternalArray* array = ExternalArray::cast(elements());
8084 if (index < static_cast<uint32_t>(array->length())) {
8085 return true;
8086 }
8087 break;
8088 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008089 case DICTIONARY_ELEMENTS: {
8090 if (element_dictionary()->FindEntry(index)
8091 != NumberDictionary::kNotFound) {
8092 return true;
8093 }
8094 break;
8095 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008096 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8097 FixedArray* parameter_map = FixedArray::cast(elements());
8098 uint32_t length = parameter_map->length();
8099 Object* probe =
8100 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8101 if (probe != NULL && !probe->IsTheHole()) return true;
8102
8103 // Not a mapped parameter, check the arguments.
8104 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8105 kind = arguments->IsDictionary() ? DICTIONARY_ELEMENTS : FAST_ELEMENTS;
8106 if (HasElementInElements(arguments, kind, index)) return true;
Steve Blocka7e24c12009-10-30 11:49:00 +00008107 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008108 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008109 }
8110
8111 // Handle [] on String objects.
8112 if (this->IsStringObjectWithCharacterAt(index)) return true;
8113
8114 Object* pt = GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008115 if (pt->IsNull()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008116 return JSObject::cast(pt)->HasElementWithReceiver(receiver, index);
8117}
8118
8119
John Reck59135872010-11-02 12:39:01 -07008120MaybeObject* JSObject::SetElementWithInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008121 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008122 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008123 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008124 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008125 // Make sure that the top context does not change when doing
8126 // callbacks or interceptor calls.
8127 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008128 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008129 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor());
8130 Handle<JSObject> this_handle(this);
Steve Block44f0eee2011-05-26 01:26:41 +01008131 Handle<Object> value_handle(value, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008132 if (!interceptor->setter()->IsUndefined()) {
8133 v8::IndexedPropertySetter setter =
8134 v8::ToCData<v8::IndexedPropertySetter>(interceptor->setter());
Steve Block44f0eee2011-05-26 01:26:41 +01008135 LOG(isolate,
8136 ApiIndexedPropertyAccess("interceptor-indexed-set", this, index));
8137 CustomArguments args(isolate, interceptor->data(), this, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008138 v8::AccessorInfo info(args.end());
8139 v8::Handle<v8::Value> result;
8140 {
8141 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008142 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008143 result = setter(index, v8::Utils::ToLocal(value_handle), info);
8144 }
Steve Block44f0eee2011-05-26 01:26:41 +01008145 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008146 if (!result.IsEmpty()) return *value_handle;
8147 }
John Reck59135872010-11-02 12:39:01 -07008148 MaybeObject* raw_result =
Steve Block9fac8402011-05-12 15:51:54 +01008149 this_handle->SetElementWithoutInterceptor(index,
8150 *value_handle,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008151 strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008152 check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008153 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008154 return raw_result;
8155}
8156
8157
John Reck59135872010-11-02 12:39:01 -07008158MaybeObject* JSObject::GetElementWithCallback(Object* receiver,
8159 Object* structure,
8160 uint32_t index,
8161 Object* holder) {
Steve Block44f0eee2011-05-26 01:26:41 +01008162 Isolate* isolate = GetIsolate();
Ben Murdoch257744e2011-11-30 15:57:28 +00008163 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008164
8165 // api style callbacks.
8166 if (structure->IsAccessorInfo()) {
Ben Murdoch257744e2011-11-30 15:57:28 +00008167 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008168 Object* fun_obj = data->getter();
8169 v8::AccessorGetter call_fun = v8::ToCData<v8::AccessorGetter>(fun_obj);
Steve Block44f0eee2011-05-26 01:26:41 +01008170 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008171 Handle<JSObject> self(JSObject::cast(receiver));
8172 Handle<JSObject> holder_handle(JSObject::cast(holder));
Steve Block44f0eee2011-05-26 01:26:41 +01008173 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008174 Handle<String> key = isolate->factory()->NumberToString(number);
Steve Block44f0eee2011-05-26 01:26:41 +01008175 LOG(isolate, ApiNamedPropertyAccess("load", *self, *key));
8176 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008177 v8::AccessorInfo info(args.end());
8178 v8::Handle<v8::Value> result;
8179 {
8180 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008181 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008182 result = call_fun(v8::Utils::ToLocal(key), info);
8183 }
Steve Block44f0eee2011-05-26 01:26:41 +01008184 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
8185 if (result.IsEmpty()) return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008186 return *v8::Utils::OpenHandle(*result);
8187 }
8188
8189 // __defineGetter__ callback
8190 if (structure->IsFixedArray()) {
8191 Object* getter = FixedArray::cast(structure)->get(kGetterIndex);
8192 if (getter->IsJSFunction()) {
8193 return Object::GetPropertyWithDefinedGetter(receiver,
8194 JSFunction::cast(getter));
8195 }
8196 // Getter is not a function.
Steve Block44f0eee2011-05-26 01:26:41 +01008197 return isolate->heap()->undefined_value();
Leon Clarkef7060e22010-06-03 12:02:55 +01008198 }
8199
8200 UNREACHABLE();
8201 return NULL;
8202}
8203
8204
John Reck59135872010-11-02 12:39:01 -07008205MaybeObject* JSObject::SetElementWithCallback(Object* structure,
8206 uint32_t index,
8207 Object* value,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008208 JSObject* holder,
8209 StrictModeFlag strict_mode) {
Steve Block44f0eee2011-05-26 01:26:41 +01008210 Isolate* isolate = GetIsolate();
8211 HandleScope scope(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008212
8213 // We should never get here to initialize a const with the hole
8214 // value since a const declaration would conflict with the setter.
8215 ASSERT(!value->IsTheHole());
Steve Block44f0eee2011-05-26 01:26:41 +01008216 Handle<Object> value_handle(value, isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008217
8218 // To accommodate both the old and the new api we switch on the
Ben Murdoch257744e2011-11-30 15:57:28 +00008219 // data structure used to store the callbacks. Eventually foreign
Leon Clarkef7060e22010-06-03 12:02:55 +01008220 // callbacks should be phased out.
Ben Murdoch257744e2011-11-30 15:57:28 +00008221 ASSERT(!structure->IsForeign());
Leon Clarkef7060e22010-06-03 12:02:55 +01008222
8223 if (structure->IsAccessorInfo()) {
8224 // api style callbacks
Ben Murdoch257744e2011-11-30 15:57:28 +00008225 Handle<JSObject> self(this);
8226 Handle<JSObject> holder_handle(JSObject::cast(holder));
8227 Handle<AccessorInfo> data(AccessorInfo::cast(structure));
Leon Clarkef7060e22010-06-03 12:02:55 +01008228 Object* call_obj = data->setter();
8229 v8::AccessorSetter call_fun = v8::ToCData<v8::AccessorSetter>(call_obj);
8230 if (call_fun == NULL) return value;
Steve Block44f0eee2011-05-26 01:26:41 +01008231 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8232 Handle<String> key(isolate->factory()->NumberToString(number));
Ben Murdoch257744e2011-11-30 15:57:28 +00008233 LOG(isolate, ApiNamedPropertyAccess("store", *self, *key));
8234 CustomArguments args(isolate, data->data(), *self, *holder_handle);
Leon Clarkef7060e22010-06-03 12:02:55 +01008235 v8::AccessorInfo info(args.end());
8236 {
8237 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008238 VMState state(isolate, EXTERNAL);
Leon Clarkef7060e22010-06-03 12:02:55 +01008239 call_fun(v8::Utils::ToLocal(key),
8240 v8::Utils::ToLocal(value_handle),
8241 info);
8242 }
Steve Block44f0eee2011-05-26 01:26:41 +01008243 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Leon Clarkef7060e22010-06-03 12:02:55 +01008244 return *value_handle;
8245 }
8246
8247 if (structure->IsFixedArray()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008248 Handle<Object> setter(FixedArray::cast(structure)->get(kSetterIndex));
Leon Clarkef7060e22010-06-03 12:02:55 +01008249 if (setter->IsJSFunction()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008250 return SetPropertyWithDefinedSetter(JSFunction::cast(*setter), value);
Leon Clarkef7060e22010-06-03 12:02:55 +01008251 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008252 if (strict_mode == kNonStrictMode) {
8253 return value;
8254 }
Steve Block44f0eee2011-05-26 01:26:41 +01008255 Handle<Object> holder_handle(holder, isolate);
8256 Handle<Object> key(isolate->factory()->NewNumberFromUint(index));
Leon Clarkef7060e22010-06-03 12:02:55 +01008257 Handle<Object> args[2] = { key, holder_handle };
Steve Block44f0eee2011-05-26 01:26:41 +01008258 return isolate->Throw(
8259 *isolate->factory()->NewTypeError("no_setter_in_callback",
8260 HandleVector(args, 2)));
Leon Clarkef7060e22010-06-03 12:02:55 +01008261 }
8262 }
8263
8264 UNREACHABLE();
8265 return NULL;
8266}
8267
8268
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008269bool JSObject::HasFastArgumentsElements() {
8270 Heap* heap = GetHeap();
8271 if (!elements()->IsFixedArray()) return false;
8272 FixedArray* elements = FixedArray::cast(this->elements());
8273 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8274 return false;
8275 }
8276 FixedArray* arguments = FixedArray::cast(elements->get(1));
8277 return !arguments->IsDictionary();
8278}
8279
8280
8281bool JSObject::HasDictionaryArgumentsElements() {
8282 Heap* heap = GetHeap();
8283 if (!elements()->IsFixedArray()) return false;
8284 FixedArray* elements = FixedArray::cast(this->elements());
8285 if (elements->map() != heap->non_strict_arguments_elements_map()) {
8286 return false;
8287 }
8288 FixedArray* arguments = FixedArray::cast(elements->get(1));
8289 return arguments->IsDictionary();
8290}
8291
8292
Steve Blocka7e24c12009-10-30 11:49:00 +00008293// Adding n elements in fast case is O(n*n).
8294// Note: revisit design to have dual undefined values to capture absent
8295// elements.
Steve Block9fac8402011-05-12 15:51:54 +01008296MaybeObject* JSObject::SetFastElement(uint32_t index,
8297 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008298 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008299 bool check_prototype) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008300 ASSERT(HasFastElements() || HasFastArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008301
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008302 FixedArray* backing_store = FixedArray::cast(elements());
8303 if (backing_store->map() == GetHeap()->non_strict_arguments_elements_map()) {
8304 backing_store = FixedArray::cast(backing_store->get(1));
8305 } else {
8306 Object* writable;
8307 MaybeObject* maybe = EnsureWritableFastElements();
8308 if (!maybe->ToObject(&writable)) return maybe;
8309 backing_store = FixedArray::cast(writable);
John Reck59135872010-11-02 12:39:01 -07008310 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008311 uint32_t length = static_cast<uint32_t>(backing_store->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00008312
Steve Block9fac8402011-05-12 15:51:54 +01008313 if (check_prototype &&
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008314 (index >= length || backing_store->get(index)->IsTheHole())) {
Steve Block1e0659c2011-05-24 12:43:12 +01008315 bool found;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008316 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8317 value,
8318 &found,
8319 strict_mode);
Steve Block1e0659c2011-05-24 12:43:12 +01008320 if (found) return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00008321 }
8322
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008323 // Check whether there is extra space in fixed array.
8324 if (index < length) {
8325 backing_store->set(index, value);
8326 if (IsJSArray()) {
8327 // Update the length of the array if needed.
8328 uint32_t array_length = 0;
8329 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
8330 if (index >= array_length) {
8331 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
8332 }
8333 }
8334 return value;
8335 }
Steve Block9fac8402011-05-12 15:51:54 +01008336
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008337 // Allow gap in fast case.
8338 if ((index - length) < kMaxGap) {
8339 // Try allocating extra space.
8340 int new_capacity = NewElementsCapacity(index + 1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008341 if (!ShouldConvertToSlowElements(new_capacity)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008342 ASSERT(static_cast<uint32_t>(new_capacity) > index);
8343 Object* new_elements;
8344 MaybeObject* maybe =
8345 SetFastElementsCapacityAndLength(new_capacity, index + 1);
8346 if (!maybe->ToObject(&new_elements)) return maybe;
8347 FixedArray::cast(new_elements)->set(index, value);
8348 return value;
8349 }
8350 }
8351
8352 // Otherwise default to slow case.
8353 MaybeObject* result = NormalizeElements();
8354 if (result->IsFailure()) return result;
8355 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8356}
8357
8358
8359MaybeObject* JSObject::SetDictionaryElement(uint32_t index,
8360 Object* value,
8361 StrictModeFlag strict_mode,
8362 bool check_prototype) {
8363 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
8364 Isolate* isolate = GetIsolate();
8365 Heap* heap = isolate->heap();
8366
8367 // Insert element in the dictionary.
8368 FixedArray* elements = FixedArray::cast(this->elements());
8369 bool is_arguments =
8370 (elements->map() == heap->non_strict_arguments_elements_map());
8371 NumberDictionary* dictionary = NULL;
8372 if (is_arguments) {
8373 dictionary = NumberDictionary::cast(elements->get(1));
8374 } else {
8375 dictionary = NumberDictionary::cast(elements);
8376 }
8377
8378 int entry = dictionary->FindEntry(index);
8379 if (entry != NumberDictionary::kNotFound) {
8380 Object* element = dictionary->ValueAt(entry);
8381 PropertyDetails details = dictionary->DetailsAt(entry);
8382 if (details.type() == CALLBACKS) {
8383 return SetElementWithCallback(element, index, value, this, strict_mode);
8384 } else {
8385 dictionary->UpdateMaxNumberKey(index);
8386 // If put fails in strict mode, throw an exception.
8387 if (!dictionary->ValueAtPut(entry, value) && strict_mode == kStrictMode) {
8388 Handle<Object> holder(this);
8389 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8390 Handle<Object> args[2] = { number, holder };
8391 Handle<Object> error =
8392 isolate->factory()->NewTypeError("strict_read_only_property",
8393 HandleVector(args, 2));
8394 return isolate->Throw(*error);
8395 }
8396 }
8397 } else {
8398 // Index not already used. Look for an accessor in the prototype chain.
8399 if (check_prototype) {
8400 bool found;
8401 MaybeObject* result =
8402 SetElementWithCallbackSetterInPrototypes(
8403 index, value, &found, strict_mode);
8404 if (found) return result;
8405 }
8406 // When we set the is_extensible flag to false we always force the
8407 // element into dictionary mode (and force them to stay there).
8408 if (!map()->is_extensible()) {
8409 if (strict_mode == kNonStrictMode) {
8410 return isolate->heap()->undefined_value();
8411 } else {
8412 Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
8413 Handle<String> name = isolate->factory()->NumberToString(number);
8414 Handle<Object> args[1] = { name };
8415 Handle<Object> error =
8416 isolate->factory()->NewTypeError("object_not_extensible",
8417 HandleVector(args, 1));
8418 return isolate->Throw(*error);
8419 }
8420 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008421 FixedArrayBase* new_dictionary;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008422 MaybeObject* maybe = dictionary->AtNumberPut(index, value);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008423 if (!maybe->To<FixedArrayBase>(&new_dictionary)) return maybe;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008424 if (dictionary != NumberDictionary::cast(new_dictionary)) {
8425 if (is_arguments) {
8426 elements->set(1, new_dictionary);
8427 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008428 set_elements(new_dictionary);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008429 }
8430 dictionary = NumberDictionary::cast(new_dictionary);
8431 }
8432 }
8433
8434 // Update the array length if this JSObject is an array.
8435 if (IsJSArray()) {
8436 MaybeObject* result =
8437 JSArray::cast(this)->JSArrayUpdateLengthFromIndex(index, value);
8438 if (result->IsFailure()) return result;
8439 }
8440
8441 // Attempt to put this object back in fast case.
8442 if (ShouldConvertToFastElements()) {
8443 uint32_t new_length = 0;
8444 if (IsJSArray()) {
8445 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&new_length));
8446 } else {
8447 new_length = dictionary->max_number_key() + 1;
8448 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008449 MaybeObject* result = CanConvertToFastDoubleElements()
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008450 ? SetFastDoubleElementsCapacityAndLength(new_length, new_length)
8451 : SetFastElementsCapacityAndLength(new_length, new_length);
8452 if (result->IsFailure()) return result;
8453#ifdef DEBUG
8454 if (FLAG_trace_normalization) {
8455 PrintF("Object elements are fast case again:\n");
8456 Print();
8457 }
8458#endif
8459 }
8460 return value;
8461}
8462
8463
8464MUST_USE_RESULT MaybeObject* JSObject::SetFastDoubleElement(
8465 uint32_t index,
8466 Object* value,
8467 StrictModeFlag strict_mode,
8468 bool check_prototype) {
8469 ASSERT(HasFastDoubleElements());
8470
8471 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
8472 uint32_t elms_length = static_cast<uint32_t>(elms->length());
8473
8474 // If storing to an element that isn't in the array, pass the store request
8475 // up the prototype chain before storing in the receiver's elements.
8476 if (check_prototype &&
8477 (index >= elms_length || elms->is_the_hole(index))) {
8478 bool found;
8479 MaybeObject* result = SetElementWithCallbackSetterInPrototypes(index,
8480 value,
8481 &found,
8482 strict_mode);
8483 if (found) return result;
8484 }
8485
8486 // If the value object is not a heap number, switch to fast elements and try
8487 // again.
8488 bool value_is_smi = value->IsSmi();
8489 if (!value->IsNumber()) {
8490 Object* obj;
8491 uint32_t length = elms_length;
8492 if (IsJSArray()) {
8493 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&length));
8494 }
8495 MaybeObject* maybe_obj =
8496 SetFastElementsCapacityAndLength(elms_length, length);
8497 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8498 return SetFastElement(index, value, strict_mode, check_prototype);
8499 }
8500
8501 double double_value = value_is_smi
8502 ? static_cast<double>(Smi::cast(value)->value())
8503 : HeapNumber::cast(value)->value();
8504
8505 // Check whether there is extra space in the fixed array.
Steve Blocka7e24c12009-10-30 11:49:00 +00008506 if (index < elms_length) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008507 elms->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008508 if (IsJSArray()) {
8509 // Update the length of the array if needed.
8510 uint32_t array_length = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008511 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_length));
Steve Blocka7e24c12009-10-30 11:49:00 +00008512 if (index >= array_length) {
Leon Clarke4515c472010-02-03 11:58:03 +00008513 JSArray::cast(this)->set_length(Smi::FromInt(index + 1));
Steve Blocka7e24c12009-10-30 11:49:00 +00008514 }
8515 }
8516 return value;
8517 }
8518
8519 // Allow gap in fast case.
8520 if ((index - elms_length) < kMaxGap) {
8521 // Try allocating extra space.
8522 int new_capacity = NewElementsCapacity(index+1);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008523 if (!ShouldConvertToSlowElements(new_capacity)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008524 ASSERT(static_cast<uint32_t>(new_capacity) > index);
John Reck59135872010-11-02 12:39:01 -07008525 Object* obj;
8526 { MaybeObject* maybe_obj =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008527 SetFastDoubleElementsCapacityAndLength(new_capacity,
8528 index + 1);
John Reck59135872010-11-02 12:39:01 -07008529 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8530 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008531 FixedDoubleArray::cast(elements())->set(index, double_value);
Steve Blocka7e24c12009-10-30 11:49:00 +00008532 return value;
8533 }
8534 }
8535
8536 // Otherwise default to slow case.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008537 ASSERT(HasFastDoubleElements());
8538 ASSERT(map()->has_fast_double_elements());
8539 ASSERT(elements()->IsFixedDoubleArray());
John Reck59135872010-11-02 12:39:01 -07008540 Object* obj;
8541 { MaybeObject* maybe_obj = NormalizeElements();
8542 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8543 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008544 ASSERT(HasDictionaryElements());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008545 return SetElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008546}
8547
Iain Merrick75681382010-08-19 15:07:18 +01008548
Steve Block9fac8402011-05-12 15:51:54 +01008549MaybeObject* JSObject::SetElement(uint32_t index,
8550 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008551 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008552 bool check_prototype) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008553 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01008554 if (IsAccessCheckNeeded()) {
8555 Heap* heap = GetHeap();
8556 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_SET)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008557 HandleScope scope(heap->isolate());
Ben Murdoch8b112d22011-06-08 16:22:53 +01008558 Handle<Object> value_handle(value);
8559 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_SET);
8560 return *value_handle;
8561 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008562 }
8563
8564 if (IsJSGlobalProxy()) {
8565 Object* proto = GetPrototype();
8566 if (proto->IsNull()) return value;
8567 ASSERT(proto->IsJSGlobalObject());
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008568 return JSObject::cast(proto)->SetElement(index,
8569 value,
8570 strict_mode,
8571 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008572 }
8573
8574 // Check for lookup interceptor
8575 if (HasIndexedInterceptor()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008576 return SetElementWithInterceptor(index,
8577 value,
8578 strict_mode,
8579 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008580 }
8581
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008582 return SetElementWithoutInterceptor(index,
8583 value,
8584 strict_mode,
8585 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008586}
8587
8588
John Reck59135872010-11-02 12:39:01 -07008589MaybeObject* JSObject::SetElementWithoutInterceptor(uint32_t index,
Steve Block9fac8402011-05-12 15:51:54 +01008590 Object* value,
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008591 StrictModeFlag strict_mode,
Steve Block9fac8402011-05-12 15:51:54 +01008592 bool check_prototype) {
Steve Block44f0eee2011-05-26 01:26:41 +01008593 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008594 switch (GetElementsKind()) {
8595 case FAST_ELEMENTS:
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008596 return SetFastElement(index, value, strict_mode, check_prototype);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008597 case FAST_DOUBLE_ELEMENTS:
8598 return SetFastDoubleElement(index, value, strict_mode, check_prototype);
Steve Block44f0eee2011-05-26 01:26:41 +01008599 case EXTERNAL_PIXEL_ELEMENTS: {
8600 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008601 return pixels->SetValue(index, value);
8602 }
Steve Block3ce2e202009-11-05 08:53:23 +00008603 case EXTERNAL_BYTE_ELEMENTS: {
8604 ExternalByteArray* array = ExternalByteArray::cast(elements());
8605 return array->SetValue(index, value);
8606 }
8607 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8608 ExternalUnsignedByteArray* array =
8609 ExternalUnsignedByteArray::cast(elements());
8610 return array->SetValue(index, value);
8611 }
8612 case EXTERNAL_SHORT_ELEMENTS: {
8613 ExternalShortArray* array = ExternalShortArray::cast(elements());
8614 return array->SetValue(index, value);
8615 }
8616 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8617 ExternalUnsignedShortArray* array =
8618 ExternalUnsignedShortArray::cast(elements());
8619 return array->SetValue(index, value);
8620 }
8621 case EXTERNAL_INT_ELEMENTS: {
8622 ExternalIntArray* array = ExternalIntArray::cast(elements());
8623 return array->SetValue(index, value);
8624 }
8625 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8626 ExternalUnsignedIntArray* array =
8627 ExternalUnsignedIntArray::cast(elements());
8628 return array->SetValue(index, value);
8629 }
8630 case EXTERNAL_FLOAT_ELEMENTS: {
8631 ExternalFloatArray* array = ExternalFloatArray::cast(elements());
8632 return array->SetValue(index, value);
8633 }
Ben Murdoch257744e2011-11-30 15:57:28 +00008634 case EXTERNAL_DOUBLE_ELEMENTS: {
8635 ExternalDoubleArray* array = ExternalDoubleArray::cast(elements());
8636 return array->SetValue(index, value);
8637 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008638 case DICTIONARY_ELEMENTS:
8639 return SetDictionaryElement(index, value, strict_mode, check_prototype);
8640 case NON_STRICT_ARGUMENTS_ELEMENTS: {
8641 FixedArray* parameter_map = FixedArray::cast(elements());
8642 uint32_t length = parameter_map->length();
8643 Object* probe =
8644 (index < length - 2) ? parameter_map->get(index + 2) : NULL;
8645 if (probe != NULL && !probe->IsTheHole()) {
8646 Context* context = Context::cast(parameter_map->get(0));
8647 int context_index = Smi::cast(probe)->value();
8648 ASSERT(!context->get(context_index)->IsTheHole());
8649 context->set(context_index, value);
8650 return value;
Steve Blocka7e24c12009-10-30 11:49:00 +00008651 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008652 // Object is not mapped, defer to the arguments.
8653 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
8654 if (arguments->IsDictionary()) {
8655 return SetDictionaryElement(index, value, strict_mode,
8656 check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008657 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008658 return SetFastElement(index, value, strict_mode, check_prototype);
Steve Blocka7e24c12009-10-30 11:49:00 +00008659 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008660 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008661 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008662 }
8663 // All possible cases have been handled above. Add a return to avoid the
8664 // complaints from the compiler.
8665 UNREACHABLE();
Steve Block44f0eee2011-05-26 01:26:41 +01008666 return isolate->heap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008667}
8668
8669
John Reck59135872010-11-02 12:39:01 -07008670MaybeObject* JSArray::JSArrayUpdateLengthFromIndex(uint32_t index,
8671 Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008672 uint32_t old_len = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01008673 CHECK(length()->ToArrayIndex(&old_len));
Steve Blocka7e24c12009-10-30 11:49:00 +00008674 // Check to see if we need to update the length. For now, we make
8675 // sure that the length stays within 32-bits (unsigned).
8676 if (index >= old_len && index != 0xffffffff) {
John Reck59135872010-11-02 12:39:01 -07008677 Object* len;
8678 { MaybeObject* maybe_len =
Steve Block44f0eee2011-05-26 01:26:41 +01008679 GetHeap()->NumberFromDouble(static_cast<double>(index) + 1);
John Reck59135872010-11-02 12:39:01 -07008680 if (!maybe_len->ToObject(&len)) return maybe_len;
8681 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008682 set_length(len);
8683 }
8684 return value;
8685}
8686
8687
Ben Murdoche0cee9b2011-05-25 10:26:03 +01008688MaybeObject* JSObject::GetElementWithInterceptor(Object* receiver,
John Reck59135872010-11-02 12:39:01 -07008689 uint32_t index) {
Steve Block44f0eee2011-05-26 01:26:41 +01008690 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008691 // Make sure that the top context does not change when doing
8692 // callbacks or interceptor calls.
8693 AssertNoContextChange ncc;
Steve Block44f0eee2011-05-26 01:26:41 +01008694 HandleScope scope(isolate);
8695 Handle<InterceptorInfo> interceptor(GetIndexedInterceptor(), isolate);
8696 Handle<Object> this_handle(receiver, isolate);
8697 Handle<JSObject> holder_handle(this, isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008698 if (!interceptor->getter()->IsUndefined()) {
8699 v8::IndexedPropertyGetter getter =
8700 v8::ToCData<v8::IndexedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008701 LOG(isolate,
8702 ApiIndexedPropertyAccess("interceptor-indexed-get", this, index));
8703 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008704 v8::AccessorInfo info(args.end());
8705 v8::Handle<v8::Value> result;
8706 {
8707 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008708 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008709 result = getter(index, info);
8710 }
Steve Block44f0eee2011-05-26 01:26:41 +01008711 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008712 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
8713 }
8714
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008715 Heap* heap = holder_handle->GetHeap();
8716 ElementsAccessor* handler = holder_handle->GetElementsAccessor();
8717 MaybeObject* raw_result = handler->Get(holder_handle->elements(),
8718 index,
8719 *holder_handle,
8720 *this_handle);
8721 if (raw_result != heap->the_hole_value()) return raw_result;
8722
Steve Block44f0eee2011-05-26 01:26:41 +01008723 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008724
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008725 Object* pt = holder_handle->GetPrototype();
Steve Block44f0eee2011-05-26 01:26:41 +01008726 if (pt == heap->null_value()) return heap->undefined_value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008727 return pt->GetElementWithReceiver(*this_handle, index);
Steve Blocka7e24c12009-10-30 11:49:00 +00008728}
8729
8730
8731bool JSObject::HasDenseElements() {
8732 int capacity = 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008733 int used = 0;
8734 GetElementsCapacityAndUsage(&capacity, &used);
8735 return (capacity == 0) || (used > (capacity / 2));
8736}
8737
8738
8739void JSObject::GetElementsCapacityAndUsage(int* capacity, int* used) {
8740 *capacity = 0;
8741 *used = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008742
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008743 FixedArrayBase* backing_store_base = FixedArrayBase::cast(elements());
8744 FixedArray* backing_store = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00008745 switch (GetElementsKind()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008746 case NON_STRICT_ARGUMENTS_ELEMENTS:
8747 backing_store_base =
8748 FixedArray::cast(FixedArray::cast(backing_store_base)->get(1));
8749 backing_store = FixedArray::cast(backing_store_base);
8750 if (backing_store->IsDictionary()) {
8751 NumberDictionary* dictionary = NumberDictionary::cast(backing_store);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008752 *capacity = dictionary->Capacity();
8753 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008754 break;
8755 }
8756 // Fall through.
8757 case FAST_ELEMENTS:
8758 backing_store = FixedArray::cast(backing_store_base);
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008759 *capacity = backing_store->length();
8760 for (int i = 0; i < *capacity; ++i) {
8761 if (!backing_store->get(i)->IsTheHole()) ++(*used);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008762 }
8763 break;
8764 case DICTIONARY_ELEMENTS: {
8765 NumberDictionary* dictionary =
8766 NumberDictionary::cast(FixedArray::cast(elements()));
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008767 *capacity = dictionary->Capacity();
8768 *used = dictionary->NumberOfElements();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008769 break;
8770 }
8771 case FAST_DOUBLE_ELEMENTS: {
8772 FixedDoubleArray* elms = FixedDoubleArray::cast(elements());
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008773 *capacity = elms->length();
8774 for (int i = 0; i < *capacity; i++) {
8775 if (!elms->is_the_hole(i)) ++(*used);
Steve Blocka7e24c12009-10-30 11:49:00 +00008776 }
8777 break;
8778 }
Steve Block3ce2e202009-11-05 08:53:23 +00008779 case EXTERNAL_BYTE_ELEMENTS:
8780 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
8781 case EXTERNAL_SHORT_ELEMENTS:
8782 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
8783 case EXTERNAL_INT_ELEMENTS:
8784 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00008785 case EXTERNAL_FLOAT_ELEMENTS:
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008786 case EXTERNAL_DOUBLE_ELEMENTS:
8787 case EXTERNAL_PIXEL_ELEMENTS:
8788 // External arrays are considered 100% used.
8789 ExternalArray* external_array = ExternalArray::cast(elements());
8790 *capacity = external_array->length();
8791 *used = external_array->length();
8792 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00008793 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008794}
8795
8796
8797bool JSObject::ShouldConvertToSlowElements(int new_capacity) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008798 STATIC_ASSERT(kMaxUncheckedOldFastElementsLength <=
8799 kMaxUncheckedFastElementsLength);
8800 if (new_capacity <= kMaxUncheckedOldFastElementsLength ||
8801 (new_capacity <= kMaxUncheckedFastElementsLength &&
8802 GetHeap()->InNewSpace(this))) {
8803 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008804 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008805 // If the fast-case backing storage takes up roughly three times as
8806 // much space (in machine words) as a dictionary backing storage
8807 // would, the object should have slow elements.
8808 int old_capacity = 0;
8809 int used_elements = 0;
8810 GetElementsCapacityAndUsage(&old_capacity, &used_elements);
8811 int dictionary_size = NumberDictionary::ComputeCapacity(used_elements) *
8812 NumberDictionary::kEntrySize;
8813 return 3 * dictionary_size <= new_capacity;
Steve Blocka7e24c12009-10-30 11:49:00 +00008814}
8815
8816
8817bool JSObject::ShouldConvertToFastElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008818 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements());
Steve Blocka7e24c12009-10-30 11:49:00 +00008819 // If the elements are sparse, we should not go back to fast case.
8820 if (!HasDenseElements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008821 // An object requiring access checks is never allowed to have fast
8822 // elements. If it had fast elements we would skip security checks.
8823 if (IsAccessCheckNeeded()) return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008824
8825 FixedArray* elements = FixedArray::cast(this->elements());
8826 NumberDictionary* dictionary = NULL;
8827 if (elements->map() == GetHeap()->non_strict_arguments_elements_map()) {
8828 dictionary = NumberDictionary::cast(elements->get(1));
8829 } else {
8830 dictionary = NumberDictionary::cast(elements);
8831 }
8832 // If an element has been added at a very high index in the elements
8833 // dictionary, we cannot go back to fast case.
8834 if (dictionary->requires_slow_elements()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00008835 // If the dictionary backing storage takes up roughly half as much
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008836 // space (in machine words) as a fast-case backing storage would,
8837 // the object should have fast elements.
8838 uint32_t array_size = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00008839 if (IsJSArray()) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008840 CHECK(JSArray::cast(this)->length()->ToArrayIndex(&array_size));
Steve Blocka7e24c12009-10-30 11:49:00 +00008841 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008842 array_size = dictionary->max_number_key();
Steve Blocka7e24c12009-10-30 11:49:00 +00008843 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008844 uint32_t dictionary_size = static_cast<uint32_t>(dictionary->Capacity()) *
8845 NumberDictionary::kEntrySize;
8846 return 2 * dictionary_size >= array_size;
Steve Blocka7e24c12009-10-30 11:49:00 +00008847}
8848
8849
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008850bool JSObject::CanConvertToFastDoubleElements() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008851 if (FLAG_unbox_double_arrays) {
8852 ASSERT(HasDictionaryElements());
8853 NumberDictionary* dictionary = NumberDictionary::cast(elements());
8854 for (int i = 0; i < dictionary->Capacity(); i++) {
8855 Object* key = dictionary->KeyAt(i);
8856 if (key->IsNumber()) {
8857 if (!dictionary->ValueAt(i)->IsNumber()) return false;
8858 }
8859 }
8860 return true;
8861 } else {
8862 return false;
8863 }
8864}
8865
8866
Steve Blocka7e24c12009-10-30 11:49:00 +00008867// Certain compilers request function template instantiation when they
8868// see the definition of the other template functions in the
8869// class. This requires us to have the template functions put
8870// together, so even though this function belongs in objects-debug.cc,
8871// we keep it here instead to satisfy certain compilers.
Ben Murdochb0fe1622011-05-05 13:52:32 +01008872#ifdef OBJECT_PRINT
Steve Blocka7e24c12009-10-30 11:49:00 +00008873template<typename Shape, typename Key>
Ben Murdochb0fe1622011-05-05 13:52:32 +01008874void Dictionary<Shape, Key>::Print(FILE* out) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008875 int capacity = HashTable<Shape, Key>::Capacity();
8876 for (int i = 0; i < capacity; i++) {
8877 Object* k = HashTable<Shape, Key>::KeyAt(i);
8878 if (HashTable<Shape, Key>::IsKey(k)) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008879 PrintF(out, " ");
Steve Blocka7e24c12009-10-30 11:49:00 +00008880 if (k->IsString()) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008881 String::cast(k)->StringPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008882 } else {
Ben Murdochb0fe1622011-05-05 13:52:32 +01008883 k->ShortPrint(out);
Steve Blocka7e24c12009-10-30 11:49:00 +00008884 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01008885 PrintF(out, ": ");
8886 ValueAt(i)->ShortPrint(out);
8887 PrintF(out, "\n");
Steve Blocka7e24c12009-10-30 11:49:00 +00008888 }
8889 }
8890}
8891#endif
8892
8893
8894template<typename Shape, typename Key>
8895void Dictionary<Shape, Key>::CopyValuesTo(FixedArray* elements) {
8896 int pos = 0;
8897 int capacity = HashTable<Shape, Key>::Capacity();
Leon Clarke4515c472010-02-03 11:58:03 +00008898 AssertNoAllocation no_gc;
8899 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
Steve Blocka7e24c12009-10-30 11:49:00 +00008900 for (int i = 0; i < capacity; i++) {
8901 Object* k = Dictionary<Shape, Key>::KeyAt(i);
8902 if (Dictionary<Shape, Key>::IsKey(k)) {
8903 elements->set(pos++, ValueAt(i), mode);
8904 }
8905 }
8906 ASSERT(pos == elements->length());
8907}
8908
8909
8910InterceptorInfo* JSObject::GetNamedInterceptor() {
8911 ASSERT(map()->has_named_interceptor());
8912 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008913 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008914 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008915 constructor->shared()->get_api_func_data()->named_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008916 return InterceptorInfo::cast(result);
8917}
8918
8919
8920InterceptorInfo* JSObject::GetIndexedInterceptor() {
8921 ASSERT(map()->has_indexed_interceptor());
8922 JSFunction* constructor = JSFunction::cast(map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +01008923 ASSERT(constructor->shared()->IsApiFunction());
Steve Blocka7e24c12009-10-30 11:49:00 +00008924 Object* result =
Steve Block6ded16b2010-05-10 14:33:55 +01008925 constructor->shared()->get_api_func_data()->indexed_property_handler();
Steve Blocka7e24c12009-10-30 11:49:00 +00008926 return InterceptorInfo::cast(result);
8927}
8928
8929
John Reck59135872010-11-02 12:39:01 -07008930MaybeObject* JSObject::GetPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008931 JSReceiver* receiver,
John Reck59135872010-11-02 12:39:01 -07008932 String* name,
8933 PropertyAttributes* attributes) {
Steve Blocka7e24c12009-10-30 11:49:00 +00008934 // Check local property in holder, ignore interceptor.
8935 LookupResult result;
8936 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008937 if (result.IsProperty()) {
8938 return GetProperty(receiver, &result, name, attributes);
8939 }
Steve Blocka7e24c12009-10-30 11:49:00 +00008940 // Continue searching via the prototype chain.
8941 Object* pt = GetPrototype();
8942 *attributes = ABSENT;
Ben Murdoch8b112d22011-06-08 16:22:53 +01008943 if (pt->IsNull()) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00008944 return pt->GetPropertyWithReceiver(receiver, name, attributes);
8945}
8946
8947
John Reck59135872010-11-02 12:39:01 -07008948MaybeObject* JSObject::GetLocalPropertyPostInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008949 JSReceiver* receiver,
Steve Blockd0582a62009-12-15 09:54:21 +00008950 String* name,
8951 PropertyAttributes* attributes) {
8952 // Check local property in holder, ignore interceptor.
8953 LookupResult result;
8954 LocalLookupRealNamedProperty(name, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00008955 if (result.IsProperty()) {
8956 return GetProperty(receiver, &result, name, attributes);
8957 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01008958 return GetHeap()->undefined_value();
Steve Blockd0582a62009-12-15 09:54:21 +00008959}
8960
8961
John Reck59135872010-11-02 12:39:01 -07008962MaybeObject* JSObject::GetPropertyWithInterceptor(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008963 JSReceiver* receiver,
Steve Blocka7e24c12009-10-30 11:49:00 +00008964 String* name,
8965 PropertyAttributes* attributes) {
Steve Block44f0eee2011-05-26 01:26:41 +01008966 Isolate* isolate = GetIsolate();
Steve Blocka7e24c12009-10-30 11:49:00 +00008967 InterceptorInfo* interceptor = GetNamedInterceptor();
Steve Block44f0eee2011-05-26 01:26:41 +01008968 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00008969 Handle<JSReceiver> receiver_handle(receiver);
Steve Blocka7e24c12009-10-30 11:49:00 +00008970 Handle<JSObject> holder_handle(this);
8971 Handle<String> name_handle(name);
8972
8973 if (!interceptor->getter()->IsUndefined()) {
8974 v8::NamedPropertyGetter getter =
8975 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter());
Steve Block44f0eee2011-05-26 01:26:41 +01008976 LOG(isolate,
8977 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name));
8978 CustomArguments args(isolate, interceptor->data(), receiver, this);
Steve Blocka7e24c12009-10-30 11:49:00 +00008979 v8::AccessorInfo info(args.end());
8980 v8::Handle<v8::Value> result;
8981 {
8982 // Leaving JavaScript.
Steve Block44f0eee2011-05-26 01:26:41 +01008983 VMState state(isolate, EXTERNAL);
Steve Blocka7e24c12009-10-30 11:49:00 +00008984 result = getter(v8::Utils::ToLocal(name_handle), info);
8985 }
Steve Block44f0eee2011-05-26 01:26:41 +01008986 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008987 if (!result.IsEmpty()) {
8988 *attributes = NONE;
8989 return *v8::Utils::OpenHandle(*result);
8990 }
8991 }
8992
John Reck59135872010-11-02 12:39:01 -07008993 MaybeObject* result = holder_handle->GetPropertyPostInterceptor(
Steve Blocka7e24c12009-10-30 11:49:00 +00008994 *receiver_handle,
8995 *name_handle,
8996 attributes);
Steve Block44f0eee2011-05-26 01:26:41 +01008997 RETURN_IF_SCHEDULED_EXCEPTION(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00008998 return result;
8999}
9000
9001
9002bool JSObject::HasRealNamedProperty(String* key) {
9003 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009004 if (IsAccessCheckNeeded()) {
9005 Heap* heap = GetHeap();
9006 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9007 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9008 return false;
9009 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009010 }
9011
9012 LookupResult result;
9013 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009014 return result.IsProperty() && (result.type() != INTERCEPTOR);
Steve Blocka7e24c12009-10-30 11:49:00 +00009015}
9016
9017
9018bool JSObject::HasRealElementProperty(uint32_t index) {
9019 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009020 if (IsAccessCheckNeeded()) {
9021 Heap* heap = GetHeap();
9022 if (!heap->isolate()->MayIndexedAccess(this, index, v8::ACCESS_HAS)) {
9023 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9024 return false;
9025 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009026 }
9027
9028 // Handle [] on String objects.
9029 if (this->IsStringObjectWithCharacterAt(index)) return true;
9030
9031 switch (GetElementsKind()) {
9032 case FAST_ELEMENTS: {
9033 uint32_t length = IsJSArray() ?
9034 static_cast<uint32_t>(
9035 Smi::cast(JSArray::cast(this)->length())->value()) :
9036 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9037 return (index < length) &&
9038 !FixedArray::cast(elements())->get(index)->IsTheHole();
9039 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009040 case FAST_DOUBLE_ELEMENTS: {
9041 uint32_t length = IsJSArray() ?
9042 static_cast<uint32_t>(
9043 Smi::cast(JSArray::cast(this)->length())->value()) :
9044 static_cast<uint32_t>(FixedDoubleArray::cast(elements())->length());
9045 return (index < length) &&
9046 !FixedDoubleArray::cast(elements())->is_the_hole(index);
9047 break;
9048 }
Steve Block44f0eee2011-05-26 01:26:41 +01009049 case EXTERNAL_PIXEL_ELEMENTS: {
9050 ExternalPixelArray* pixels = ExternalPixelArray::cast(elements());
Steve Blocka7e24c12009-10-30 11:49:00 +00009051 return index < static_cast<uint32_t>(pixels->length());
9052 }
Steve Block3ce2e202009-11-05 08:53:23 +00009053 case EXTERNAL_BYTE_ELEMENTS:
9054 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9055 case EXTERNAL_SHORT_ELEMENTS:
9056 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9057 case EXTERNAL_INT_ELEMENTS:
9058 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009059 case EXTERNAL_FLOAT_ELEMENTS:
9060 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009061 ExternalArray* array = ExternalArray::cast(elements());
9062 return index < static_cast<uint32_t>(array->length());
9063 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009064 case DICTIONARY_ELEMENTS: {
9065 return element_dictionary()->FindEntry(index)
9066 != NumberDictionary::kNotFound;
9067 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009068 case NON_STRICT_ARGUMENTS_ELEMENTS:
9069 UNIMPLEMENTED();
Steve Blocka7e24c12009-10-30 11:49:00 +00009070 break;
9071 }
9072 // All possibilities have been handled above already.
9073 UNREACHABLE();
Ben Murdoch8b112d22011-06-08 16:22:53 +01009074 return GetHeap()->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00009075}
9076
9077
9078bool JSObject::HasRealNamedCallbackProperty(String* key) {
9079 // Check access rights if needed.
Ben Murdoch8b112d22011-06-08 16:22:53 +01009080 if (IsAccessCheckNeeded()) {
9081 Heap* heap = GetHeap();
9082 if (!heap->isolate()->MayNamedAccess(this, key, v8::ACCESS_HAS)) {
9083 heap->isolate()->ReportFailedAccessCheck(this, v8::ACCESS_HAS);
9084 return false;
9085 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009086 }
9087
9088 LookupResult result;
9089 LocalLookupRealNamedProperty(key, &result);
Andrei Popescu402d9372010-02-26 13:31:12 +00009090 return result.IsProperty() && (result.type() == CALLBACKS);
Steve Blocka7e24c12009-10-30 11:49:00 +00009091}
9092
9093
9094int JSObject::NumberOfLocalProperties(PropertyAttributes filter) {
9095 if (HasFastProperties()) {
9096 DescriptorArray* descs = map()->instance_descriptors();
9097 int result = 0;
9098 for (int i = 0; i < descs->number_of_descriptors(); i++) {
Ben Murdoch8b112d22011-06-08 16:22:53 +01009099 PropertyDetails details(descs->GetDetails(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009100 if (details.IsProperty() && (details.attributes() & filter) == 0) {
9101 result++;
9102 }
9103 }
9104 return result;
9105 } else {
9106 return property_dictionary()->NumberOfElementsFilterAttributes(filter);
9107 }
9108}
9109
9110
9111int JSObject::NumberOfEnumProperties() {
9112 return NumberOfLocalProperties(static_cast<PropertyAttributes>(DONT_ENUM));
9113}
9114
9115
9116void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) {
9117 Object* temp = get(i);
9118 set(i, get(j));
9119 set(j, temp);
9120 if (this != numbers) {
9121 temp = numbers->get(i);
9122 numbers->set(i, numbers->get(j));
9123 numbers->set(j, temp);
9124 }
9125}
9126
9127
9128static void InsertionSortPairs(FixedArray* content,
9129 FixedArray* numbers,
9130 int len) {
9131 for (int i = 1; i < len; i++) {
9132 int j = i;
9133 while (j > 0 &&
9134 (NumberToUint32(numbers->get(j - 1)) >
9135 NumberToUint32(numbers->get(j)))) {
9136 content->SwapPairs(numbers, j - 1, j);
9137 j--;
9138 }
9139 }
9140}
9141
9142
9143void HeapSortPairs(FixedArray* content, FixedArray* numbers, int len) {
9144 // In-place heap sort.
9145 ASSERT(content->length() == numbers->length());
9146
9147 // Bottom-up max-heap construction.
9148 for (int i = 1; i < len; ++i) {
9149 int child_index = i;
9150 while (child_index > 0) {
9151 int parent_index = ((child_index + 1) >> 1) - 1;
9152 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9153 uint32_t child_value = NumberToUint32(numbers->get(child_index));
9154 if (parent_value < child_value) {
9155 content->SwapPairs(numbers, parent_index, child_index);
9156 } else {
9157 break;
9158 }
9159 child_index = parent_index;
9160 }
9161 }
9162
9163 // Extract elements and create sorted array.
9164 for (int i = len - 1; i > 0; --i) {
9165 // Put max element at the back of the array.
9166 content->SwapPairs(numbers, 0, i);
9167 // Sift down the new top element.
9168 int parent_index = 0;
9169 while (true) {
9170 int child_index = ((parent_index + 1) << 1) - 1;
9171 if (child_index >= i) break;
9172 uint32_t child1_value = NumberToUint32(numbers->get(child_index));
9173 uint32_t child2_value = NumberToUint32(numbers->get(child_index + 1));
9174 uint32_t parent_value = NumberToUint32(numbers->get(parent_index));
9175 if (child_index + 1 >= i || child1_value > child2_value) {
9176 if (parent_value > child1_value) break;
9177 content->SwapPairs(numbers, parent_index, child_index);
9178 parent_index = child_index;
9179 } else {
9180 if (parent_value > child2_value) break;
9181 content->SwapPairs(numbers, parent_index, child_index + 1);
9182 parent_index = child_index + 1;
9183 }
9184 }
9185 }
9186}
9187
9188
9189// Sort this array and the numbers as pairs wrt. the (distinct) numbers.
9190void FixedArray::SortPairs(FixedArray* numbers, uint32_t len) {
9191 ASSERT(this->length() == numbers->length());
9192 // For small arrays, simply use insertion sort.
9193 if (len <= 10) {
9194 InsertionSortPairs(this, numbers, len);
9195 return;
9196 }
9197 // Check the range of indices.
9198 uint32_t min_index = NumberToUint32(numbers->get(0));
9199 uint32_t max_index = min_index;
9200 uint32_t i;
9201 for (i = 1; i < len; i++) {
9202 if (NumberToUint32(numbers->get(i)) < min_index) {
9203 min_index = NumberToUint32(numbers->get(i));
9204 } else if (NumberToUint32(numbers->get(i)) > max_index) {
9205 max_index = NumberToUint32(numbers->get(i));
9206 }
9207 }
9208 if (max_index - min_index + 1 == len) {
9209 // Indices form a contiguous range, unless there are duplicates.
9210 // Do an in-place linear time sort assuming distinct numbers, but
9211 // avoid hanging in case they are not.
9212 for (i = 0; i < len; i++) {
9213 uint32_t p;
9214 uint32_t j = 0;
9215 // While the current element at i is not at its correct position p,
9216 // swap the elements at these two positions.
9217 while ((p = NumberToUint32(numbers->get(i)) - min_index) != i &&
9218 j++ < len) {
9219 SwapPairs(numbers, i, p);
9220 }
9221 }
9222 } else {
9223 HeapSortPairs(this, numbers, len);
9224 return;
9225 }
9226}
9227
9228
9229// Fill in the names of local properties into the supplied storage. The main
9230// purpose of this function is to provide reflection information for the object
9231// mirrors.
9232void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) {
9233 ASSERT(storage->length() >= (NumberOfLocalProperties(NONE) - index));
9234 if (HasFastProperties()) {
9235 DescriptorArray* descs = map()->instance_descriptors();
9236 for (int i = 0; i < descs->number_of_descriptors(); i++) {
9237 if (descs->IsProperty(i)) storage->set(index++, descs->GetKey(i));
9238 }
9239 ASSERT(storage->length() >= index);
9240 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009241 property_dictionary()->CopyKeysTo(storage,
9242 index,
9243 StringDictionary::UNSORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009244 }
9245}
9246
9247
9248int JSObject::NumberOfLocalElements(PropertyAttributes filter) {
9249 return GetLocalElementKeys(NULL, filter);
9250}
9251
9252
9253int JSObject::NumberOfEnumElements() {
Steve Blockd0582a62009-12-15 09:54:21 +00009254 // Fast case for objects with no elements.
9255 if (!IsJSValue() && HasFastElements()) {
9256 uint32_t length = IsJSArray() ?
9257 static_cast<uint32_t>(
9258 Smi::cast(JSArray::cast(this)->length())->value()) :
9259 static_cast<uint32_t>(FixedArray::cast(elements())->length());
9260 if (length == 0) return 0;
9261 }
9262 // Compute the number of enumerable elements.
Steve Blocka7e24c12009-10-30 11:49:00 +00009263 return NumberOfLocalElements(static_cast<PropertyAttributes>(DONT_ENUM));
9264}
9265
9266
9267int JSObject::GetLocalElementKeys(FixedArray* storage,
9268 PropertyAttributes filter) {
9269 int counter = 0;
9270 switch (GetElementsKind()) {
9271 case FAST_ELEMENTS: {
9272 int length = IsJSArray() ?
9273 Smi::cast(JSArray::cast(this)->length())->value() :
9274 FixedArray::cast(elements())->length();
9275 for (int i = 0; i < length; i++) {
9276 if (!FixedArray::cast(elements())->get(i)->IsTheHole()) {
9277 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009278 storage->set(counter, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009279 }
9280 counter++;
9281 }
9282 }
9283 ASSERT(!storage || storage->length() >= counter);
9284 break;
9285 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009286 case FAST_DOUBLE_ELEMENTS: {
9287 int length = IsJSArray() ?
9288 Smi::cast(JSArray::cast(this)->length())->value() :
9289 FixedDoubleArray::cast(elements())->length();
9290 for (int i = 0; i < length; i++) {
9291 if (!FixedDoubleArray::cast(elements())->is_the_hole(i)) {
9292 if (storage != NULL) {
9293 storage->set(counter, Smi::FromInt(i));
9294 }
9295 counter++;
9296 }
9297 }
9298 ASSERT(!storage || storage->length() >= counter);
9299 break;
9300 }
Steve Block44f0eee2011-05-26 01:26:41 +01009301 case EXTERNAL_PIXEL_ELEMENTS: {
9302 int length = ExternalPixelArray::cast(elements())->length();
Steve Blocka7e24c12009-10-30 11:49:00 +00009303 while (counter < length) {
9304 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009305 storage->set(counter, Smi::FromInt(counter));
Steve Blocka7e24c12009-10-30 11:49:00 +00009306 }
9307 counter++;
9308 }
9309 ASSERT(!storage || storage->length() >= counter);
9310 break;
9311 }
Steve Block3ce2e202009-11-05 08:53:23 +00009312 case EXTERNAL_BYTE_ELEMENTS:
9313 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9314 case EXTERNAL_SHORT_ELEMENTS:
9315 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9316 case EXTERNAL_INT_ELEMENTS:
9317 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
Ben Murdoch257744e2011-11-30 15:57:28 +00009318 case EXTERNAL_FLOAT_ELEMENTS:
9319 case EXTERNAL_DOUBLE_ELEMENTS: {
Steve Block3ce2e202009-11-05 08:53:23 +00009320 int length = ExternalArray::cast(elements())->length();
9321 while (counter < length) {
9322 if (storage != NULL) {
Leon Clarke4515c472010-02-03 11:58:03 +00009323 storage->set(counter, Smi::FromInt(counter));
Steve Block3ce2e202009-11-05 08:53:23 +00009324 }
9325 counter++;
9326 }
9327 ASSERT(!storage || storage->length() >= counter);
9328 break;
9329 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009330 case DICTIONARY_ELEMENTS: {
9331 if (storage != NULL) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009332 element_dictionary()->CopyKeysTo(storage,
9333 filter,
9334 NumberDictionary::SORTED);
Steve Blocka7e24c12009-10-30 11:49:00 +00009335 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009336 counter += element_dictionary()->NumberOfElementsFilterAttributes(filter);
Steve Blocka7e24c12009-10-30 11:49:00 +00009337 break;
9338 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009339 case NON_STRICT_ARGUMENTS_ELEMENTS: {
9340 FixedArray* parameter_map = FixedArray::cast(elements());
9341 int mapped_length = parameter_map->length() - 2;
9342 FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
9343 if (arguments->IsDictionary()) {
9344 // Copy the keys from arguments first, because Dictionary::CopyKeysTo
9345 // will insert in storage starting at index 0.
9346 NumberDictionary* dictionary = NumberDictionary::cast(arguments);
9347 if (storage != NULL) {
9348 dictionary->CopyKeysTo(storage, filter, NumberDictionary::UNSORTED);
9349 }
9350 counter += dictionary->NumberOfElementsFilterAttributes(filter);
9351 for (int i = 0; i < mapped_length; ++i) {
9352 if (!parameter_map->get(i + 2)->IsTheHole()) {
9353 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9354 ++counter;
9355 }
9356 }
9357 if (storage != NULL) storage->SortPairs(storage, counter);
9358
9359 } else {
9360 int backing_length = arguments->length();
9361 int i = 0;
9362 for (; i < mapped_length; ++i) {
9363 if (!parameter_map->get(i + 2)->IsTheHole()) {
9364 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9365 ++counter;
9366 } else if (i < backing_length && !arguments->get(i)->IsTheHole()) {
9367 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9368 ++counter;
9369 }
9370 }
9371 for (; i < backing_length; ++i) {
9372 if (storage != NULL) storage->set(counter, Smi::FromInt(i));
9373 ++counter;
9374 }
9375 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009376 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009377 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009378 }
9379
9380 if (this->IsJSValue()) {
9381 Object* val = JSValue::cast(this)->value();
9382 if (val->IsString()) {
9383 String* str = String::cast(val);
9384 if (storage) {
9385 for (int i = 0; i < str->length(); i++) {
Leon Clarke4515c472010-02-03 11:58:03 +00009386 storage->set(counter + i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +00009387 }
9388 }
9389 counter += str->length();
9390 }
9391 }
9392 ASSERT(!storage || storage->length() == counter);
9393 return counter;
9394}
9395
9396
9397int JSObject::GetEnumElementKeys(FixedArray* storage) {
9398 return GetLocalElementKeys(storage,
9399 static_cast<PropertyAttributes>(DONT_ENUM));
9400}
9401
9402
Steve Blocka7e24c12009-10-30 11:49:00 +00009403// StringKey simply carries a string object as key.
9404class StringKey : public HashTableKey {
9405 public:
9406 explicit StringKey(String* string) :
9407 string_(string),
9408 hash_(HashForObject(string)) { }
9409
9410 bool IsMatch(Object* string) {
9411 // We know that all entries in a hash table had their hash keys created.
9412 // Use that knowledge to have fast failure.
9413 if (hash_ != HashForObject(string)) {
9414 return false;
9415 }
9416 return string_->Equals(String::cast(string));
9417 }
9418
9419 uint32_t Hash() { return hash_; }
9420
9421 uint32_t HashForObject(Object* other) { return String::cast(other)->Hash(); }
9422
9423 Object* AsObject() { return string_; }
9424
9425 String* string_;
9426 uint32_t hash_;
9427};
9428
9429
9430// StringSharedKeys are used as keys in the eval cache.
9431class StringSharedKey : public HashTableKey {
9432 public:
Steve Block1e0659c2011-05-24 12:43:12 +01009433 StringSharedKey(String* source,
9434 SharedFunctionInfo* shared,
9435 StrictModeFlag strict_mode)
9436 : source_(source),
9437 shared_(shared),
9438 strict_mode_(strict_mode) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009439
9440 bool IsMatch(Object* other) {
9441 if (!other->IsFixedArray()) return false;
9442 FixedArray* pair = FixedArray::cast(other);
9443 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9444 if (shared != shared_) return false;
Steve Block1e0659c2011-05-24 12:43:12 +01009445 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9446 Smi::cast(pair->get(2))->value());
9447 if (strict_mode != strict_mode_) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00009448 String* source = String::cast(pair->get(1));
9449 return source->Equals(source_);
9450 }
9451
9452 static uint32_t StringSharedHashHelper(String* source,
Steve Block1e0659c2011-05-24 12:43:12 +01009453 SharedFunctionInfo* shared,
9454 StrictModeFlag strict_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009455 uint32_t hash = source->Hash();
9456 if (shared->HasSourceCode()) {
9457 // Instead of using the SharedFunctionInfo pointer in the hash
9458 // code computation, we use a combination of the hash of the
9459 // script source code and the start and end positions. We do
9460 // this to ensure that the cache entries can survive garbage
9461 // collection.
9462 Script* script = Script::cast(shared->script());
9463 hash ^= String::cast(script->source())->Hash();
Steve Block1e0659c2011-05-24 12:43:12 +01009464 if (strict_mode == kStrictMode) hash ^= 0x8000;
Steve Blocka7e24c12009-10-30 11:49:00 +00009465 hash += shared->start_position();
9466 }
9467 return hash;
9468 }
9469
9470 uint32_t Hash() {
Steve Block1e0659c2011-05-24 12:43:12 +01009471 return StringSharedHashHelper(source_, shared_, strict_mode_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009472 }
9473
9474 uint32_t HashForObject(Object* obj) {
9475 FixedArray* pair = FixedArray::cast(obj);
9476 SharedFunctionInfo* shared = SharedFunctionInfo::cast(pair->get(0));
9477 String* source = String::cast(pair->get(1));
Steve Block1e0659c2011-05-24 12:43:12 +01009478 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(
9479 Smi::cast(pair->get(2))->value());
9480 return StringSharedHashHelper(source, shared, strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009481 }
9482
John Reck59135872010-11-02 12:39:01 -07009483 MUST_USE_RESULT MaybeObject* AsObject() {
9484 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009485 { MaybeObject* maybe_obj = source_->GetHeap()->AllocateFixedArray(3);
John Reck59135872010-11-02 12:39:01 -07009486 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9487 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009488 FixedArray* pair = FixedArray::cast(obj);
9489 pair->set(0, shared_);
9490 pair->set(1, source_);
Steve Block1e0659c2011-05-24 12:43:12 +01009491 pair->set(2, Smi::FromInt(strict_mode_));
Steve Blocka7e24c12009-10-30 11:49:00 +00009492 return pair;
9493 }
9494
9495 private:
9496 String* source_;
9497 SharedFunctionInfo* shared_;
Steve Block1e0659c2011-05-24 12:43:12 +01009498 StrictModeFlag strict_mode_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009499};
9500
9501
9502// RegExpKey carries the source and flags of a regular expression as key.
9503class RegExpKey : public HashTableKey {
9504 public:
9505 RegExpKey(String* string, JSRegExp::Flags flags)
9506 : string_(string),
9507 flags_(Smi::FromInt(flags.value())) { }
9508
Steve Block3ce2e202009-11-05 08:53:23 +00009509 // Rather than storing the key in the hash table, a pointer to the
9510 // stored value is stored where the key should be. IsMatch then
9511 // compares the search key to the found object, rather than comparing
9512 // a key to a key.
Steve Blocka7e24c12009-10-30 11:49:00 +00009513 bool IsMatch(Object* obj) {
9514 FixedArray* val = FixedArray::cast(obj);
9515 return string_->Equals(String::cast(val->get(JSRegExp::kSourceIndex)))
9516 && (flags_ == val->get(JSRegExp::kFlagsIndex));
9517 }
9518
9519 uint32_t Hash() { return RegExpHash(string_, flags_); }
9520
9521 Object* AsObject() {
9522 // Plain hash maps, which is where regexp keys are used, don't
9523 // use this function.
9524 UNREACHABLE();
9525 return NULL;
9526 }
9527
9528 uint32_t HashForObject(Object* obj) {
9529 FixedArray* val = FixedArray::cast(obj);
9530 return RegExpHash(String::cast(val->get(JSRegExp::kSourceIndex)),
9531 Smi::cast(val->get(JSRegExp::kFlagsIndex)));
9532 }
9533
9534 static uint32_t RegExpHash(String* string, Smi* flags) {
9535 return string->Hash() + flags->value();
9536 }
9537
9538 String* string_;
9539 Smi* flags_;
9540};
9541
9542// Utf8SymbolKey carries a vector of chars as key.
9543class Utf8SymbolKey : public HashTableKey {
9544 public:
9545 explicit Utf8SymbolKey(Vector<const char> string)
Steve Blockd0582a62009-12-15 09:54:21 +00009546 : string_(string), hash_field_(0) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009547
9548 bool IsMatch(Object* string) {
9549 return String::cast(string)->IsEqualTo(string_);
9550 }
9551
9552 uint32_t Hash() {
Steve Blockd0582a62009-12-15 09:54:21 +00009553 if (hash_field_ != 0) return hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009554 unibrow::Utf8InputBuffer<> buffer(string_.start(),
9555 static_cast<unsigned>(string_.length()));
9556 chars_ = buffer.Length();
Steve Blockd0582a62009-12-15 09:54:21 +00009557 hash_field_ = String::ComputeHashField(&buffer, chars_);
9558 uint32_t result = hash_field_ >> String::kHashShift;
Steve Blocka7e24c12009-10-30 11:49:00 +00009559 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9560 return result;
9561 }
9562
9563 uint32_t HashForObject(Object* other) {
9564 return String::cast(other)->Hash();
9565 }
9566
John Reck59135872010-11-02 12:39:01 -07009567 MaybeObject* AsObject() {
Steve Blockd0582a62009-12-15 09:54:21 +00009568 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009569 return Isolate::Current()->heap()->AllocateSymbol(
9570 string_, chars_, hash_field_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009571 }
9572
9573 Vector<const char> string_;
Steve Blockd0582a62009-12-15 09:54:21 +00009574 uint32_t hash_field_;
Steve Blocka7e24c12009-10-30 11:49:00 +00009575 int chars_; // Caches the number of characters when computing the hash code.
9576};
9577
9578
Steve Block9fac8402011-05-12 15:51:54 +01009579template <typename Char>
9580class SequentialSymbolKey : public HashTableKey {
9581 public:
9582 explicit SequentialSymbolKey(Vector<const Char> string)
9583 : string_(string), hash_field_(0) { }
9584
9585 uint32_t Hash() {
9586 StringHasher hasher(string_.length());
9587
9588 // Very long strings have a trivial hash that doesn't inspect the
9589 // string contents.
9590 if (hasher.has_trivial_hash()) {
9591 hash_field_ = hasher.GetHashField();
9592 } else {
9593 int i = 0;
9594 // Do the iterative array index computation as long as there is a
9595 // chance this is an array index.
9596 while (i < string_.length() && hasher.is_array_index()) {
9597 hasher.AddCharacter(static_cast<uc32>(string_[i]));
9598 i++;
9599 }
9600
9601 // Process the remaining characters without updating the array
9602 // index.
9603 while (i < string_.length()) {
9604 hasher.AddCharacterNoIndex(static_cast<uc32>(string_[i]));
9605 i++;
9606 }
9607 hash_field_ = hasher.GetHashField();
9608 }
9609
9610 uint32_t result = hash_field_ >> String::kHashShift;
9611 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9612 return result;
9613 }
9614
9615
9616 uint32_t HashForObject(Object* other) {
9617 return String::cast(other)->Hash();
9618 }
9619
9620 Vector<const Char> string_;
9621 uint32_t hash_field_;
9622};
9623
9624
9625
9626class AsciiSymbolKey : public SequentialSymbolKey<char> {
9627 public:
9628 explicit AsciiSymbolKey(Vector<const char> str)
9629 : SequentialSymbolKey<char>(str) { }
9630
9631 bool IsMatch(Object* string) {
9632 return String::cast(string)->IsAsciiEqualTo(string_);
9633 }
9634
9635 MaybeObject* AsObject() {
9636 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009637 return HEAP->AllocateAsciiSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009638 }
9639};
9640
9641
Ben Murdoch257744e2011-11-30 15:57:28 +00009642class SubStringAsciiSymbolKey : public HashTableKey {
9643 public:
9644 explicit SubStringAsciiSymbolKey(Handle<SeqAsciiString> string,
9645 int from,
9646 int length)
9647 : string_(string), from_(from), length_(length) { }
9648
9649 uint32_t Hash() {
9650 ASSERT(length_ >= 0);
9651 ASSERT(from_ + length_ <= string_->length());
9652 StringHasher hasher(length_);
9653
9654 // Very long strings have a trivial hash that doesn't inspect the
9655 // string contents.
9656 if (hasher.has_trivial_hash()) {
9657 hash_field_ = hasher.GetHashField();
9658 } else {
9659 int i = 0;
9660 // Do the iterative array index computation as long as there is a
9661 // chance this is an array index.
9662 while (i < length_ && hasher.is_array_index()) {
9663 hasher.AddCharacter(static_cast<uc32>(
9664 string_->SeqAsciiStringGet(i + from_)));
9665 i++;
9666 }
9667
9668 // Process the remaining characters without updating the array
9669 // index.
9670 while (i < length_) {
9671 hasher.AddCharacterNoIndex(static_cast<uc32>(
9672 string_->SeqAsciiStringGet(i + from_)));
9673 i++;
9674 }
9675 hash_field_ = hasher.GetHashField();
9676 }
9677
9678 uint32_t result = hash_field_ >> String::kHashShift;
9679 ASSERT(result != 0); // Ensure that the hash value of 0 is never computed.
9680 return result;
9681 }
9682
9683
9684 uint32_t HashForObject(Object* other) {
9685 return String::cast(other)->Hash();
9686 }
9687
9688 bool IsMatch(Object* string) {
9689 Vector<const char> chars(string_->GetChars() + from_, length_);
9690 return String::cast(string)->IsAsciiEqualTo(chars);
9691 }
9692
9693 MaybeObject* AsObject() {
9694 if (hash_field_ == 0) Hash();
9695 Vector<const char> chars(string_->GetChars() + from_, length_);
9696 return HEAP->AllocateAsciiSymbol(chars, hash_field_);
9697 }
9698
9699 private:
9700 Handle<SeqAsciiString> string_;
9701 int from_;
9702 int length_;
9703 uint32_t hash_field_;
9704};
9705
9706
Steve Block9fac8402011-05-12 15:51:54 +01009707class TwoByteSymbolKey : public SequentialSymbolKey<uc16> {
9708 public:
9709 explicit TwoByteSymbolKey(Vector<const uc16> str)
9710 : SequentialSymbolKey<uc16>(str) { }
9711
9712 bool IsMatch(Object* string) {
9713 return String::cast(string)->IsTwoByteEqualTo(string_);
9714 }
9715
9716 MaybeObject* AsObject() {
9717 if (hash_field_ == 0) Hash();
Steve Block44f0eee2011-05-26 01:26:41 +01009718 return HEAP->AllocateTwoByteSymbol(string_, hash_field_);
Steve Block9fac8402011-05-12 15:51:54 +01009719 }
9720};
9721
9722
Steve Blocka7e24c12009-10-30 11:49:00 +00009723// SymbolKey carries a string/symbol object as key.
9724class SymbolKey : public HashTableKey {
9725 public:
Steve Block44f0eee2011-05-26 01:26:41 +01009726 explicit SymbolKey(String* string)
9727 : string_(string) { }
Steve Blocka7e24c12009-10-30 11:49:00 +00009728
9729 bool IsMatch(Object* string) {
9730 return String::cast(string)->Equals(string_);
9731 }
9732
9733 uint32_t Hash() { return string_->Hash(); }
9734
9735 uint32_t HashForObject(Object* other) {
9736 return String::cast(other)->Hash();
9737 }
9738
John Reck59135872010-11-02 12:39:01 -07009739 MaybeObject* AsObject() {
Leon Clarkef7060e22010-06-03 12:02:55 +01009740 // Attempt to flatten the string, so that symbols will most often
9741 // be flat strings.
9742 string_ = string_->TryFlattenGetString();
Steve Block44f0eee2011-05-26 01:26:41 +01009743 Heap* heap = string_->GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +00009744 // Transform string to symbol if possible.
Steve Block44f0eee2011-05-26 01:26:41 +01009745 Map* map = heap->SymbolMapForString(string_);
Steve Blocka7e24c12009-10-30 11:49:00 +00009746 if (map != NULL) {
9747 string_->set_map(map);
9748 ASSERT(string_->IsSymbol());
9749 return string_;
9750 }
9751 // Otherwise allocate a new symbol.
9752 StringInputBuffer buffer(string_);
Steve Block44f0eee2011-05-26 01:26:41 +01009753 return heap->AllocateInternalSymbol(&buffer,
Steve Blocka7e24c12009-10-30 11:49:00 +00009754 string_->length(),
Steve Blockd0582a62009-12-15 09:54:21 +00009755 string_->hash_field());
Steve Blocka7e24c12009-10-30 11:49:00 +00009756 }
9757
9758 static uint32_t StringHash(Object* obj) {
9759 return String::cast(obj)->Hash();
9760 }
9761
9762 String* string_;
9763};
9764
9765
9766template<typename Shape, typename Key>
9767void HashTable<Shape, Key>::IteratePrefix(ObjectVisitor* v) {
9768 IteratePointers(v, 0, kElementsStartOffset);
9769}
9770
9771
9772template<typename Shape, typename Key>
9773void HashTable<Shape, Key>::IterateElements(ObjectVisitor* v) {
9774 IteratePointers(v,
9775 kElementsStartOffset,
9776 kHeaderSize + length() * kPointerSize);
9777}
9778
9779
9780template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009781MaybeObject* HashTable<Shape, Key>::Allocate(int at_least_space_for,
9782 PretenureFlag pretenure) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009783 int capacity = ComputeCapacity(at_least_space_for);
9784 if (capacity > HashTable::kMaxCapacity) {
Leon Clarkee46be812010-01-19 14:06:41 +00009785 return Failure::OutOfMemoryException();
9786 }
9787
John Reck59135872010-11-02 12:39:01 -07009788 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +01009789 { MaybeObject* maybe_obj = Isolate::Current()->heap()->
9790 AllocateHashTable(EntryToIndex(capacity), pretenure);
John Reck59135872010-11-02 12:39:01 -07009791 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009792 }
John Reck59135872010-11-02 12:39:01 -07009793 HashTable::cast(obj)->SetNumberOfElements(0);
9794 HashTable::cast(obj)->SetNumberOfDeletedElements(0);
9795 HashTable::cast(obj)->SetCapacity(capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009796 return obj;
9797}
9798
9799
Leon Clarkee46be812010-01-19 14:06:41 +00009800// Find entry for key otherwise return kNotFound.
Ben Murdoch3bec4d22010-07-22 14:51:16 +01009801int StringDictionary::FindEntry(String* key) {
9802 if (!key->IsSymbol()) {
9803 return HashTable<StringDictionaryShape, String*>::FindEntry(key);
9804 }
9805
9806 // Optimized for symbol key. Knowledge of the key type allows:
9807 // 1. Move the check if the key is a symbol out of the loop.
9808 // 2. Avoid comparing hash codes in symbol to symbol comparision.
9809 // 3. Detect a case when a dictionary key is not a symbol but the key is.
9810 // In case of positive result the dictionary key may be replaced by
9811 // the symbol with minimal performance penalty. It gives a chance to
9812 // perform further lookups in code stubs (and significant performance boost
9813 // a certain style of code).
9814
9815 // EnsureCapacity will guarantee the hash table is never full.
9816 uint32_t capacity = Capacity();
9817 uint32_t entry = FirstProbe(key->Hash(), capacity);
9818 uint32_t count = 1;
9819
9820 while (true) {
9821 int index = EntryToIndex(entry);
9822 Object* element = get(index);
9823 if (element->IsUndefined()) break; // Empty entry.
9824 if (key == element) return entry;
9825 if (!element->IsSymbol() &&
9826 !element->IsNull() &&
9827 String::cast(element)->Equals(key)) {
9828 // Replace a non-symbol key by the equivalent symbol for faster further
9829 // lookups.
9830 set(index, key);
9831 return entry;
9832 }
9833 ASSERT(element->IsNull() || !String::cast(element)->Equals(key));
9834 entry = NextProbe(entry, count++, capacity);
9835 }
9836 return kNotFound;
9837}
9838
9839
Steve Blocka7e24c12009-10-30 11:49:00 +00009840template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009841MaybeObject* HashTable<Shape, Key>::Rehash(HashTable* new_table, Key key) {
9842 ASSERT(NumberOfElements() < new_table->Capacity());
9843
9844 AssertNoAllocation no_gc;
9845 WriteBarrierMode mode = new_table->GetWriteBarrierMode(no_gc);
9846
9847 // Copy prefix to new array.
9848 for (int i = kPrefixStartIndex;
9849 i < kPrefixStartIndex + Shape::kPrefixSize;
9850 i++) {
9851 new_table->set(i, get(i), mode);
9852 }
9853
9854 // Rehash the elements.
9855 int capacity = Capacity();
9856 for (int i = 0; i < capacity; i++) {
9857 uint32_t from_index = EntryToIndex(i);
9858 Object* k = get(from_index);
9859 if (IsKey(k)) {
9860 uint32_t hash = Shape::HashForObject(key, k);
9861 uint32_t insertion_index =
9862 EntryToIndex(new_table->FindInsertionEntry(hash));
9863 for (int j = 0; j < Shape::kEntrySize; j++) {
9864 new_table->set(insertion_index + j, get(from_index + j), mode);
9865 }
9866 }
9867 }
9868 new_table->SetNumberOfElements(NumberOfElements());
9869 new_table->SetNumberOfDeletedElements(0);
9870 return new_table;
9871}
9872
9873
9874template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -07009875MaybeObject* HashTable<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +00009876 int capacity = Capacity();
9877 int nof = NumberOfElements() + n;
Leon Clarkee46be812010-01-19 14:06:41 +00009878 int nod = NumberOfDeletedElements();
9879 // Return if:
9880 // 50% is still free after adding n elements and
9881 // at most 50% of the free elements are deleted elements.
Steve Block6ded16b2010-05-10 14:33:55 +01009882 if (nod <= (capacity - nof) >> 1) {
9883 int needed_free = nof >> 1;
9884 if (nof + needed_free <= capacity) return this;
9885 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009886
Steve Block6ded16b2010-05-10 14:33:55 +01009887 const int kMinCapacityForPretenure = 256;
9888 bool pretenure =
Ben Murdoch8b112d22011-06-08 16:22:53 +01009889 (capacity > kMinCapacityForPretenure) && !GetHeap()->InNewSpace(this);
John Reck59135872010-11-02 12:39:01 -07009890 Object* obj;
9891 { MaybeObject* maybe_obj =
9892 Allocate(nof * 2, pretenure ? TENURED : NOT_TENURED);
9893 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9894 }
Leon Clarke4515c472010-02-03 11:58:03 +00009895
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009896 return Rehash(HashTable::cast(obj), key);
9897}
Steve Blocka7e24c12009-10-30 11:49:00 +00009898
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009899
9900template<typename Shape, typename Key>
9901MaybeObject* HashTable<Shape, Key>::Shrink(Key key) {
9902 int capacity = Capacity();
9903 int nof = NumberOfElements();
9904
9905 // Shrink to fit the number of elements if only a quarter of the
9906 // capacity is filled with elements.
9907 if (nof > (capacity >> 2)) return this;
9908 // Allocate a new dictionary with room for at least the current
9909 // number of elements. The allocation method will make sure that
9910 // there is extra room in the dictionary for additions. Don't go
9911 // lower than room for 16 elements.
9912 int at_least_room_for = nof;
9913 if (at_least_room_for < 16) return this;
9914
9915 const int kMinCapacityForPretenure = 256;
9916 bool pretenure =
9917 (at_least_room_for > kMinCapacityForPretenure) &&
9918 !GetHeap()->InNewSpace(this);
9919 Object* obj;
9920 { MaybeObject* maybe_obj =
9921 Allocate(at_least_room_for, pretenure ? TENURED : NOT_TENURED);
9922 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +00009923 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009924
9925 return Rehash(HashTable::cast(obj), key);
Steve Blocka7e24c12009-10-30 11:49:00 +00009926}
9927
9928
9929template<typename Shape, typename Key>
9930uint32_t HashTable<Shape, Key>::FindInsertionEntry(uint32_t hash) {
9931 uint32_t capacity = Capacity();
Leon Clarkee46be812010-01-19 14:06:41 +00009932 uint32_t entry = FirstProbe(hash, capacity);
9933 uint32_t count = 1;
9934 // EnsureCapacity will guarantee the hash table is never full.
9935 while (true) {
9936 Object* element = KeyAt(entry);
9937 if (element->IsUndefined() || element->IsNull()) break;
9938 entry = NextProbe(entry, count++, capacity);
Steve Blocka7e24c12009-10-30 11:49:00 +00009939 }
Steve Blocka7e24c12009-10-30 11:49:00 +00009940 return entry;
9941}
9942
9943// Force instantiation of template instances class.
9944// Please note this list is compiler dependent.
9945
9946template class HashTable<SymbolTableShape, HashTableKey*>;
9947
9948template class HashTable<CompilationCacheShape, HashTableKey*>;
9949
9950template class HashTable<MapCacheShape, HashTableKey*>;
9951
Ben Murdoch69a99ed2011-11-30 16:03:39 +00009952template class HashTable<ObjectHashTableShape, JSObject*>;
9953
Steve Blocka7e24c12009-10-30 11:49:00 +00009954template class Dictionary<StringDictionaryShape, String*>;
9955
9956template class Dictionary<NumberDictionaryShape, uint32_t>;
9957
John Reck59135872010-11-02 12:39:01 -07009958template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00009959 int);
9960
John Reck59135872010-11-02 12:39:01 -07009961template MaybeObject* Dictionary<StringDictionaryShape, String*>::Allocate(
Steve Blocka7e24c12009-10-30 11:49:00 +00009962 int);
9963
John Reck59135872010-11-02 12:39:01 -07009964template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AtPut(
Steve Blocka7e24c12009-10-30 11:49:00 +00009965 uint32_t, Object*);
9966
9967template Object* Dictionary<NumberDictionaryShape, uint32_t>::SlowReverseLookup(
9968 Object*);
9969
9970template Object* Dictionary<StringDictionaryShape, String*>::SlowReverseLookup(
9971 Object*);
9972
9973template void Dictionary<NumberDictionaryShape, uint32_t>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009974 FixedArray*,
9975 PropertyAttributes,
9976 Dictionary<NumberDictionaryShape, uint32_t>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009977
9978template Object* Dictionary<StringDictionaryShape, String*>::DeleteProperty(
9979 int, JSObject::DeleteMode);
9980
9981template Object* Dictionary<NumberDictionaryShape, uint32_t>::DeleteProperty(
9982 int, JSObject::DeleteMode);
9983
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009984template MaybeObject* Dictionary<StringDictionaryShape, String*>::Shrink(
9985 String*);
9986
9987template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Shrink(
9988 uint32_t);
9989
Steve Blocka7e24c12009-10-30 11:49:00 +00009990template void Dictionary<StringDictionaryShape, String*>::CopyKeysTo(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009991 FixedArray*,
9992 int,
9993 Dictionary<StringDictionaryShape, String*>::SortMode);
Steve Blocka7e24c12009-10-30 11:49:00 +00009994
9995template int
9996Dictionary<StringDictionaryShape, String*>::NumberOfElementsFilterAttributes(
9997 PropertyAttributes);
9998
John Reck59135872010-11-02 12:39:01 -07009999template MaybeObject* Dictionary<StringDictionaryShape, String*>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010000 String*, Object*, PropertyDetails);
10001
John Reck59135872010-11-02 12:39:01 -070010002template MaybeObject*
Steve Blocka7e24c12009-10-30 11:49:00 +000010003Dictionary<StringDictionaryShape, String*>::GenerateNewEnumerationIndices();
10004
10005template int
10006Dictionary<NumberDictionaryShape, uint32_t>::NumberOfElementsFilterAttributes(
10007 PropertyAttributes);
10008
John Reck59135872010-11-02 12:39:01 -070010009template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::Add(
Steve Blocka7e24c12009-10-30 11:49:00 +000010010 uint32_t, Object*, PropertyDetails);
10011
John Reck59135872010-11-02 12:39:01 -070010012template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::
10013 EnsureCapacity(int, uint32_t);
Steve Blocka7e24c12009-10-30 11:49:00 +000010014
John Reck59135872010-11-02 12:39:01 -070010015template MaybeObject* Dictionary<StringDictionaryShape, String*>::
10016 EnsureCapacity(int, String*);
Steve Blocka7e24c12009-10-30 11:49:00 +000010017
John Reck59135872010-11-02 12:39:01 -070010018template MaybeObject* Dictionary<NumberDictionaryShape, uint32_t>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010019 uint32_t, Object*, PropertyDetails, uint32_t);
10020
John Reck59135872010-11-02 12:39:01 -070010021template MaybeObject* Dictionary<StringDictionaryShape, String*>::AddEntry(
Steve Blocka7e24c12009-10-30 11:49:00 +000010022 String*, Object*, PropertyDetails, uint32_t);
10023
10024template
10025int Dictionary<NumberDictionaryShape, uint32_t>::NumberOfEnumElements();
10026
10027template
10028int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements();
10029
Leon Clarkee46be812010-01-19 14:06:41 +000010030template
10031int HashTable<NumberDictionaryShape, uint32_t>::FindEntry(uint32_t);
10032
10033
Steve Blocka7e24c12009-10-30 11:49:00 +000010034// Collates undefined and unexisting elements below limit from position
10035// zero of the elements. The object stays in Dictionary mode.
John Reck59135872010-11-02 12:39:01 -070010036MaybeObject* JSObject::PrepareSlowElementsForSort(uint32_t limit) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010037 ASSERT(HasDictionaryElements());
10038 // Must stay in dictionary mode, either because of requires_slow_elements,
10039 // or because we are not going to sort (and therefore compact) all of the
10040 // elements.
10041 NumberDictionary* dict = element_dictionary();
10042 HeapNumber* result_double = NULL;
10043 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10044 // Allocate space for result before we start mutating the object.
John Reck59135872010-11-02 12:39:01 -070010045 Object* new_double;
Ben Murdoch8b112d22011-06-08 16:22:53 +010010046 { MaybeObject* maybe_new_double = GetHeap()->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010047 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10048 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010049 result_double = HeapNumber::cast(new_double);
10050 }
10051
John Reck59135872010-11-02 12:39:01 -070010052 Object* obj;
10053 { MaybeObject* maybe_obj =
10054 NumberDictionary::Allocate(dict->NumberOfElements());
10055 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10056 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010057 NumberDictionary* new_dict = NumberDictionary::cast(obj);
10058
10059 AssertNoAllocation no_alloc;
10060
10061 uint32_t pos = 0;
10062 uint32_t undefs = 0;
Steve Block6ded16b2010-05-10 14:33:55 +010010063 int capacity = dict->Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000010064 for (int i = 0; i < capacity; i++) {
10065 Object* k = dict->KeyAt(i);
10066 if (dict->IsKey(k)) {
10067 ASSERT(k->IsNumber());
10068 ASSERT(!k->IsSmi() || Smi::cast(k)->value() >= 0);
10069 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() >= 0);
10070 ASSERT(!k->IsHeapNumber() || HeapNumber::cast(k)->value() <= kMaxUInt32);
10071 Object* value = dict->ValueAt(i);
10072 PropertyDetails details = dict->DetailsAt(i);
10073 if (details.type() == CALLBACKS) {
10074 // Bail out and do the sorting of undefineds and array holes in JS.
10075 return Smi::FromInt(-1);
10076 }
10077 uint32_t key = NumberToUint32(k);
John Reck59135872010-11-02 12:39:01 -070010078 // In the following we assert that adding the entry to the new dictionary
10079 // does not cause GC. This is the case because we made sure to allocate
10080 // the dictionary big enough above, so it need not grow.
Steve Blocka7e24c12009-10-30 11:49:00 +000010081 if (key < limit) {
10082 if (value->IsUndefined()) {
10083 undefs++;
10084 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010085 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10086 // Adding an entry with the key beyond smi-range requires
10087 // allocation. Bailout.
10088 return Smi::FromInt(-1);
10089 }
John Reck59135872010-11-02 12:39:01 -070010090 new_dict->AddNumberEntry(pos, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010091 pos++;
10092 }
10093 } else {
Steve Block1e0659c2011-05-24 12:43:12 +010010094 if (key > static_cast<uint32_t>(Smi::kMaxValue)) {
10095 // Adding an entry with the key beyond smi-range requires
10096 // allocation. Bailout.
10097 return Smi::FromInt(-1);
10098 }
John Reck59135872010-11-02 12:39:01 -070010099 new_dict->AddNumberEntry(key, value, details)->ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010100 }
10101 }
10102 }
10103
10104 uint32_t result = pos;
10105 PropertyDetails no_details = PropertyDetails(NONE, NORMAL);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010106 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010107 while (undefs > 0) {
Steve Block1e0659c2011-05-24 12:43:12 +010010108 if (pos > static_cast<uint32_t>(Smi::kMaxValue)) {
10109 // Adding an entry with the key beyond smi-range requires
10110 // allocation. Bailout.
10111 return Smi::FromInt(-1);
10112 }
Steve Block44f0eee2011-05-26 01:26:41 +010010113 new_dict->AddNumberEntry(pos, heap->undefined_value(), no_details)->
John Reck59135872010-11-02 12:39:01 -070010114 ToObjectUnchecked();
Steve Blocka7e24c12009-10-30 11:49:00 +000010115 pos++;
10116 undefs--;
10117 }
10118
10119 set_elements(new_dict);
10120
10121 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10122 return Smi::FromInt(static_cast<int>(result));
10123 }
10124
10125 ASSERT_NE(NULL, result_double);
10126 result_double->set_value(static_cast<double>(result));
10127 return result_double;
10128}
10129
10130
10131// Collects all defined (non-hole) and non-undefined (array) elements at
10132// the start of the elements array.
10133// If the object is in dictionary mode, it is converted to fast elements
10134// mode.
John Reck59135872010-11-02 12:39:01 -070010135MaybeObject* JSObject::PrepareElementsForSort(uint32_t limit) {
Ben Murdoch589d6972011-11-30 16:04:58 +000010136 ASSERT(!HasExternalArrayElements());
10137
Ben Murdoch8b112d22011-06-08 16:22:53 +010010138 Heap* heap = GetHeap();
10139
Steve Blocka7e24c12009-10-30 11:49:00 +000010140 if (HasDictionaryElements()) {
10141 // Convert to fast elements containing only the existing properties.
10142 // Ordering is irrelevant, since we are going to sort anyway.
10143 NumberDictionary* dict = element_dictionary();
10144 if (IsJSArray() || dict->requires_slow_elements() ||
10145 dict->max_number_key() >= limit) {
10146 return PrepareSlowElementsForSort(limit);
10147 }
10148 // Convert to fast elements.
10149
John Reck59135872010-11-02 12:39:01 -070010150 Object* obj;
10151 { MaybeObject* maybe_obj = map()->GetFastElementsMap();
10152 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10153 }
Steve Block8defd9f2010-07-08 12:39:36 +010010154 Map* new_map = Map::cast(obj);
10155
Steve Block44f0eee2011-05-26 01:26:41 +010010156 PretenureFlag tenure = heap->InNewSpace(this) ? NOT_TENURED: TENURED;
John Reck59135872010-11-02 12:39:01 -070010157 Object* new_array;
10158 { MaybeObject* maybe_new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010010159 heap->AllocateFixedArray(dict->NumberOfElements(), tenure);
John Reck59135872010-11-02 12:39:01 -070010160 if (!maybe_new_array->ToObject(&new_array)) return maybe_new_array;
10161 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010162 FixedArray* fast_elements = FixedArray::cast(new_array);
10163 dict->CopyValuesTo(fast_elements);
Steve Block8defd9f2010-07-08 12:39:36 +010010164
10165 set_map(new_map);
Steve Blocka7e24c12009-10-30 11:49:00 +000010166 set_elements(fast_elements);
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010167 } else if (!HasFastDoubleElements()) {
John Reck59135872010-11-02 12:39:01 -070010168 Object* obj;
10169 { MaybeObject* maybe_obj = EnsureWritableFastElements();
10170 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10171 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010172 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010173 ASSERT(HasFastElements() || HasFastDoubleElements());
Steve Blocka7e24c12009-10-30 11:49:00 +000010174
10175 // Collect holes at the end, undefined before that and the rest at the
10176 // start, and return the number of non-hole, non-undefined values.
10177
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010178 FixedArrayBase* elements_base = FixedArrayBase::cast(this->elements());
10179 uint32_t elements_length = static_cast<uint32_t>(elements_base->length());
Steve Blocka7e24c12009-10-30 11:49:00 +000010180 if (limit > elements_length) {
10181 limit = elements_length ;
10182 }
10183 if (limit == 0) {
10184 return Smi::FromInt(0);
10185 }
10186
10187 HeapNumber* result_double = NULL;
10188 if (limit > static_cast<uint32_t>(Smi::kMaxValue)) {
10189 // Pessimistically allocate space for return value before
10190 // we start mutating the array.
John Reck59135872010-11-02 12:39:01 -070010191 Object* new_double;
Steve Block44f0eee2011-05-26 01:26:41 +010010192 { MaybeObject* maybe_new_double = heap->AllocateHeapNumber(0.0);
John Reck59135872010-11-02 12:39:01 -070010193 if (!maybe_new_double->ToObject(&new_double)) return maybe_new_double;
10194 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010195 result_double = HeapNumber::cast(new_double);
10196 }
10197
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010198 uint32_t result = 0;
10199 if (elements_base->map() == heap->fixed_double_array_map()) {
10200 FixedDoubleArray* elements = FixedDoubleArray::cast(elements_base);
10201 // Split elements into defined and the_hole, in that order.
10202 unsigned int holes = limit;
10203 // Assume most arrays contain no holes and undefined values, so minimize the
10204 // number of stores of non-undefined, non-the-hole values.
10205 for (unsigned int i = 0; i < holes; i++) {
10206 if (elements->is_the_hole(i)) {
10207 holes--;
10208 } else {
10209 continue;
10210 }
10211 // Position i needs to be filled.
10212 while (holes > i) {
10213 if (elements->is_the_hole(holes)) {
10214 holes--;
10215 } else {
10216 elements->set(i, elements->get_scalar(holes));
10217 break;
10218 }
10219 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010220 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010221 result = holes;
10222 while (holes < limit) {
10223 elements->set_the_hole(holes);
10224 holes++;
10225 }
10226 } else {
10227 FixedArray* elements = FixedArray::cast(elements_base);
10228 AssertNoAllocation no_alloc;
10229
10230 // Split elements into defined, undefined and the_hole, in that order. Only
10231 // count locations for undefined and the hole, and fill them afterwards.
10232 WriteBarrierMode write_barrier = elements->GetWriteBarrierMode(no_alloc);
10233 unsigned int undefs = limit;
10234 unsigned int holes = limit;
10235 // Assume most arrays contain no holes and undefined values, so minimize the
10236 // number of stores of non-undefined, non-the-hole values.
10237 for (unsigned int i = 0; i < undefs; i++) {
10238 Object* current = elements->get(i);
Steve Blocka7e24c12009-10-30 11:49:00 +000010239 if (current->IsTheHole()) {
10240 holes--;
10241 undefs--;
10242 } else if (current->IsUndefined()) {
10243 undefs--;
10244 } else {
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010245 continue;
10246 }
10247 // Position i needs to be filled.
10248 while (undefs > i) {
10249 current = elements->get(undefs);
10250 if (current->IsTheHole()) {
10251 holes--;
10252 undefs--;
10253 } else if (current->IsUndefined()) {
10254 undefs--;
10255 } else {
10256 elements->set(i, current, write_barrier);
10257 break;
10258 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010259 }
10260 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +000010261 result = undefs;
10262 while (undefs < holes) {
10263 elements->set_undefined(undefs);
10264 undefs++;
10265 }
10266 while (holes < limit) {
10267 elements->set_the_hole(holes);
10268 holes++;
10269 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010270 }
10271
10272 if (result <= static_cast<uint32_t>(Smi::kMaxValue)) {
10273 return Smi::FromInt(static_cast<int>(result));
10274 }
10275 ASSERT_NE(NULL, result_double);
10276 result_double->set_value(static_cast<double>(result));
10277 return result_double;
10278}
10279
10280
Steve Block44f0eee2011-05-26 01:26:41 +010010281Object* ExternalPixelArray::SetValue(uint32_t index, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010282 uint8_t clamped_value = 0;
10283 if (index < static_cast<uint32_t>(length())) {
10284 if (value->IsSmi()) {
10285 int int_value = Smi::cast(value)->value();
10286 if (int_value < 0) {
10287 clamped_value = 0;
10288 } else if (int_value > 255) {
10289 clamped_value = 255;
10290 } else {
10291 clamped_value = static_cast<uint8_t>(int_value);
10292 }
10293 } else if (value->IsHeapNumber()) {
10294 double double_value = HeapNumber::cast(value)->value();
10295 if (!(double_value > 0)) {
10296 // NaN and less than zero clamp to zero.
10297 clamped_value = 0;
10298 } else if (double_value > 255) {
10299 // Greater than 255 clamp to 255.
10300 clamped_value = 255;
10301 } else {
10302 // Other doubles are rounded to the nearest integer.
10303 clamped_value = static_cast<uint8_t>(double_value + 0.5);
10304 }
10305 } else {
10306 // Clamp undefined to zero (default). All other types have been
10307 // converted to a number type further up in the call chain.
10308 ASSERT(value->IsUndefined());
10309 }
10310 set(index, clamped_value);
10311 }
10312 return Smi::FromInt(clamped_value);
10313}
10314
10315
Steve Block3ce2e202009-11-05 08:53:23 +000010316template<typename ExternalArrayClass, typename ValueType>
Steve Block44f0eee2011-05-26 01:26:41 +010010317static MaybeObject* ExternalArrayIntSetter(Heap* heap,
10318 ExternalArrayClass* receiver,
John Reck59135872010-11-02 12:39:01 -070010319 uint32_t index,
10320 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010321 ValueType cast_value = 0;
10322 if (index < static_cast<uint32_t>(receiver->length())) {
10323 if (value->IsSmi()) {
10324 int int_value = Smi::cast(value)->value();
10325 cast_value = static_cast<ValueType>(int_value);
10326 } else if (value->IsHeapNumber()) {
10327 double double_value = HeapNumber::cast(value)->value();
10328 cast_value = static_cast<ValueType>(DoubleToInt32(double_value));
10329 } else {
10330 // Clamp undefined to zero (default). All other types have been
10331 // converted to a number type further up in the call chain.
10332 ASSERT(value->IsUndefined());
10333 }
10334 receiver->set(index, cast_value);
10335 }
Steve Block44f0eee2011-05-26 01:26:41 +010010336 return heap->NumberFromInt32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010337}
10338
10339
John Reck59135872010-11-02 12:39:01 -070010340MaybeObject* ExternalByteArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010341 return ExternalArrayIntSetter<ExternalByteArray, int8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010342 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010343}
10344
10345
John Reck59135872010-11-02 12:39:01 -070010346MaybeObject* ExternalUnsignedByteArray::SetValue(uint32_t index,
10347 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010348 return ExternalArrayIntSetter<ExternalUnsignedByteArray, uint8_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010349 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010350}
10351
10352
John Reck59135872010-11-02 12:39:01 -070010353MaybeObject* ExternalShortArray::SetValue(uint32_t index,
10354 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010355 return ExternalArrayIntSetter<ExternalShortArray, int16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010356 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010357}
10358
10359
John Reck59135872010-11-02 12:39:01 -070010360MaybeObject* ExternalUnsignedShortArray::SetValue(uint32_t index,
10361 Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010362 return ExternalArrayIntSetter<ExternalUnsignedShortArray, uint16_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010363 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010364}
10365
10366
John Reck59135872010-11-02 12:39:01 -070010367MaybeObject* ExternalIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010368 return ExternalArrayIntSetter<ExternalIntArray, int32_t>
Steve Block44f0eee2011-05-26 01:26:41 +010010369 (GetHeap(), this, index, value);
Steve Block3ce2e202009-11-05 08:53:23 +000010370}
10371
10372
John Reck59135872010-11-02 12:39:01 -070010373MaybeObject* ExternalUnsignedIntArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010374 uint32_t cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010375 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010376 if (index < static_cast<uint32_t>(length())) {
10377 if (value->IsSmi()) {
10378 int int_value = Smi::cast(value)->value();
10379 cast_value = static_cast<uint32_t>(int_value);
10380 } else if (value->IsHeapNumber()) {
10381 double double_value = HeapNumber::cast(value)->value();
10382 cast_value = static_cast<uint32_t>(DoubleToUint32(double_value));
10383 } else {
10384 // Clamp undefined to zero (default). All other types have been
10385 // converted to a number type further up in the call chain.
10386 ASSERT(value->IsUndefined());
10387 }
10388 set(index, cast_value);
10389 }
Steve Block44f0eee2011-05-26 01:26:41 +010010390 return heap->NumberFromUint32(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010391}
10392
10393
John Reck59135872010-11-02 12:39:01 -070010394MaybeObject* ExternalFloatArray::SetValue(uint32_t index, Object* value) {
Steve Block3ce2e202009-11-05 08:53:23 +000010395 float cast_value = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010396 Heap* heap = GetHeap();
Steve Block3ce2e202009-11-05 08:53:23 +000010397 if (index < static_cast<uint32_t>(length())) {
10398 if (value->IsSmi()) {
10399 int int_value = Smi::cast(value)->value();
10400 cast_value = static_cast<float>(int_value);
10401 } else if (value->IsHeapNumber()) {
10402 double double_value = HeapNumber::cast(value)->value();
10403 cast_value = static_cast<float>(double_value);
10404 } else {
10405 // Clamp undefined to zero (default). All other types have been
10406 // converted to a number type further up in the call chain.
10407 ASSERT(value->IsUndefined());
10408 }
10409 set(index, cast_value);
10410 }
Steve Block44f0eee2011-05-26 01:26:41 +010010411 return heap->AllocateHeapNumber(cast_value);
Steve Block3ce2e202009-11-05 08:53:23 +000010412}
10413
10414
Ben Murdoch257744e2011-11-30 15:57:28 +000010415MaybeObject* ExternalDoubleArray::SetValue(uint32_t index, Object* value) {
10416 double double_value = 0;
10417 Heap* heap = GetHeap();
10418 if (index < static_cast<uint32_t>(length())) {
10419 if (value->IsSmi()) {
10420 int int_value = Smi::cast(value)->value();
10421 double_value = static_cast<double>(int_value);
10422 } else if (value->IsHeapNumber()) {
10423 double_value = HeapNumber::cast(value)->value();
10424 } else {
10425 // Clamp undefined to zero (default). All other types have been
10426 // converted to a number type further up in the call chain.
10427 ASSERT(value->IsUndefined());
10428 }
10429 set(index, double_value);
10430 }
10431 return heap->AllocateHeapNumber(double_value);
10432}
10433
10434
Ben Murdochb0fe1622011-05-05 13:52:32 +010010435JSGlobalPropertyCell* GlobalObject::GetPropertyCell(LookupResult* result) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010436 ASSERT(!HasFastProperties());
10437 Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry());
Ben Murdochb0fe1622011-05-05 13:52:32 +010010438 return JSGlobalPropertyCell::cast(value);
Steve Blocka7e24c12009-10-30 11:49:00 +000010439}
10440
10441
John Reck59135872010-11-02 12:39:01 -070010442MaybeObject* GlobalObject::EnsurePropertyCell(String* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010443 ASSERT(!HasFastProperties());
10444 int entry = property_dictionary()->FindEntry(name);
10445 if (entry == StringDictionary::kNotFound) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010446 Heap* heap = GetHeap();
John Reck59135872010-11-02 12:39:01 -070010447 Object* cell;
10448 { MaybeObject* maybe_cell =
Steve Block44f0eee2011-05-26 01:26:41 +010010449 heap->AllocateJSGlobalPropertyCell(heap->the_hole_value());
John Reck59135872010-11-02 12:39:01 -070010450 if (!maybe_cell->ToObject(&cell)) return maybe_cell;
10451 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010452 PropertyDetails details(NONE, NORMAL);
10453 details = details.AsDeleted();
John Reck59135872010-11-02 12:39:01 -070010454 Object* dictionary;
10455 { MaybeObject* maybe_dictionary =
10456 property_dictionary()->Add(name, cell, details);
10457 if (!maybe_dictionary->ToObject(&dictionary)) return maybe_dictionary;
10458 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010459 set_properties(StringDictionary::cast(dictionary));
10460 return cell;
10461 } else {
10462 Object* value = property_dictionary()->ValueAt(entry);
10463 ASSERT(value->IsJSGlobalPropertyCell());
10464 return value;
10465 }
10466}
10467
10468
John Reck59135872010-11-02 12:39:01 -070010469MaybeObject* SymbolTable::LookupString(String* string, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010470 SymbolKey key(string);
10471 return LookupKey(&key, s);
10472}
10473
10474
Steve Blockd0582a62009-12-15 09:54:21 +000010475// This class is used for looking up two character strings in the symbol table.
10476// If we don't have a hit we don't want to waste much time so we unroll the
10477// string hash calculation loop here for speed. Doesn't work if the two
10478// characters form a decimal integer, since such strings have a different hash
10479// algorithm.
10480class TwoCharHashTableKey : public HashTableKey {
10481 public:
10482 TwoCharHashTableKey(uint32_t c1, uint32_t c2)
10483 : c1_(c1), c2_(c2) {
10484 // Char 1.
10485 uint32_t hash = c1 + (c1 << 10);
10486 hash ^= hash >> 6;
10487 // Char 2.
10488 hash += c2;
10489 hash += hash << 10;
10490 hash ^= hash >> 6;
10491 // GetHash.
10492 hash += hash << 3;
10493 hash ^= hash >> 11;
10494 hash += hash << 15;
10495 if (hash == 0) hash = 27;
10496#ifdef DEBUG
10497 StringHasher hasher(2);
10498 hasher.AddCharacter(c1);
10499 hasher.AddCharacter(c2);
10500 // If this assert fails then we failed to reproduce the two-character
10501 // version of the string hashing algorithm above. One reason could be
10502 // that we were passed two digits as characters, since the hash
10503 // algorithm is different in that case.
10504 ASSERT_EQ(static_cast<int>(hasher.GetHash()), static_cast<int>(hash));
10505#endif
10506 hash_ = hash;
10507 }
10508
10509 bool IsMatch(Object* o) {
10510 if (!o->IsString()) return false;
10511 String* other = String::cast(o);
10512 if (other->length() != 2) return false;
10513 if (other->Get(0) != c1_) return false;
10514 return other->Get(1) == c2_;
10515 }
10516
10517 uint32_t Hash() { return hash_; }
10518 uint32_t HashForObject(Object* key) {
10519 if (!key->IsString()) return 0;
10520 return String::cast(key)->Hash();
10521 }
10522
10523 Object* AsObject() {
10524 // The TwoCharHashTableKey is only used for looking in the symbol
10525 // table, not for adding to it.
10526 UNREACHABLE();
10527 return NULL;
10528 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010529
Steve Blockd0582a62009-12-15 09:54:21 +000010530 private:
10531 uint32_t c1_;
10532 uint32_t c2_;
10533 uint32_t hash_;
10534};
10535
10536
Steve Blocka7e24c12009-10-30 11:49:00 +000010537bool SymbolTable::LookupSymbolIfExists(String* string, String** symbol) {
10538 SymbolKey key(string);
10539 int entry = FindEntry(&key);
10540 if (entry == kNotFound) {
10541 return false;
10542 } else {
10543 String* result = String::cast(KeyAt(entry));
10544 ASSERT(StringShape(result).IsSymbol());
10545 *symbol = result;
10546 return true;
10547 }
10548}
10549
10550
Steve Blockd0582a62009-12-15 09:54:21 +000010551bool SymbolTable::LookupTwoCharsSymbolIfExists(uint32_t c1,
10552 uint32_t c2,
10553 String** symbol) {
10554 TwoCharHashTableKey key(c1, c2);
10555 int entry = FindEntry(&key);
10556 if (entry == kNotFound) {
10557 return false;
10558 } else {
10559 String* result = String::cast(KeyAt(entry));
10560 ASSERT(StringShape(result).IsSymbol());
10561 *symbol = result;
10562 return true;
10563 }
10564}
10565
10566
John Reck59135872010-11-02 12:39:01 -070010567MaybeObject* SymbolTable::LookupSymbol(Vector<const char> str, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010568 Utf8SymbolKey key(str);
10569 return LookupKey(&key, s);
10570}
10571
10572
Steve Block9fac8402011-05-12 15:51:54 +010010573MaybeObject* SymbolTable::LookupAsciiSymbol(Vector<const char> str,
10574 Object** s) {
10575 AsciiSymbolKey key(str);
10576 return LookupKey(&key, s);
10577}
10578
10579
Ben Murdoch257744e2011-11-30 15:57:28 +000010580MaybeObject* SymbolTable::LookupSubStringAsciiSymbol(Handle<SeqAsciiString> str,
10581 int from,
10582 int length,
10583 Object** s) {
10584 SubStringAsciiSymbolKey key(str, from, length);
10585 return LookupKey(&key, s);
10586}
10587
10588
Steve Block9fac8402011-05-12 15:51:54 +010010589MaybeObject* SymbolTable::LookupTwoByteSymbol(Vector<const uc16> str,
10590 Object** s) {
10591 TwoByteSymbolKey key(str);
10592 return LookupKey(&key, s);
10593}
10594
John Reck59135872010-11-02 12:39:01 -070010595MaybeObject* SymbolTable::LookupKey(HashTableKey* key, Object** s) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010596 int entry = FindEntry(key);
10597
10598 // Symbol already in table.
10599 if (entry != kNotFound) {
10600 *s = KeyAt(entry);
10601 return this;
10602 }
10603
10604 // Adding new symbol. Grow table if needed.
John Reck59135872010-11-02 12:39:01 -070010605 Object* obj;
10606 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10607 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10608 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010609
10610 // Create symbol object.
John Reck59135872010-11-02 12:39:01 -070010611 Object* symbol;
10612 { MaybeObject* maybe_symbol = key->AsObject();
10613 if (!maybe_symbol->ToObject(&symbol)) return maybe_symbol;
10614 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010615
10616 // If the symbol table grew as part of EnsureCapacity, obj is not
10617 // the current symbol table and therefore we cannot use
10618 // SymbolTable::cast here.
10619 SymbolTable* table = reinterpret_cast<SymbolTable*>(obj);
10620
10621 // Add the new symbol and return it along with the symbol table.
10622 entry = table->FindInsertionEntry(key->Hash());
10623 table->set(EntryToIndex(entry), symbol);
10624 table->ElementAdded();
10625 *s = symbol;
10626 return table;
10627}
10628
10629
10630Object* CompilationCacheTable::Lookup(String* src) {
10631 StringKey key(src);
10632 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010633 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010634 return get(EntryToIndex(entry) + 1);
10635}
10636
10637
Steve Block1e0659c2011-05-24 12:43:12 +010010638Object* CompilationCacheTable::LookupEval(String* src,
10639 Context* context,
10640 StrictModeFlag strict_mode) {
10641 StringSharedKey key(src, context->closure()->shared(), strict_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +000010642 int entry = FindEntry(&key);
Steve Block44f0eee2011-05-26 01:26:41 +010010643 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010644 return get(EntryToIndex(entry) + 1);
10645}
10646
10647
10648Object* CompilationCacheTable::LookupRegExp(String* src,
10649 JSRegExp::Flags flags) {
10650 RegExpKey key(src, flags);
10651 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010652 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010653 return get(EntryToIndex(entry) + 1);
10654}
10655
10656
John Reck59135872010-11-02 12:39:01 -070010657MaybeObject* CompilationCacheTable::Put(String* src, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010658 StringKey key(src);
John Reck59135872010-11-02 12:39:01 -070010659 Object* obj;
10660 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10661 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10662 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010663
10664 CompilationCacheTable* cache =
10665 reinterpret_cast<CompilationCacheTable*>(obj);
10666 int entry = cache->FindInsertionEntry(key.Hash());
10667 cache->set(EntryToIndex(entry), src);
10668 cache->set(EntryToIndex(entry) + 1, value);
10669 cache->ElementAdded();
10670 return cache;
10671}
10672
10673
John Reck59135872010-11-02 12:39:01 -070010674MaybeObject* CompilationCacheTable::PutEval(String* src,
10675 Context* context,
Steve Block1e0659c2011-05-24 12:43:12 +010010676 SharedFunctionInfo* value) {
10677 StringSharedKey key(src,
10678 context->closure()->shared(),
10679 value->strict_mode() ? kStrictMode : kNonStrictMode);
John Reck59135872010-11-02 12:39:01 -070010680 Object* obj;
10681 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10682 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10683 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010684
10685 CompilationCacheTable* cache =
10686 reinterpret_cast<CompilationCacheTable*>(obj);
10687 int entry = cache->FindInsertionEntry(key.Hash());
10688
John Reck59135872010-11-02 12:39:01 -070010689 Object* k;
10690 { MaybeObject* maybe_k = key.AsObject();
10691 if (!maybe_k->ToObject(&k)) return maybe_k;
10692 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010693
10694 cache->set(EntryToIndex(entry), k);
10695 cache->set(EntryToIndex(entry) + 1, value);
10696 cache->ElementAdded();
10697 return cache;
10698}
10699
10700
John Reck59135872010-11-02 12:39:01 -070010701MaybeObject* CompilationCacheTable::PutRegExp(String* src,
10702 JSRegExp::Flags flags,
10703 FixedArray* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010704 RegExpKey key(src, flags);
John Reck59135872010-11-02 12:39:01 -070010705 Object* obj;
10706 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10707 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10708 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010709
10710 CompilationCacheTable* cache =
10711 reinterpret_cast<CompilationCacheTable*>(obj);
10712 int entry = cache->FindInsertionEntry(key.Hash());
Steve Block3ce2e202009-11-05 08:53:23 +000010713 // We store the value in the key slot, and compare the search key
10714 // to the stored value with a custon IsMatch function during lookups.
Steve Blocka7e24c12009-10-30 11:49:00 +000010715 cache->set(EntryToIndex(entry), value);
10716 cache->set(EntryToIndex(entry) + 1, value);
10717 cache->ElementAdded();
10718 return cache;
10719}
10720
10721
Ben Murdochb0fe1622011-05-05 13:52:32 +010010722void CompilationCacheTable::Remove(Object* value) {
Steve Block44f0eee2011-05-26 01:26:41 +010010723 Object* null_value = GetHeap()->null_value();
Ben Murdochb0fe1622011-05-05 13:52:32 +010010724 for (int entry = 0, size = Capacity(); entry < size; entry++) {
10725 int entry_index = EntryToIndex(entry);
10726 int value_index = entry_index + 1;
10727 if (get(value_index) == value) {
Steve Block44f0eee2011-05-26 01:26:41 +010010728 fast_set(this, entry_index, null_value);
10729 fast_set(this, value_index, null_value);
Ben Murdochb0fe1622011-05-05 13:52:32 +010010730 ElementRemoved();
10731 }
10732 }
10733 return;
10734}
10735
10736
Steve Blocka7e24c12009-10-30 11:49:00 +000010737// SymbolsKey used for HashTable where key is array of symbols.
10738class SymbolsKey : public HashTableKey {
10739 public:
10740 explicit SymbolsKey(FixedArray* symbols) : symbols_(symbols) { }
10741
10742 bool IsMatch(Object* symbols) {
10743 FixedArray* o = FixedArray::cast(symbols);
10744 int len = symbols_->length();
10745 if (o->length() != len) return false;
10746 for (int i = 0; i < len; i++) {
10747 if (o->get(i) != symbols_->get(i)) return false;
10748 }
10749 return true;
10750 }
10751
10752 uint32_t Hash() { return HashForObject(symbols_); }
10753
10754 uint32_t HashForObject(Object* obj) {
10755 FixedArray* symbols = FixedArray::cast(obj);
10756 int len = symbols->length();
10757 uint32_t hash = 0;
10758 for (int i = 0; i < len; i++) {
10759 hash ^= String::cast(symbols->get(i))->Hash();
10760 }
10761 return hash;
10762 }
10763
10764 Object* AsObject() { return symbols_; }
10765
10766 private:
10767 FixedArray* symbols_;
10768};
10769
10770
10771Object* MapCache::Lookup(FixedArray* array) {
10772 SymbolsKey key(array);
10773 int entry = FindEntry(&key);
Ben Murdoch8b112d22011-06-08 16:22:53 +010010774 if (entry == kNotFound) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010775 return get(EntryToIndex(entry) + 1);
10776}
10777
10778
John Reck59135872010-11-02 12:39:01 -070010779MaybeObject* MapCache::Put(FixedArray* array, Map* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010780 SymbolsKey key(array);
John Reck59135872010-11-02 12:39:01 -070010781 Object* obj;
10782 { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
10783 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10784 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010785
10786 MapCache* cache = reinterpret_cast<MapCache*>(obj);
10787 int entry = cache->FindInsertionEntry(key.Hash());
10788 cache->set(EntryToIndex(entry), array);
10789 cache->set(EntryToIndex(entry) + 1, value);
10790 cache->ElementAdded();
10791 return cache;
10792}
10793
10794
10795template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010796MaybeObject* Dictionary<Shape, Key>::Allocate(int at_least_space_for) {
10797 Object* obj;
10798 { MaybeObject* maybe_obj =
10799 HashTable<Shape, Key>::Allocate(at_least_space_for);
10800 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
Steve Blocka7e24c12009-10-30 11:49:00 +000010801 }
John Reck59135872010-11-02 12:39:01 -070010802 // Initialize the next enumeration index.
10803 Dictionary<Shape, Key>::cast(obj)->
10804 SetNextEnumerationIndex(PropertyDetails::kInitialIndex);
Steve Blocka7e24c12009-10-30 11:49:00 +000010805 return obj;
10806}
10807
10808
10809template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010810MaybeObject* Dictionary<Shape, Key>::GenerateNewEnumerationIndices() {
Steve Block44f0eee2011-05-26 01:26:41 +010010811 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010812 int length = HashTable<Shape, Key>::NumberOfElements();
10813
10814 // Allocate and initialize iteration order array.
John Reck59135872010-11-02 12:39:01 -070010815 Object* obj;
Steve Block44f0eee2011-05-26 01:26:41 +010010816 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070010817 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10818 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010819 FixedArray* iteration_order = FixedArray::cast(obj);
10820 for (int i = 0; i < length; i++) {
Leon Clarke4515c472010-02-03 11:58:03 +000010821 iteration_order->set(i, Smi::FromInt(i));
Steve Blocka7e24c12009-10-30 11:49:00 +000010822 }
10823
10824 // Allocate array with enumeration order.
Steve Block44f0eee2011-05-26 01:26:41 +010010825 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length);
John Reck59135872010-11-02 12:39:01 -070010826 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10827 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010828 FixedArray* enumeration_order = FixedArray::cast(obj);
10829
10830 // Fill the enumeration order array with property details.
10831 int capacity = HashTable<Shape, Key>::Capacity();
10832 int pos = 0;
10833 for (int i = 0; i < capacity; i++) {
10834 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
Leon Clarke4515c472010-02-03 11:58:03 +000010835 enumeration_order->set(pos++, Smi::FromInt(DetailsAt(i).index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000010836 }
10837 }
10838
10839 // Sort the arrays wrt. enumeration order.
10840 iteration_order->SortPairs(enumeration_order, enumeration_order->length());
10841
10842 // Overwrite the enumeration_order with the enumeration indices.
10843 for (int i = 0; i < length; i++) {
10844 int index = Smi::cast(iteration_order->get(i))->value();
10845 int enum_index = PropertyDetails::kInitialIndex + i;
Leon Clarke4515c472010-02-03 11:58:03 +000010846 enumeration_order->set(index, Smi::FromInt(enum_index));
Steve Blocka7e24c12009-10-30 11:49:00 +000010847 }
10848
10849 // Update the dictionary with new indices.
10850 capacity = HashTable<Shape, Key>::Capacity();
10851 pos = 0;
10852 for (int i = 0; i < capacity; i++) {
10853 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) {
10854 int enum_index = Smi::cast(enumeration_order->get(pos++))->value();
10855 PropertyDetails details = DetailsAt(i);
10856 PropertyDetails new_details =
10857 PropertyDetails(details.attributes(), details.type(), enum_index);
10858 DetailsAtPut(i, new_details);
10859 }
10860 }
10861
10862 // Set the next enumeration index.
10863 SetNextEnumerationIndex(PropertyDetails::kInitialIndex+length);
10864 return this;
10865}
10866
10867template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010868MaybeObject* Dictionary<Shape, Key>::EnsureCapacity(int n, Key key) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010869 // Check whether there are enough enumeration indices to add n elements.
10870 if (Shape::kIsEnumerable &&
10871 !PropertyDetails::IsValidIndex(NextEnumerationIndex() + n)) {
10872 // If not, we generate new indices for the properties.
John Reck59135872010-11-02 12:39:01 -070010873 Object* result;
10874 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
10875 if (!maybe_result->ToObject(&result)) return maybe_result;
10876 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010877 }
10878 return HashTable<Shape, Key>::EnsureCapacity(n, key);
10879}
10880
10881
10882void NumberDictionary::RemoveNumberEntries(uint32_t from, uint32_t to) {
10883 // Do nothing if the interval [from, to) is empty.
10884 if (from >= to) return;
10885
Steve Block44f0eee2011-05-26 01:26:41 +010010886 Heap* heap = GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010887 int removed_entries = 0;
Steve Block44f0eee2011-05-26 01:26:41 +010010888 Object* sentinel = heap->null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010889 int capacity = Capacity();
10890 for (int i = 0; i < capacity; i++) {
10891 Object* key = KeyAt(i);
10892 if (key->IsNumber()) {
10893 uint32_t number = static_cast<uint32_t>(key->Number());
10894 if (from <= number && number < to) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010010895 SetEntry(i, sentinel, sentinel);
Steve Blocka7e24c12009-10-30 11:49:00 +000010896 removed_entries++;
10897 }
10898 }
10899 }
10900
10901 // Update the number of elements.
Leon Clarkee46be812010-01-19 14:06:41 +000010902 ElementsRemoved(removed_entries);
Steve Blocka7e24c12009-10-30 11:49:00 +000010903}
10904
10905
10906template<typename Shape, typename Key>
10907Object* Dictionary<Shape, Key>::DeleteProperty(int entry,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010908 JSReceiver::DeleteMode mode) {
Steve Block44f0eee2011-05-26 01:26:41 +010010909 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Blocka7e24c12009-10-30 11:49:00 +000010910 PropertyDetails details = DetailsAt(entry);
10911 // Ignore attributes if forcing a deletion.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010912 if (details.IsDontDelete() && mode != JSReceiver::FORCE_DELETION) {
Steve Block44f0eee2011-05-26 01:26:41 +010010913 return heap->false_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010914 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010010915 SetEntry(entry, heap->null_value(), heap->null_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000010916 HashTable<Shape, Key>::ElementRemoved();
Steve Block44f0eee2011-05-26 01:26:41 +010010917 return heap->true_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000010918}
10919
10920
10921template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000010922MaybeObject* Dictionary<Shape, Key>::Shrink(Key key) {
10923 return HashTable<Shape, Key>::Shrink(key);
10924}
10925
10926
10927template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010928MaybeObject* Dictionary<Shape, Key>::AtPut(Key key, Object* value) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010929 int entry = this->FindEntry(key);
Steve Blocka7e24c12009-10-30 11:49:00 +000010930
10931 // If the entry is present set the value;
10932 if (entry != Dictionary<Shape, Key>::kNotFound) {
10933 ValueAtPut(entry, value);
10934 return this;
10935 }
10936
10937 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010938 Object* obj;
10939 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10940 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10941 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010942
John Reck59135872010-11-02 12:39:01 -070010943 Object* k;
10944 { MaybeObject* maybe_k = Shape::AsObject(key);
10945 if (!maybe_k->ToObject(&k)) return maybe_k;
10946 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010947 PropertyDetails details = PropertyDetails(NONE, NORMAL);
10948 return Dictionary<Shape, Key>::cast(obj)->
10949 AddEntry(key, value, details, Shape::Hash(key));
10950}
10951
10952
10953template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010954MaybeObject* Dictionary<Shape, Key>::Add(Key key,
10955 Object* value,
10956 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010957 // Valdate key is absent.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010010958 SLOW_ASSERT((this->FindEntry(key) == Dictionary<Shape, Key>::kNotFound));
Steve Blocka7e24c12009-10-30 11:49:00 +000010959 // Check whether the dictionary should be extended.
John Reck59135872010-11-02 12:39:01 -070010960 Object* obj;
10961 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
10962 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10963 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010964 return Dictionary<Shape, Key>::cast(obj)->
10965 AddEntry(key, value, details, Shape::Hash(key));
10966}
10967
10968
10969// Add a key, value pair to the dictionary.
10970template<typename Shape, typename Key>
John Reck59135872010-11-02 12:39:01 -070010971MaybeObject* Dictionary<Shape, Key>::AddEntry(Key key,
10972 Object* value,
10973 PropertyDetails details,
10974 uint32_t hash) {
Steve Blocka7e24c12009-10-30 11:49:00 +000010975 // Compute the key object.
John Reck59135872010-11-02 12:39:01 -070010976 Object* k;
10977 { MaybeObject* maybe_k = Shape::AsObject(key);
10978 if (!maybe_k->ToObject(&k)) return maybe_k;
10979 }
Steve Blocka7e24c12009-10-30 11:49:00 +000010980
10981 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash);
10982 // Insert element at empty or deleted entry
10983 if (!details.IsDeleted() && details.index() == 0 && Shape::kIsEnumerable) {
10984 // Assign an enumeration index to the property and update
10985 // SetNextEnumerationIndex.
10986 int index = NextEnumerationIndex();
10987 details = PropertyDetails(details.attributes(), details.type(), index);
10988 SetNextEnumerationIndex(index + 1);
10989 }
10990 SetEntry(entry, k, value, details);
10991 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber()
10992 || Dictionary<Shape, Key>::KeyAt(entry)->IsString()));
10993 HashTable<Shape, Key>::ElementAdded();
10994 return this;
10995}
10996
10997
10998void NumberDictionary::UpdateMaxNumberKey(uint32_t key) {
10999 // If the dictionary requires slow elements an element has already
11000 // been added at a high index.
11001 if (requires_slow_elements()) return;
11002 // Check if this index is high enough that we should require slow
11003 // elements.
11004 if (key > kRequiresSlowElementsLimit) {
11005 set_requires_slow_elements();
11006 return;
11007 }
11008 // Update max key value.
11009 Object* max_index_object = get(kMaxNumberKeyIndex);
11010 if (!max_index_object->IsSmi() || max_number_key() < key) {
11011 FixedArray::set(kMaxNumberKeyIndex,
Leon Clarke4515c472010-02-03 11:58:03 +000011012 Smi::FromInt(key << kRequiresSlowElementsTagSize));
Steve Blocka7e24c12009-10-30 11:49:00 +000011013 }
11014}
11015
11016
John Reck59135872010-11-02 12:39:01 -070011017MaybeObject* NumberDictionary::AddNumberEntry(uint32_t key,
11018 Object* value,
11019 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011020 UpdateMaxNumberKey(key);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011021 SLOW_ASSERT(this->FindEntry(key) == kNotFound);
Steve Blocka7e24c12009-10-30 11:49:00 +000011022 return Add(key, value, details);
11023}
11024
11025
John Reck59135872010-11-02 12:39:01 -070011026MaybeObject* NumberDictionary::AtNumberPut(uint32_t key, Object* value) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011027 UpdateMaxNumberKey(key);
11028 return AtPut(key, value);
11029}
11030
11031
John Reck59135872010-11-02 12:39:01 -070011032MaybeObject* NumberDictionary::Set(uint32_t key,
11033 Object* value,
11034 PropertyDetails details) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011035 int entry = FindEntry(key);
11036 if (entry == kNotFound) return AddNumberEntry(key, value, details);
11037 // Preserve enumeration index.
11038 details = PropertyDetails(details.attributes(),
11039 details.type(),
11040 DetailsAt(entry).index());
John Reck59135872010-11-02 12:39:01 -070011041 MaybeObject* maybe_object_key = NumberDictionaryShape::AsObject(key);
11042 Object* object_key;
11043 if (!maybe_object_key->ToObject(&object_key)) return maybe_object_key;
Ben Murdochf87a2032010-10-22 12:50:53 +010011044 SetEntry(entry, object_key, value, details);
Steve Blocka7e24c12009-10-30 11:49:00 +000011045 return this;
11046}
11047
11048
11049
11050template<typename Shape, typename Key>
11051int Dictionary<Shape, Key>::NumberOfElementsFilterAttributes(
11052 PropertyAttributes filter) {
11053 int capacity = HashTable<Shape, Key>::Capacity();
11054 int result = 0;
11055 for (int i = 0; i < capacity; i++) {
11056 Object* k = HashTable<Shape, Key>::KeyAt(i);
11057 if (HashTable<Shape, Key>::IsKey(k)) {
11058 PropertyDetails details = DetailsAt(i);
11059 if (details.IsDeleted()) continue;
11060 PropertyAttributes attr = details.attributes();
11061 if ((attr & filter) == 0) result++;
11062 }
11063 }
11064 return result;
11065}
11066
11067
11068template<typename Shape, typename Key>
11069int Dictionary<Shape, Key>::NumberOfEnumElements() {
11070 return NumberOfElementsFilterAttributes(
11071 static_cast<PropertyAttributes>(DONT_ENUM));
11072}
11073
11074
11075template<typename Shape, typename Key>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011076void Dictionary<Shape, Key>::CopyKeysTo(
11077 FixedArray* storage,
11078 PropertyAttributes filter,
11079 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011080 ASSERT(storage->length() >= NumberOfEnumElements());
11081 int capacity = HashTable<Shape, Key>::Capacity();
11082 int index = 0;
11083 for (int i = 0; i < capacity; i++) {
11084 Object* k = HashTable<Shape, Key>::KeyAt(i);
11085 if (HashTable<Shape, Key>::IsKey(k)) {
11086 PropertyDetails details = DetailsAt(i);
11087 if (details.IsDeleted()) continue;
11088 PropertyAttributes attr = details.attributes();
11089 if ((attr & filter) == 0) storage->set(index++, k);
11090 }
11091 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011092 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11093 storage->SortPairs(storage, index);
11094 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011095 ASSERT(storage->length() >= index);
11096}
11097
11098
11099void StringDictionary::CopyEnumKeysTo(FixedArray* storage,
11100 FixedArray* sort_array) {
11101 ASSERT(storage->length() >= NumberOfEnumElements());
11102 int capacity = Capacity();
11103 int index = 0;
11104 for (int i = 0; i < capacity; i++) {
11105 Object* k = KeyAt(i);
11106 if (IsKey(k)) {
11107 PropertyDetails details = DetailsAt(i);
11108 if (details.IsDeleted() || details.IsDontEnum()) continue;
11109 storage->set(index, k);
Leon Clarke4515c472010-02-03 11:58:03 +000011110 sort_array->set(index, Smi::FromInt(details.index()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011111 index++;
11112 }
11113 }
11114 storage->SortPairs(sort_array, sort_array->length());
11115 ASSERT(storage->length() >= index);
11116}
11117
11118
11119template<typename Shape, typename Key>
Ben Murdoch6d7cb002011-08-04 19:25:22 +010011120void Dictionary<Shape, Key>::CopyKeysTo(
Ben Murdoch257744e2011-11-30 15:57:28 +000011121 FixedArray* storage,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011122 int index,
11123 typename Dictionary<Shape, Key>::SortMode sort_mode) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011124 ASSERT(storage->length() >= NumberOfElementsFilterAttributes(
11125 static_cast<PropertyAttributes>(NONE)));
11126 int capacity = HashTable<Shape, Key>::Capacity();
Steve Blocka7e24c12009-10-30 11:49:00 +000011127 for (int i = 0; i < capacity; i++) {
11128 Object* k = HashTable<Shape, Key>::KeyAt(i);
11129 if (HashTable<Shape, Key>::IsKey(k)) {
11130 PropertyDetails details = DetailsAt(i);
11131 if (details.IsDeleted()) continue;
11132 storage->set(index++, k);
11133 }
11134 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011135 if (sort_mode == Dictionary<Shape, Key>::SORTED) {
11136 storage->SortPairs(storage, index);
11137 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011138 ASSERT(storage->length() >= index);
11139}
11140
11141
11142// Backwards lookup (slow).
11143template<typename Shape, typename Key>
11144Object* Dictionary<Shape, Key>::SlowReverseLookup(Object* value) {
11145 int capacity = HashTable<Shape, Key>::Capacity();
11146 for (int i = 0; i < capacity; i++) {
11147 Object* k = HashTable<Shape, Key>::KeyAt(i);
11148 if (Dictionary<Shape, Key>::IsKey(k)) {
11149 Object* e = ValueAt(i);
11150 if (e->IsJSGlobalPropertyCell()) {
11151 e = JSGlobalPropertyCell::cast(e)->value();
11152 }
11153 if (e == value) return k;
11154 }
11155 }
Ben Murdoch8b112d22011-06-08 16:22:53 +010011156 Heap* heap = Dictionary<Shape, Key>::GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011157 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011158}
11159
11160
John Reck59135872010-11-02 12:39:01 -070011161MaybeObject* StringDictionary::TransformPropertiesToFastFor(
Steve Blocka7e24c12009-10-30 11:49:00 +000011162 JSObject* obj, int unused_property_fields) {
11163 // Make sure we preserve dictionary representation if there are too many
11164 // descriptors.
11165 if (NumberOfElements() > DescriptorArray::kMaxNumberOfDescriptors) return obj;
11166
11167 // Figure out if it is necessary to generate new enumeration indices.
11168 int max_enumeration_index =
11169 NextEnumerationIndex() +
11170 (DescriptorArray::kMaxNumberOfDescriptors -
11171 NumberOfElements());
11172 if (!PropertyDetails::IsValidIndex(max_enumeration_index)) {
John Reck59135872010-11-02 12:39:01 -070011173 Object* result;
11174 { MaybeObject* maybe_result = GenerateNewEnumerationIndices();
11175 if (!maybe_result->ToObject(&result)) return maybe_result;
11176 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011177 }
11178
11179 int instance_descriptor_length = 0;
11180 int number_of_fields = 0;
11181
Ben Murdoch8b112d22011-06-08 16:22:53 +010011182 Heap* heap = GetHeap();
11183
Steve Blocka7e24c12009-10-30 11:49:00 +000011184 // Compute the length of the instance descriptor.
11185 int capacity = Capacity();
11186 for (int i = 0; i < capacity; i++) {
11187 Object* k = KeyAt(i);
11188 if (IsKey(k)) {
11189 Object* value = ValueAt(i);
11190 PropertyType type = DetailsAt(i).type();
11191 ASSERT(type != FIELD);
11192 instance_descriptor_length++;
Leon Clarkee46be812010-01-19 14:06:41 +000011193 if (type == NORMAL &&
Steve Block44f0eee2011-05-26 01:26:41 +010011194 (!value->IsJSFunction() || heap->InNewSpace(value))) {
Leon Clarkee46be812010-01-19 14:06:41 +000011195 number_of_fields += 1;
11196 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011197 }
11198 }
11199
11200 // Allocate the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011201 Object* descriptors_unchecked;
11202 { MaybeObject* maybe_descriptors_unchecked =
11203 DescriptorArray::Allocate(instance_descriptor_length);
11204 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
11205 return maybe_descriptors_unchecked;
11206 }
11207 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011208 DescriptorArray* descriptors = DescriptorArray::cast(descriptors_unchecked);
11209
11210 int inobject_props = obj->map()->inobject_properties();
11211 int number_of_allocated_fields =
11212 number_of_fields + unused_property_fields - inobject_props;
Ben Murdochf87a2032010-10-22 12:50:53 +010011213 if (number_of_allocated_fields < 0) {
11214 // There is enough inobject space for all fields (including unused).
11215 number_of_allocated_fields = 0;
11216 unused_property_fields = inobject_props - number_of_fields;
11217 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011218
11219 // Allocate the fixed array for the fields.
John Reck59135872010-11-02 12:39:01 -070011220 Object* fields;
11221 { MaybeObject* maybe_fields =
Steve Block44f0eee2011-05-26 01:26:41 +010011222 heap->AllocateFixedArray(number_of_allocated_fields);
John Reck59135872010-11-02 12:39:01 -070011223 if (!maybe_fields->ToObject(&fields)) return maybe_fields;
11224 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011225
11226 // Fill in the instance descriptor and the fields.
11227 int next_descriptor = 0;
11228 int current_offset = 0;
11229 for (int i = 0; i < capacity; i++) {
11230 Object* k = KeyAt(i);
11231 if (IsKey(k)) {
11232 Object* value = ValueAt(i);
11233 // Ensure the key is a symbol before writing into the instance descriptor.
John Reck59135872010-11-02 12:39:01 -070011234 Object* key;
Steve Block44f0eee2011-05-26 01:26:41 +010011235 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k));
John Reck59135872010-11-02 12:39:01 -070011236 if (!maybe_key->ToObject(&key)) return maybe_key;
11237 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011238 PropertyDetails details = DetailsAt(i);
11239 PropertyType type = details.type();
11240
Steve Block44f0eee2011-05-26 01:26:41 +010011241 if (value->IsJSFunction() && !heap->InNewSpace(value)) {
Steve Blocka7e24c12009-10-30 11:49:00 +000011242 ConstantFunctionDescriptor d(String::cast(key),
11243 JSFunction::cast(value),
11244 details.attributes(),
11245 details.index());
11246 descriptors->Set(next_descriptor++, &d);
11247 } else if (type == NORMAL) {
11248 if (current_offset < inobject_props) {
11249 obj->InObjectPropertyAtPut(current_offset,
11250 value,
11251 UPDATE_WRITE_BARRIER);
11252 } else {
11253 int offset = current_offset - inobject_props;
11254 FixedArray::cast(fields)->set(offset, value);
11255 }
11256 FieldDescriptor d(String::cast(key),
11257 current_offset++,
11258 details.attributes(),
11259 details.index());
11260 descriptors->Set(next_descriptor++, &d);
11261 } else if (type == CALLBACKS) {
11262 CallbacksDescriptor d(String::cast(key),
11263 value,
11264 details.attributes(),
11265 details.index());
11266 descriptors->Set(next_descriptor++, &d);
11267 } else {
11268 UNREACHABLE();
11269 }
11270 }
11271 }
11272 ASSERT(current_offset == number_of_fields);
11273
11274 descriptors->Sort();
11275 // Allocate new map.
John Reck59135872010-11-02 12:39:01 -070011276 Object* new_map;
11277 { MaybeObject* maybe_new_map = obj->map()->CopyDropDescriptors();
11278 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
11279 }
Steve Blocka7e24c12009-10-30 11:49:00 +000011280
11281 // Transform the object.
11282 obj->set_map(Map::cast(new_map));
11283 obj->map()->set_instance_descriptors(descriptors);
11284 obj->map()->set_unused_property_fields(unused_property_fields);
11285
11286 obj->set_properties(FixedArray::cast(fields));
11287 ASSERT(obj->IsJSObject());
11288
11289 descriptors->SetNextEnumerationIndex(NextEnumerationIndex());
11290 // Check that it really works.
11291 ASSERT(obj->HasFastProperties());
11292
11293 return obj;
11294}
11295
11296
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011297Object* ObjectHashTable::Lookup(JSObject* key) {
11298 // If the object does not have an identity hash, it was never used as a key.
11299 MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::OMIT_CREATION);
11300 if (maybe_hash->IsFailure()) return GetHeap()->undefined_value();
11301 int entry = FindEntry(key);
11302 if (entry == kNotFound) return GetHeap()->undefined_value();
11303 return get(EntryToIndex(entry) + 1);
11304}
11305
11306
11307MaybeObject* ObjectHashTable::Put(JSObject* key, Object* value) {
11308 // Make sure the key object has an identity hash code.
11309 int hash;
11310 { MaybeObject* maybe_hash = key->GetIdentityHash(JSObject::ALLOW_CREATION);
11311 if (maybe_hash->IsFailure()) return maybe_hash;
11312 hash = Smi::cast(maybe_hash->ToObjectUnchecked())->value();
11313 }
11314 int entry = FindEntry(key);
11315
11316 // Check whether to perform removal operation.
11317 if (value->IsUndefined()) {
11318 if (entry == kNotFound) return this;
11319 RemoveEntry(entry);
11320 return Shrink(key);
11321 }
11322
11323 // Key is already in table, just overwrite value.
11324 if (entry != kNotFound) {
11325 set(EntryToIndex(entry) + 1, value);
11326 return this;
11327 }
11328
11329 // Check whether the hash table should be extended.
11330 Object* obj;
11331 { MaybeObject* maybe_obj = EnsureCapacity(1, key);
11332 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
11333 }
11334 ObjectHashTable* table = ObjectHashTable::cast(obj);
11335 table->AddEntry(table->FindInsertionEntry(hash), key, value);
11336 return table;
11337}
11338
11339
11340void ObjectHashTable::AddEntry(int entry, JSObject* key, Object* value) {
11341 set(EntryToIndex(entry), key);
11342 set(EntryToIndex(entry) + 1, value);
11343 ElementAdded();
11344}
11345
11346
11347void ObjectHashTable::RemoveEntry(int entry, Heap* heap) {
11348 set_null(heap, EntryToIndex(entry));
11349 set_null(heap, EntryToIndex(entry) + 1);
11350 ElementRemoved();
11351}
11352
11353
Steve Blocka7e24c12009-10-30 11:49:00 +000011354#ifdef ENABLE_DEBUGGER_SUPPORT
11355// Check if there is a break point at this code position.
11356bool DebugInfo::HasBreakPoint(int code_position) {
11357 // Get the break point info object for this code position.
11358 Object* break_point_info = GetBreakPointInfo(code_position);
11359
11360 // If there is no break point info object or no break points in the break
11361 // point info object there is no break point at this code position.
11362 if (break_point_info->IsUndefined()) return false;
11363 return BreakPointInfo::cast(break_point_info)->GetBreakPointCount() > 0;
11364}
11365
11366
11367// Get the break point info object for this code position.
11368Object* DebugInfo::GetBreakPointInfo(int code_position) {
11369 // Find the index of the break point info object for this code position.
11370 int index = GetBreakPointInfoIndex(code_position);
11371
11372 // Return the break point info object if any.
Ben Murdoch8b112d22011-06-08 16:22:53 +010011373 if (index == kNoBreakPointInfo) return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011374 return BreakPointInfo::cast(break_points()->get(index));
11375}
11376
11377
11378// Clear a break point at the specified code position.
11379void DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
11380 int code_position,
11381 Handle<Object> break_point_object) {
11382 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11383 if (break_point_info->IsUndefined()) return;
11384 BreakPointInfo::ClearBreakPoint(
11385 Handle<BreakPointInfo>::cast(break_point_info),
11386 break_point_object);
11387}
11388
11389
11390void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info,
11391 int code_position,
11392 int source_position,
11393 int statement_position,
11394 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011395 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011396 Handle<Object> break_point_info(debug_info->GetBreakPointInfo(code_position));
11397 if (!break_point_info->IsUndefined()) {
11398 BreakPointInfo::SetBreakPoint(
11399 Handle<BreakPointInfo>::cast(break_point_info),
11400 break_point_object);
11401 return;
11402 }
11403
11404 // Adding a new break point for a code position which did not have any
11405 // break points before. Try to find a free slot.
11406 int index = kNoBreakPointInfo;
11407 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11408 if (debug_info->break_points()->get(i)->IsUndefined()) {
11409 index = i;
11410 break;
11411 }
11412 }
11413 if (index == kNoBreakPointInfo) {
11414 // No free slot - extend break point info array.
11415 Handle<FixedArray> old_break_points =
11416 Handle<FixedArray>(FixedArray::cast(debug_info->break_points()));
Steve Blocka7e24c12009-10-30 11:49:00 +000011417 Handle<FixedArray> new_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +010011418 isolate->factory()->NewFixedArray(
11419 old_break_points->length() +
11420 Debug::kEstimatedNofBreakPointsInFunction);
Kristian Monsen0d5e1162010-09-30 15:31:59 +010011421
11422 debug_info->set_break_points(*new_break_points);
Steve Blocka7e24c12009-10-30 11:49:00 +000011423 for (int i = 0; i < old_break_points->length(); i++) {
11424 new_break_points->set(i, old_break_points->get(i));
11425 }
11426 index = old_break_points->length();
11427 }
11428 ASSERT(index != kNoBreakPointInfo);
11429
11430 // Allocate new BreakPointInfo object and set the break point.
Steve Block44f0eee2011-05-26 01:26:41 +010011431 Handle<BreakPointInfo> new_break_point_info = Handle<BreakPointInfo>::cast(
11432 isolate->factory()->NewStruct(BREAK_POINT_INFO_TYPE));
Steve Blocka7e24c12009-10-30 11:49:00 +000011433 new_break_point_info->set_code_position(Smi::FromInt(code_position));
11434 new_break_point_info->set_source_position(Smi::FromInt(source_position));
11435 new_break_point_info->
11436 set_statement_position(Smi::FromInt(statement_position));
Steve Block44f0eee2011-05-26 01:26:41 +010011437 new_break_point_info->set_break_point_objects(
11438 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011439 BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
11440 debug_info->break_points()->set(index, *new_break_point_info);
11441}
11442
11443
11444// Get the break point objects for a code position.
11445Object* DebugInfo::GetBreakPointObjects(int code_position) {
11446 Object* break_point_info = GetBreakPointInfo(code_position);
11447 if (break_point_info->IsUndefined()) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011448 return GetHeap()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011449 }
11450 return BreakPointInfo::cast(break_point_info)->break_point_objects();
11451}
11452
11453
11454// Get the total number of break points.
11455int DebugInfo::GetBreakPointCount() {
11456 if (break_points()->IsUndefined()) return 0;
11457 int count = 0;
11458 for (int i = 0; i < break_points()->length(); i++) {
11459 if (!break_points()->get(i)->IsUndefined()) {
11460 BreakPointInfo* break_point_info =
11461 BreakPointInfo::cast(break_points()->get(i));
11462 count += break_point_info->GetBreakPointCount();
11463 }
11464 }
11465 return count;
11466}
11467
11468
11469Object* DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
11470 Handle<Object> break_point_object) {
Ben Murdoch8b112d22011-06-08 16:22:53 +010011471 Heap* heap = debug_info->GetHeap();
Steve Block44f0eee2011-05-26 01:26:41 +010011472 if (debug_info->break_points()->IsUndefined()) return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011473 for (int i = 0; i < debug_info->break_points()->length(); i++) {
11474 if (!debug_info->break_points()->get(i)->IsUndefined()) {
11475 Handle<BreakPointInfo> break_point_info =
11476 Handle<BreakPointInfo>(BreakPointInfo::cast(
11477 debug_info->break_points()->get(i)));
11478 if (BreakPointInfo::HasBreakPointObject(break_point_info,
11479 break_point_object)) {
11480 return *break_point_info;
11481 }
11482 }
11483 }
Steve Block44f0eee2011-05-26 01:26:41 +010011484 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +000011485}
11486
11487
11488// Find the index of the break point info object for the specified code
11489// position.
11490int DebugInfo::GetBreakPointInfoIndex(int code_position) {
11491 if (break_points()->IsUndefined()) return kNoBreakPointInfo;
11492 for (int i = 0; i < break_points()->length(); i++) {
11493 if (!break_points()->get(i)->IsUndefined()) {
11494 BreakPointInfo* break_point_info =
11495 BreakPointInfo::cast(break_points()->get(i));
11496 if (break_point_info->code_position()->value() == code_position) {
11497 return i;
11498 }
11499 }
11500 }
11501 return kNoBreakPointInfo;
11502}
11503
11504
11505// Remove the specified break point object.
11506void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
11507 Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011508 Isolate* isolate = Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +000011509 // If there are no break points just ignore.
11510 if (break_point_info->break_point_objects()->IsUndefined()) return;
11511 // If there is a single break point clear it if it is the same.
11512 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11513 if (break_point_info->break_point_objects() == *break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +010011514 break_point_info->set_break_point_objects(
11515 isolate->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +000011516 }
11517 return;
11518 }
11519 // If there are multiple break points shrink the array
11520 ASSERT(break_point_info->break_point_objects()->IsFixedArray());
11521 Handle<FixedArray> old_array =
11522 Handle<FixedArray>(
11523 FixedArray::cast(break_point_info->break_point_objects()));
11524 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011525 isolate->factory()->NewFixedArray(old_array->length() - 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011526 int found_count = 0;
11527 for (int i = 0; i < old_array->length(); i++) {
11528 if (old_array->get(i) == *break_point_object) {
11529 ASSERT(found_count == 0);
11530 found_count++;
11531 } else {
11532 new_array->set(i - found_count, old_array->get(i));
11533 }
11534 }
11535 // If the break point was found in the list change it.
11536 if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
11537}
11538
11539
11540// Add the specified break point object.
11541void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
11542 Handle<Object> break_point_object) {
11543 // If there was no break point objects before just set it.
11544 if (break_point_info->break_point_objects()->IsUndefined()) {
11545 break_point_info->set_break_point_objects(*break_point_object);
11546 return;
11547 }
11548 // If the break point object is the same as before just ignore.
11549 if (break_point_info->break_point_objects() == *break_point_object) return;
11550 // If there was one break point object before replace with array.
11551 if (!break_point_info->break_point_objects()->IsFixedArray()) {
Steve Block44f0eee2011-05-26 01:26:41 +010011552 Handle<FixedArray> array = FACTORY->NewFixedArray(2);
Steve Blocka7e24c12009-10-30 11:49:00 +000011553 array->set(0, break_point_info->break_point_objects());
11554 array->set(1, *break_point_object);
11555 break_point_info->set_break_point_objects(*array);
11556 return;
11557 }
11558 // If there was more than one break point before extend array.
11559 Handle<FixedArray> old_array =
11560 Handle<FixedArray>(
11561 FixedArray::cast(break_point_info->break_point_objects()));
11562 Handle<FixedArray> new_array =
Steve Block44f0eee2011-05-26 01:26:41 +010011563 FACTORY->NewFixedArray(old_array->length() + 1);
Steve Blocka7e24c12009-10-30 11:49:00 +000011564 for (int i = 0; i < old_array->length(); i++) {
11565 // If the break point was there before just ignore.
11566 if (old_array->get(i) == *break_point_object) return;
11567 new_array->set(i, old_array->get(i));
11568 }
11569 // Add the new break point.
11570 new_array->set(old_array->length(), *break_point_object);
11571 break_point_info->set_break_point_objects(*new_array);
11572}
11573
11574
11575bool BreakPointInfo::HasBreakPointObject(
11576 Handle<BreakPointInfo> break_point_info,
11577 Handle<Object> break_point_object) {
11578 // No break point.
11579 if (break_point_info->break_point_objects()->IsUndefined()) return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011580 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000011581 if (!break_point_info->break_point_objects()->IsFixedArray()) {
11582 return break_point_info->break_point_objects() == *break_point_object;
11583 }
11584 // Multiple break points.
11585 FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
11586 for (int i = 0; i < array->length(); i++) {
11587 if (array->get(i) == *break_point_object) {
11588 return true;
11589 }
11590 }
11591 return false;
11592}
11593
11594
11595// Get the number of break points.
11596int BreakPointInfo::GetBreakPointCount() {
11597 // No break point.
11598 if (break_point_objects()->IsUndefined()) return 0;
Ben Murdoch69a99ed2011-11-30 16:03:39 +000011599 // Single break point.
Steve Blocka7e24c12009-10-30 11:49:00 +000011600 if (!break_point_objects()->IsFixedArray()) return 1;
11601 // Multiple break points.
11602 return FixedArray::cast(break_point_objects())->length();
11603}
11604#endif
11605
11606
11607} } // namespace v8::internal